Patch "netlink: Fix autobind race condition that leads to zero port ID" has been added to the 4.1-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
netlink: Fix autobind race condition that leads to zero port ID
to the 4.1-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
netlink-fix-autobind-race-condition-that-leads-to-zero-port-id.patch
and it can be found in the queue-4.1 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From foo@baz Wed Sep 30 05:22:23 CEST 2015
From: Herbert Xu <[email protected]>
Date: Fri, 18 Sep 2015 19:16:50 +0800
Subject: netlink: Fix autobind race condition that leads to zero port ID
Status: RO
Content-Length: 3101
Lines: 90
From: Herbert Xu <[email protected]>
[ Upstream commit 1f770c0a09da855a2b51af6d19de97fb955eca85 ]
The commit c0bb07df7d981e4091432754e30c9c720e2c0c78 ("netlink:
Reset portid after netlink_insert failure") introduced a race condition where if two threads try to autobind the same socket one of them may end up with a zero port ID. This led to kernel deadlocks that were observed by multiple people.
This patch reverts that commit and instead fixes it by introducing a separte rhash_portid variable so that the real portid is only set after the socket has been successfully hashed.
--- net/netlink/af_netlink.c | 11 ++++++----- net/netlink/af_netlink.h | 1 + 2 files changed, 7 insertions(+), 5 deletions(-)
net/netlink/af_netlink.c +6 -5
@@ -1017,7 +1017,7 @@ static inline int netlink_compare(structconst struct netlink_compare_arg *x = arg->key;const struct netlink_sock *nlk = ptr; -return nlk->portid != x->portid || +return nlk->rhash_portid != x->portid || !net_eq (sock_net (&nlk->sk),read_pnet (&x->pnet)); }
@@ -1043,7 +1043,7 @@ static int __netlink_insert(struct netli {struct netlink_compare_arg arg; -netlink_compare_arg_init (&arg,sock_net (sk),nlk_sk (sk)->portid); +netlink_compare_arg_init (&arg,sock_net (sk),nlk_sk (sk)->rhash_portid);return rhashtable_lookup_insert_key (&table->hash, &arg, &nlk_sk (sk)->node, netlink_rhashtable_params);
@@ -1105,7 +1105,7 @@ static int netlink_insert(struct sock *s unlikely(atomic_read(&table->hash.nelems) >= UINT_MAX)) goto err; -nlk_sk (sk)->portid = portid; +nlk_sk (sk)->rhash_portid = portid;sock_hold (sk); err =__netlink_insert (table, sk);
@@ -1117,10 +1117,11 @@ static int netlink_insert(struct sock *s err = -EOVERFLOW ;if (err == -EEXIST ) err = -EADDRINUSE ; -nlk_sk (sk)->portid =0 ;sock_put (sk); } +nlk_sk (sk)->portid = portid; + err:release_sock (sk);return err;
@@ -3167,7 +3168,7 @@ static inline u32 netlink_hash(const voiconst struct netlink_sock *nlk = data;struct netlink_compare_arg arg; -netlink_compare_arg_init (&arg,sock_net (&nlk->sk), nlk->portid); +netlink_compare_arg_init (&arg,sock_net (&nlk->sk), nlk->rhash_portid);return jhash2 ((u32 *)&arg, netlink_compare_arg_len /sizeof (u32), seed); }
net/netlink/af_netlink.h +1 -0
@@ -25,6 +25,7 @@ struct netlink_ring {struct netlink_sock {/* struct sock has to be the first member of netlink_sock */ struct sock sk; +u32 rhash_portid;u32 portid;u32 dst_portid;u32 dst_group;
Patches currently in stable-queue which might be from [email protected] are
queue-4.1/netlink-replace-rhash_portid-with-bound.patch queue-4.1/netlink-fix-autobind-race-condition-that-leads-to-zero-port-id.patch