conn_service.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /* Service connection management
  2. *
  3. * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
  4. * Written by David Howells (dhowells@redhat.com)
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public Licence
  8. * as published by the Free Software Foundation; either version
  9. * 2 of the Licence, or (at your option) any later version.
  10. */
  11. #include <linux/slab.h>
  12. #include "ar-internal.h"
  13. /*
  14. * Find a service connection under RCU conditions.
  15. *
  16. * We could use a hash table, but that is subject to bucket stuffing by an
  17. * attacker as the client gets to pick the epoch and cid values and would know
  18. * the hash function. So, instead, we use a hash table for the peer and from
  19. * that an rbtree to find the service connection. Under ordinary circumstances
  20. * it might be slower than a large hash table, but it is at least limited in
  21. * depth.
  22. */
  23. struct rxrpc_connection *rxrpc_find_service_conn_rcu(struct rxrpc_peer *peer,
  24. struct sk_buff *skb)
  25. {
  26. struct rxrpc_connection *conn = NULL;
  27. struct rxrpc_conn_proto k;
  28. struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
  29. struct rb_node *p;
  30. unsigned int seq = 0;
  31. k.epoch = sp->hdr.epoch;
  32. k.cid = sp->hdr.cid & RXRPC_CIDMASK;
  33. do {
  34. /* Unfortunately, rbtree walking doesn't give reliable results
  35. * under just the RCU read lock, so we have to check for
  36. * changes.
  37. */
  38. read_seqbegin_or_lock(&peer->service_conn_lock, &seq);
  39. p = rcu_dereference_raw(peer->service_conns.rb_node);
  40. while (p) {
  41. conn = rb_entry(p, struct rxrpc_connection, service_node);
  42. if (conn->proto.index_key < k.index_key)
  43. p = rcu_dereference_raw(p->rb_left);
  44. else if (conn->proto.index_key > k.index_key)
  45. p = rcu_dereference_raw(p->rb_right);
  46. else
  47. goto done;
  48. conn = NULL;
  49. }
  50. } while (need_seqretry(&peer->service_conn_lock, seq));
  51. done:
  52. done_seqretry(&peer->service_conn_lock, seq);
  53. _leave(" = %d", conn ? conn->debug_id : -1);
  54. return conn;
  55. }
  56. /*
  57. * Insert a service connection into a peer's tree, thereby making it a target
  58. * for incoming packets.
  59. */
  60. static struct rxrpc_connection *
  61. rxrpc_publish_service_conn(struct rxrpc_peer *peer,
  62. struct rxrpc_connection *conn)
  63. {
  64. struct rxrpc_connection *cursor = NULL;
  65. struct rxrpc_conn_proto k = conn->proto;
  66. struct rb_node **pp, *parent;
  67. write_seqlock_bh(&peer->service_conn_lock);
  68. pp = &peer->service_conns.rb_node;
  69. parent = NULL;
  70. while (*pp) {
  71. parent = *pp;
  72. cursor = rb_entry(parent,
  73. struct rxrpc_connection, service_node);
  74. if (cursor->proto.index_key < k.index_key)
  75. pp = &(*pp)->rb_left;
  76. else if (cursor->proto.index_key > k.index_key)
  77. pp = &(*pp)->rb_right;
  78. else
  79. goto found_extant_conn;
  80. }
  81. rb_link_node_rcu(&conn->service_node, parent, pp);
  82. rb_insert_color(&conn->service_node, &peer->service_conns);
  83. conn_published:
  84. set_bit(RXRPC_CONN_IN_SERVICE_CONNS, &conn->flags);
  85. write_sequnlock_bh(&peer->service_conn_lock);
  86. _leave(" = %d [new]", conn->debug_id);
  87. return conn;
  88. found_extant_conn:
  89. if (atomic_read(&cursor->usage) == 0)
  90. goto replace_old_connection;
  91. write_sequnlock_bh(&peer->service_conn_lock);
  92. /* We should not be able to get here. rxrpc_incoming_connection() is
  93. * called in a non-reentrant context, so there can't be a race to
  94. * insert a new connection.
  95. */
  96. BUG();
  97. replace_old_connection:
  98. /* The old connection is from an outdated epoch. */
  99. _debug("replace conn");
  100. rb_replace_node_rcu(&cursor->service_node,
  101. &conn->service_node,
  102. &peer->service_conns);
  103. clear_bit(RXRPC_CONN_IN_SERVICE_CONNS, &cursor->flags);
  104. goto conn_published;
  105. }
  106. /*
  107. * get a record of an incoming connection
  108. */
  109. struct rxrpc_connection *rxrpc_incoming_connection(struct rxrpc_local *local,
  110. struct sockaddr_rxrpc *srx,
  111. struct sk_buff *skb)
  112. {
  113. struct rxrpc_connection *conn;
  114. struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
  115. struct rxrpc_peer *peer;
  116. const char *new = "old";
  117. _enter("");
  118. peer = rxrpc_lookup_peer(local, srx, GFP_NOIO);
  119. if (!peer) {
  120. _debug("no peer");
  121. return ERR_PTR(-EBUSY);
  122. }
  123. ASSERT(sp->hdr.flags & RXRPC_CLIENT_INITIATED);
  124. rcu_read_lock();
  125. peer = rxrpc_lookup_peer_rcu(local, srx);
  126. if (peer) {
  127. conn = rxrpc_find_service_conn_rcu(peer, skb);
  128. if (conn) {
  129. if (sp->hdr.securityIndex != conn->security_ix)
  130. goto security_mismatch_rcu;
  131. if (rxrpc_get_connection_maybe(conn))
  132. goto found_extant_connection_rcu;
  133. /* The conn has expired but we can't remove it without
  134. * the appropriate lock, so we attempt to replace it
  135. * when we have a new candidate.
  136. */
  137. }
  138. if (!rxrpc_get_peer_maybe(peer))
  139. peer = NULL;
  140. }
  141. rcu_read_unlock();
  142. if (!peer) {
  143. peer = rxrpc_lookup_peer(local, srx, GFP_NOIO);
  144. if (!peer)
  145. goto enomem;
  146. }
  147. /* We don't have a matching record yet. */
  148. conn = rxrpc_alloc_connection(GFP_NOIO);
  149. if (!conn)
  150. goto enomem_peer;
  151. conn->proto.epoch = sp->hdr.epoch;
  152. conn->proto.cid = sp->hdr.cid & RXRPC_CIDMASK;
  153. conn->params.local = local;
  154. conn->params.peer = peer;
  155. conn->params.service_id = sp->hdr.serviceId;
  156. conn->security_ix = sp->hdr.securityIndex;
  157. conn->out_clientflag = 0;
  158. conn->state = RXRPC_CONN_SERVICE;
  159. if (conn->params.service_id)
  160. conn->state = RXRPC_CONN_SERVICE_UNSECURED;
  161. rxrpc_get_local(local);
  162. write_lock(&rxrpc_connection_lock);
  163. list_add_tail(&conn->link, &rxrpc_connections);
  164. write_unlock(&rxrpc_connection_lock);
  165. /* Make the connection a target for incoming packets. */
  166. rxrpc_publish_service_conn(peer, conn);
  167. new = "new";
  168. success:
  169. _net("CONNECTION %s %d {%x}", new, conn->debug_id, conn->proto.cid);
  170. _leave(" = %p {u=%d}", conn, atomic_read(&conn->usage));
  171. return conn;
  172. found_extant_connection_rcu:
  173. rcu_read_unlock();
  174. goto success;
  175. security_mismatch_rcu:
  176. rcu_read_unlock();
  177. _leave(" = -EKEYREJECTED");
  178. return ERR_PTR(-EKEYREJECTED);
  179. enomem_peer:
  180. rxrpc_put_peer(peer);
  181. enomem:
  182. _leave(" = -ENOMEM");
  183. return ERR_PTR(-ENOMEM);
  184. }
  185. /*
  186. * Remove the service connection from the peer's tree, thereby removing it as a
  187. * target for incoming packets.
  188. */
  189. void rxrpc_unpublish_service_conn(struct rxrpc_connection *conn)
  190. {
  191. struct rxrpc_peer *peer = conn->params.peer;
  192. write_seqlock_bh(&peer->service_conn_lock);
  193. if (test_and_clear_bit(RXRPC_CONN_IN_SERVICE_CONNS, &conn->flags))
  194. rb_erase(&conn->service_node, &peer->service_conns);
  195. write_sequnlock_bh(&peer->service_conn_lock);
  196. }