Patch "netlink: Fix autobind race condition that leads to zero port ID" has been added to the 4.2-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.2-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.2 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:25:07 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
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 | 12 +++++++----- net/netlink/af_netlink.h | 1 + 2 files changed, 8 insertions(+), 5 deletions(-)
net/netlink/af_netlink.c +7 -5
@@ -1019,7 +1019,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)); }
@@ -1045,7 +1045,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);
@@ -1107,7 +1107,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);
@@ -1119,10 +1119,12 @@ static int netlink_insert(struct sock *s err = -EOVERFLOW ;if (err == -EEXIST ) err = -EADDRINUSE ; -nlk_sk (sk)->portid =0 ;sock_put (sk); + goto err; } +nlk_sk (sk)->portid = portid; + err:release_sock (sk);return err;
@@ -3233,7 +3235,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.2/netlink-replace-rhash_portid-with-bound.patch queue-4.2/netlink-fix-autobind-race-condition-that-leads-to-zero-port-id.patch