Skip to content

Commit 30f7ea1

Browse files
Francesco Ruggeridavem330
Francesco Ruggeri
authored andcommitted
packet: race condition in packet_bind
There is a race conditions between packet_notifier and packet_bind{_spkt}. It happens if packet_notifier(NETDEV_UNREGISTER) executes between the time packet_bind{_spkt} takes a reference on the new netdevice and the time packet_do_bind sets po->ifindex. In this case the notification can be missed. If this happens during a dev_change_net_namespace this can result in the netdevice to be moved to the new namespace while the packet_sock in the old namespace still holds a reference on it. When the netdevice is later deleted in the new namespace the deletion hangs since the packet_sock is not found in the new namespace' &net->packet.sklist. It can be reproduced with the script below. This patch makes packet_do_bind check again for the presence of the netdevice in the packet_sock's namespace after the synchronize_net in unregister_prot_hook. More in general it also uses the rcu lock for the duration of the bind to stop dev_change_net_namespace/rollback_registered_many from going past the synchronize_net following unlist_netdevice, so that no NETDEV_UNREGISTER notifications can happen on the new netdevice while the bind is executing. In order to do this some code from packet_bind{_spkt} is consolidated into packet_do_dev. import socket, os, time, sys proto=7 realDev='em1' vlanId=400 if len(sys.argv) > 1: vlanId=int(sys.argv[1]) dev='vlan%d' % vlanId os.system('taskset -p 0x10 %d' % os.getpid()) s = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, proto) os.system('ip link add link %s name %s type vlan id %d' % (realDev, dev, vlanId)) os.system('ip netns add dummy') pid=os.fork() if pid == 0: # dev should be moved while packet_do_bind is in synchronize net os.system('taskset -p 0x20000 %d' % os.getpid()) os.system('ip link set %s netns dummy' % dev) os.system('ip netns exec dummy ip link del %s' % dev) s.close() sys.exit(0) time.sleep(.004) try: s.bind(('%s' % dev, proto+1)) except: print 'Could not bind socket' s.close() os.system('ip netns del dummy') sys.exit(0) os.waitpid(pid, 0) s.close() os.system('ip netns del dummy') sys.exit(0) Signed-off-by: Francesco Ruggeri <fruggeri@arista.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent f668f5f commit 30f7ea1

File tree

1 file changed

+49
-31
lines changed

1 file changed

+49
-31
lines changed

net/packet/af_packet.c

+49-31
Original file line numberDiff line numberDiff line change
@@ -2911,45 +2911,78 @@ static int packet_release(struct socket *sock)
29112911
* Attach a packet hook.
29122912
*/
29132913

2914-
static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 proto)
2914+
static int packet_do_bind(struct sock *sk, const char *name, int ifindex,
2915+
__be16 proto)
29152916
{
29162917
struct packet_sock *po = pkt_sk(sk);
29172918
struct net_device *dev_curr;
29182919
__be16 proto_curr;
29192920
bool need_rehook;
2921+
struct net_device *dev = NULL;
2922+
int ret = 0;
2923+
bool unlisted = false;
29202924

2921-
if (po->fanout) {
2922-
if (dev)
2923-
dev_put(dev);
2924-
2925+
if (po->fanout)
29252926
return -EINVAL;
2926-
}
29272927

29282928
lock_sock(sk);
29292929
spin_lock(&po->bind_lock);
2930+
rcu_read_lock();
2931+
2932+
if (name) {
2933+
dev = dev_get_by_name_rcu(sock_net(sk), name);
2934+
if (!dev) {
2935+
ret = -ENODEV;
2936+
goto out_unlock;
2937+
}
2938+
} else if (ifindex) {
2939+
dev = dev_get_by_index_rcu(sock_net(sk), ifindex);
2940+
if (!dev) {
2941+
ret = -ENODEV;
2942+
goto out_unlock;
2943+
}
2944+
}
2945+
2946+
if (dev)
2947+
dev_hold(dev);
29302948

29312949
proto_curr = po->prot_hook.type;
29322950
dev_curr = po->prot_hook.dev;
29332951

29342952
need_rehook = proto_curr != proto || dev_curr != dev;
29352953

29362954
if (need_rehook) {
2937-
unregister_prot_hook(sk, true);
2955+
if (po->running) {
2956+
rcu_read_unlock();
2957+
__unregister_prot_hook(sk, true);
2958+
rcu_read_lock();
2959+
dev_curr = po->prot_hook.dev;
2960+
if (dev)
2961+
unlisted = !dev_get_by_index_rcu(sock_net(sk),
2962+
dev->ifindex);
2963+
}
29382964

29392965
po->num = proto;
29402966
po->prot_hook.type = proto;
2941-
po->prot_hook.dev = dev;
29422967

2943-
po->ifindex = dev ? dev->ifindex : 0;
2944-
packet_cached_dev_assign(po, dev);
2968+
if (unlikely(unlisted)) {
2969+
dev_put(dev);
2970+
po->prot_hook.dev = NULL;
2971+
po->ifindex = -1;
2972+
packet_cached_dev_reset(po);
2973+
} else {
2974+
po->prot_hook.dev = dev;
2975+
po->ifindex = dev ? dev->ifindex : 0;
2976+
packet_cached_dev_assign(po, dev);
2977+
}
29452978
}
29462979
if (dev_curr)
29472980
dev_put(dev_curr);
29482981

29492982
if (proto == 0 || !need_rehook)
29502983
goto out_unlock;
29512984

2952-
if (!dev || (dev->flags & IFF_UP)) {
2985+
if (!unlisted && (!dev || (dev->flags & IFF_UP))) {
29532986
register_prot_hook(sk);
29542987
} else {
29552988
sk->sk_err = ENETDOWN;
@@ -2958,9 +2991,10 @@ static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 proto)
29582991
}
29592992

29602993
out_unlock:
2994+
rcu_read_unlock();
29612995
spin_unlock(&po->bind_lock);
29622996
release_sock(sk);
2963-
return 0;
2997+
return ret;
29642998
}
29652999

29663000
/*
@@ -2972,8 +3006,6 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr,
29723006
{
29733007
struct sock *sk = sock->sk;
29743008
char name[15];
2975-
struct net_device *dev;
2976-
int err = -ENODEV;
29773009

29783010
/*
29793011
* Check legality
@@ -2983,19 +3015,13 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr,
29833015
return -EINVAL;
29843016
strlcpy(name, uaddr->sa_data, sizeof(name));
29853017

2986-
dev = dev_get_by_name(sock_net(sk), name);
2987-
if (dev)
2988-
err = packet_do_bind(sk, dev, pkt_sk(sk)->num);
2989-
return err;
3018+
return packet_do_bind(sk, name, 0, pkt_sk(sk)->num);
29903019
}
29913020

29923021
static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
29933022
{
29943023
struct sockaddr_ll *sll = (struct sockaddr_ll *)uaddr;
29953024
struct sock *sk = sock->sk;
2996-
struct net_device *dev = NULL;
2997-
int err;
2998-
29993025

30003026
/*
30013027
* Check legality
@@ -3006,16 +3032,8 @@ static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len
30063032
if (sll->sll_family != AF_PACKET)
30073033
return -EINVAL;
30083034

3009-
if (sll->sll_ifindex) {
3010-
err = -ENODEV;
3011-
dev = dev_get_by_index(sock_net(sk), sll->sll_ifindex);
3012-
if (dev == NULL)
3013-
goto out;
3014-
}
3015-
err = packet_do_bind(sk, dev, sll->sll_protocol ? : pkt_sk(sk)->num);
3016-
3017-
out:
3018-
return err;
3035+
return packet_do_bind(sk, NULL, sll->sll_ifindex,
3036+
sll->sll_protocol ? : pkt_sk(sk)->num);
30193037
}
30203038

30213039
static struct proto packet_proto = {

0 commit comments

Comments
 (0)