Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* Service connection management
0003  *
0004  * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
0005  * Written by David Howells (dhowells@redhat.com)
0006  */
0007 
0008 #include <linux/slab.h>
0009 #include "ar-internal.h"
0010 
0011 static struct rxrpc_bundle rxrpc_service_dummy_bundle = {
0012     .ref        = REFCOUNT_INIT(1),
0013     .debug_id   = UINT_MAX,
0014     .channel_lock   = __SPIN_LOCK_UNLOCKED(&rxrpc_service_dummy_bundle.channel_lock),
0015 };
0016 
0017 /*
0018  * Find a service connection under RCU conditions.
0019  *
0020  * We could use a hash table, but that is subject to bucket stuffing by an
0021  * attacker as the client gets to pick the epoch and cid values and would know
0022  * the hash function.  So, instead, we use a hash table for the peer and from
0023  * that an rbtree to find the service connection.  Under ordinary circumstances
0024  * it might be slower than a large hash table, but it is at least limited in
0025  * depth.
0026  */
0027 struct rxrpc_connection *rxrpc_find_service_conn_rcu(struct rxrpc_peer *peer,
0028                              struct sk_buff *skb)
0029 {
0030     struct rxrpc_connection *conn = NULL;
0031     struct rxrpc_conn_proto k;
0032     struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
0033     struct rb_node *p;
0034     unsigned int seq = 0;
0035 
0036     k.epoch = sp->hdr.epoch;
0037     k.cid   = sp->hdr.cid & RXRPC_CIDMASK;
0038 
0039     do {
0040         /* Unfortunately, rbtree walking doesn't give reliable results
0041          * under just the RCU read lock, so we have to check for
0042          * changes.
0043          */
0044         read_seqbegin_or_lock(&peer->service_conn_lock, &seq);
0045 
0046         p = rcu_dereference_raw(peer->service_conns.rb_node);
0047         while (p) {
0048             conn = rb_entry(p, struct rxrpc_connection, service_node);
0049 
0050             if (conn->proto.index_key < k.index_key)
0051                 p = rcu_dereference_raw(p->rb_left);
0052             else if (conn->proto.index_key > k.index_key)
0053                 p = rcu_dereference_raw(p->rb_right);
0054             else
0055                 break;
0056             conn = NULL;
0057         }
0058     } while (need_seqretry(&peer->service_conn_lock, seq));
0059 
0060     done_seqretry(&peer->service_conn_lock, seq);
0061     _leave(" = %d", conn ? conn->debug_id : -1);
0062     return conn;
0063 }
0064 
0065 /*
0066  * Insert a service connection into a peer's tree, thereby making it a target
0067  * for incoming packets.
0068  */
0069 static void rxrpc_publish_service_conn(struct rxrpc_peer *peer,
0070                        struct rxrpc_connection *conn)
0071 {
0072     struct rxrpc_connection *cursor = NULL;
0073     struct rxrpc_conn_proto k = conn->proto;
0074     struct rb_node **pp, *parent;
0075 
0076     write_seqlock_bh(&peer->service_conn_lock);
0077 
0078     pp = &peer->service_conns.rb_node;
0079     parent = NULL;
0080     while (*pp) {
0081         parent = *pp;
0082         cursor = rb_entry(parent,
0083                   struct rxrpc_connection, service_node);
0084 
0085         if (cursor->proto.index_key < k.index_key)
0086             pp = &(*pp)->rb_left;
0087         else if (cursor->proto.index_key > k.index_key)
0088             pp = &(*pp)->rb_right;
0089         else
0090             goto found_extant_conn;
0091     }
0092 
0093     rb_link_node_rcu(&conn->service_node, parent, pp);
0094     rb_insert_color(&conn->service_node, &peer->service_conns);
0095 conn_published:
0096     set_bit(RXRPC_CONN_IN_SERVICE_CONNS, &conn->flags);
0097     write_sequnlock_bh(&peer->service_conn_lock);
0098     _leave(" = %d [new]", conn->debug_id);
0099     return;
0100 
0101 found_extant_conn:
0102     if (refcount_read(&cursor->ref) == 0)
0103         goto replace_old_connection;
0104     write_sequnlock_bh(&peer->service_conn_lock);
0105     /* We should not be able to get here.  rxrpc_incoming_connection() is
0106      * called in a non-reentrant context, so there can't be a race to
0107      * insert a new connection.
0108      */
0109     BUG();
0110 
0111 replace_old_connection:
0112     /* The old connection is from an outdated epoch. */
0113     _debug("replace conn");
0114     rb_replace_node_rcu(&cursor->service_node,
0115                 &conn->service_node,
0116                 &peer->service_conns);
0117     clear_bit(RXRPC_CONN_IN_SERVICE_CONNS, &cursor->flags);
0118     goto conn_published;
0119 }
0120 
0121 /*
0122  * Preallocate a service connection.  The connection is placed on the proc and
0123  * reap lists so that we don't have to get the lock from BH context.
0124  */
0125 struct rxrpc_connection *rxrpc_prealloc_service_connection(struct rxrpc_net *rxnet,
0126                                gfp_t gfp)
0127 {
0128     struct rxrpc_connection *conn = rxrpc_alloc_connection(gfp);
0129 
0130     if (conn) {
0131         /* We maintain an extra ref on the connection whilst it is on
0132          * the rxrpc_connections list.
0133          */
0134         conn->state = RXRPC_CONN_SERVICE_PREALLOC;
0135         refcount_set(&conn->ref, 2);
0136         conn->bundle = rxrpc_get_bundle(&rxrpc_service_dummy_bundle);
0137 
0138         atomic_inc(&rxnet->nr_conns);
0139         write_lock(&rxnet->conn_lock);
0140         list_add_tail(&conn->link, &rxnet->service_conns);
0141         list_add_tail(&conn->proc_link, &rxnet->conn_proc_list);
0142         write_unlock(&rxnet->conn_lock);
0143 
0144         trace_rxrpc_conn(conn->debug_id, rxrpc_conn_new_service,
0145                  refcount_read(&conn->ref),
0146                  __builtin_return_address(0));
0147     }
0148 
0149     return conn;
0150 }
0151 
0152 /*
0153  * Set up an incoming connection.  This is called in BH context with the RCU
0154  * read lock held.
0155  */
0156 void rxrpc_new_incoming_connection(struct rxrpc_sock *rx,
0157                    struct rxrpc_connection *conn,
0158                    const struct rxrpc_security *sec,
0159                    struct sk_buff *skb)
0160 {
0161     struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
0162 
0163     _enter("");
0164 
0165     conn->proto.epoch   = sp->hdr.epoch;
0166     conn->proto.cid     = sp->hdr.cid & RXRPC_CIDMASK;
0167     conn->params.service_id = sp->hdr.serviceId;
0168     conn->service_id    = sp->hdr.serviceId;
0169     conn->security_ix   = sp->hdr.securityIndex;
0170     conn->out_clientflag    = 0;
0171     conn->security      = sec;
0172     if (conn->security_ix)
0173         conn->state = RXRPC_CONN_SERVICE_UNSECURED;
0174     else
0175         conn->state = RXRPC_CONN_SERVICE;
0176 
0177     /* See if we should upgrade the service.  This can only happen on the
0178      * first packet on a new connection.  Once done, it applies to all
0179      * subsequent calls on that connection.
0180      */
0181     if (sp->hdr.userStatus == RXRPC_USERSTATUS_SERVICE_UPGRADE &&
0182         conn->service_id == rx->service_upgrade.from)
0183         conn->service_id = rx->service_upgrade.to;
0184 
0185     /* Make the connection a target for incoming packets. */
0186     rxrpc_publish_service_conn(conn->params.peer, conn);
0187 
0188     _net("CONNECTION new %d {%x}", conn->debug_id, conn->proto.cid);
0189 }
0190 
0191 /*
0192  * Remove the service connection from the peer's tree, thereby removing it as a
0193  * target for incoming packets.
0194  */
0195 void rxrpc_unpublish_service_conn(struct rxrpc_connection *conn)
0196 {
0197     struct rxrpc_peer *peer = conn->params.peer;
0198 
0199     write_seqlock_bh(&peer->service_conn_lock);
0200     if (test_and_clear_bit(RXRPC_CONN_IN_SERVICE_CONNS, &conn->flags))
0201         rb_erase(&conn->service_node, &peer->service_conns);
0202     write_sequnlock_bh(&peer->service_conn_lock);
0203 }