cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

bind.c (7889B)


      1/*
      2 * Copyright (c) 2006, 2019 Oracle and/or its affiliates. All rights reserved.
      3 *
      4 * This software is available to you under a choice of one of two
      5 * licenses.  You may choose to be licensed under the terms of the GNU
      6 * General Public License (GPL) Version 2, available from the file
      7 * COPYING in the main directory of this source tree, or the
      8 * OpenIB.org BSD license below:
      9 *
     10 *     Redistribution and use in source and binary forms, with or
     11 *     without modification, are permitted provided that the following
     12 *     conditions are met:
     13 *
     14 *      - Redistributions of source code must retain the above
     15 *        copyright notice, this list of conditions and the following
     16 *        disclaimer.
     17 *
     18 *      - Redistributions in binary form must reproduce the above
     19 *        copyright notice, this list of conditions and the following
     20 *        disclaimer in the documentation and/or other materials
     21 *        provided with the distribution.
     22 *
     23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
     27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     30 * SOFTWARE.
     31 *
     32 */
     33#include <linux/kernel.h>
     34#include <net/sock.h>
     35#include <linux/in.h>
     36#include <linux/ipv6.h>
     37#include <linux/if_arp.h>
     38#include <linux/jhash.h>
     39#include <linux/ratelimit.h>
     40#include "rds.h"
     41
     42static struct rhashtable bind_hash_table;
     43
     44static const struct rhashtable_params ht_parms = {
     45	.nelem_hint = 768,
     46	.key_len = RDS_BOUND_KEY_LEN,
     47	.key_offset = offsetof(struct rds_sock, rs_bound_key),
     48	.head_offset = offsetof(struct rds_sock, rs_bound_node),
     49	.max_size = 16384,
     50	.min_size = 1024,
     51};
     52
     53/* Create a key for the bind hash table manipulation.  Port is in network byte
     54 * order.
     55 */
     56static inline void __rds_create_bind_key(u8 *key, const struct in6_addr *addr,
     57					 __be16 port, __u32 scope_id)
     58{
     59	memcpy(key, addr, sizeof(*addr));
     60	key += sizeof(*addr);
     61	memcpy(key, &port, sizeof(port));
     62	key += sizeof(port);
     63	memcpy(key, &scope_id, sizeof(scope_id));
     64}
     65
     66/*
     67 * Return the rds_sock bound at the given local address.
     68 *
     69 * The rx path can race with rds_release.  We notice if rds_release() has
     70 * marked this socket and don't return a rs ref to the rx path.
     71 */
     72struct rds_sock *rds_find_bound(const struct in6_addr *addr, __be16 port,
     73				__u32 scope_id)
     74{
     75	u8 key[RDS_BOUND_KEY_LEN];
     76	struct rds_sock *rs;
     77
     78	__rds_create_bind_key(key, addr, port, scope_id);
     79	rcu_read_lock();
     80	rs = rhashtable_lookup(&bind_hash_table, key, ht_parms);
     81	if (rs && (sock_flag(rds_rs_to_sk(rs), SOCK_DEAD) ||
     82		   !refcount_inc_not_zero(&rds_rs_to_sk(rs)->sk_refcnt)))
     83		rs = NULL;
     84
     85	rcu_read_unlock();
     86
     87	rdsdebug("returning rs %p for %pI6c:%u\n", rs, addr,
     88		 ntohs(port));
     89
     90	return rs;
     91}
     92
     93/* returns -ve errno or +ve port */
     94static int rds_add_bound(struct rds_sock *rs, const struct in6_addr *addr,
     95			 __be16 *port, __u32 scope_id)
     96{
     97	int ret = -EADDRINUSE;
     98	u16 rover, last;
     99	u8 key[RDS_BOUND_KEY_LEN];
    100
    101	if (*port != 0) {
    102		rover = be16_to_cpu(*port);
    103		if (rover == RDS_FLAG_PROBE_PORT)
    104			return -EINVAL;
    105		last = rover;
    106	} else {
    107		rover = max_t(u16, prandom_u32(), 2);
    108		last = rover - 1;
    109	}
    110
    111	do {
    112		if (rover == 0)
    113			rover++;
    114
    115		if (rover == RDS_FLAG_PROBE_PORT)
    116			continue;
    117		__rds_create_bind_key(key, addr, cpu_to_be16(rover),
    118				      scope_id);
    119		if (rhashtable_lookup_fast(&bind_hash_table, key, ht_parms))
    120			continue;
    121
    122		memcpy(rs->rs_bound_key, key, sizeof(rs->rs_bound_key));
    123		rs->rs_bound_addr = *addr;
    124		net_get_random_once(&rs->rs_hash_initval,
    125				    sizeof(rs->rs_hash_initval));
    126		rs->rs_bound_port = cpu_to_be16(rover);
    127		rs->rs_bound_node.next = NULL;
    128		rds_sock_addref(rs);
    129		if (!rhashtable_insert_fast(&bind_hash_table,
    130					    &rs->rs_bound_node, ht_parms)) {
    131			*port = rs->rs_bound_port;
    132			rs->rs_bound_scope_id = scope_id;
    133			ret = 0;
    134			rdsdebug("rs %p binding to %pI6c:%d\n",
    135				 rs, addr, (int)ntohs(*port));
    136			break;
    137		} else {
    138			rs->rs_bound_addr = in6addr_any;
    139			rds_sock_put(rs);
    140			ret = -ENOMEM;
    141			break;
    142		}
    143	} while (rover++ != last);
    144
    145	return ret;
    146}
    147
    148void rds_remove_bound(struct rds_sock *rs)
    149{
    150
    151	if (ipv6_addr_any(&rs->rs_bound_addr))
    152		return;
    153
    154	rdsdebug("rs %p unbinding from %pI6c:%d\n",
    155		 rs, &rs->rs_bound_addr,
    156		 ntohs(rs->rs_bound_port));
    157
    158	rhashtable_remove_fast(&bind_hash_table, &rs->rs_bound_node, ht_parms);
    159	rds_sock_put(rs);
    160	rs->rs_bound_addr = in6addr_any;
    161}
    162
    163int rds_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
    164{
    165	struct sock *sk = sock->sk;
    166	struct rds_sock *rs = rds_sk_to_rs(sk);
    167	struct in6_addr v6addr, *binding_addr;
    168	struct rds_transport *trans;
    169	__u32 scope_id = 0;
    170	int ret = 0;
    171	__be16 port;
    172
    173	/* We allow an RDS socket to be bound to either IPv4 or IPv6
    174	 * address.
    175	 */
    176	if (addr_len < offsetofend(struct sockaddr, sa_family))
    177		return -EINVAL;
    178	if (uaddr->sa_family == AF_INET) {
    179		struct sockaddr_in *sin = (struct sockaddr_in *)uaddr;
    180
    181		if (addr_len < sizeof(struct sockaddr_in) ||
    182		    sin->sin_addr.s_addr == htonl(INADDR_ANY) ||
    183		    sin->sin_addr.s_addr == htonl(INADDR_BROADCAST) ||
    184		    ipv4_is_multicast(sin->sin_addr.s_addr))
    185			return -EINVAL;
    186		ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &v6addr);
    187		binding_addr = &v6addr;
    188		port = sin->sin_port;
    189#if IS_ENABLED(CONFIG_IPV6)
    190	} else if (uaddr->sa_family == AF_INET6) {
    191		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)uaddr;
    192		int addr_type;
    193
    194		if (addr_len < sizeof(struct sockaddr_in6))
    195			return -EINVAL;
    196		addr_type = ipv6_addr_type(&sin6->sin6_addr);
    197		if (!(addr_type & IPV6_ADDR_UNICAST)) {
    198			__be32 addr4;
    199
    200			if (!(addr_type & IPV6_ADDR_MAPPED))
    201				return -EINVAL;
    202
    203			/* It is a mapped address.  Need to do some sanity
    204			 * checks.
    205			 */
    206			addr4 = sin6->sin6_addr.s6_addr32[3];
    207			if (addr4 == htonl(INADDR_ANY) ||
    208			    addr4 == htonl(INADDR_BROADCAST) ||
    209			    ipv4_is_multicast(addr4))
    210				return -EINVAL;
    211		}
    212		/* The scope ID must be specified for link local address. */
    213		if (addr_type & IPV6_ADDR_LINKLOCAL) {
    214			if (sin6->sin6_scope_id == 0)
    215				return -EINVAL;
    216			scope_id = sin6->sin6_scope_id;
    217		}
    218		binding_addr = &sin6->sin6_addr;
    219		port = sin6->sin6_port;
    220#endif
    221	} else {
    222		return -EINVAL;
    223	}
    224	lock_sock(sk);
    225
    226	/* RDS socket does not allow re-binding. */
    227	if (!ipv6_addr_any(&rs->rs_bound_addr)) {
    228		ret = -EINVAL;
    229		goto out;
    230	}
    231	/* Socket is connected.  The binding address should have the same
    232	 * scope ID as the connected address, except the case when one is
    233	 * non-link local address (scope_id is 0).
    234	 */
    235	if (!ipv6_addr_any(&rs->rs_conn_addr) && scope_id &&
    236	    rs->rs_bound_scope_id &&
    237	    scope_id != rs->rs_bound_scope_id) {
    238		ret = -EINVAL;
    239		goto out;
    240	}
    241
    242	/* The transport can be set using SO_RDS_TRANSPORT option before the
    243	 * socket is bound.
    244	 */
    245	if (rs->rs_transport) {
    246		trans = rs->rs_transport;
    247		if (!trans->laddr_check ||
    248		    trans->laddr_check(sock_net(sock->sk),
    249				       binding_addr, scope_id) != 0) {
    250			ret = -ENOPROTOOPT;
    251			goto out;
    252		}
    253	} else {
    254		trans = rds_trans_get_preferred(sock_net(sock->sk),
    255						binding_addr, scope_id);
    256		if (!trans) {
    257			ret = -EADDRNOTAVAIL;
    258			pr_info_ratelimited("RDS: %s could not find a transport for %pI6c, load rds_tcp or rds_rdma?\n",
    259					    __func__, binding_addr);
    260			goto out;
    261		}
    262		rs->rs_transport = trans;
    263	}
    264
    265	sock_set_flag(sk, SOCK_RCU_FREE);
    266	ret = rds_add_bound(rs, binding_addr, &port, scope_id);
    267	if (ret)
    268		rs->rs_transport = NULL;
    269
    270out:
    271	release_sock(sk);
    272	return ret;
    273}
    274
    275void rds_bind_lock_destroy(void)
    276{
    277	rhashtable_destroy(&bind_hash_table);
    278}
    279
    280int rds_bind_lock_init(void)
    281{
    282	return rhashtable_init(&bind_hash_table, &ht_parms);
    283}