diff options
author | Subash Abhinov Kasiviswanathan <subashab@codeaurora.org> | 2019-09-10 14:02:57 -0600 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-09-19 09:09:29 +0200 |
commit | 88a46756f016552581fc07e0a5d5c23b5a26737f (patch) | |
tree | 86c24066146cef85931635a3512a80d2f12f2d65 /net/core/dev.c | |
parent | b26f489245b3cf0c06d09a10a8cbdd426af94df6 (diff) | |
download | linux-stable-88a46756f016552581fc07e0a5d5c23b5a26737f.tar.gz linux-stable-88a46756f016552581fc07e0a5d5c23b5a26737f.tar.bz2 linux-stable-88a46756f016552581fc07e0a5d5c23b5a26737f.zip |
net: Fix null de-reference of device refcount
[ Upstream commit 10cc514f451a0f239aa34f91bc9dc954a9397840 ]
In event of failure during register_netdevice, free_netdev is
invoked immediately. free_netdev assumes that all the netdevice
refcounts have been dropped prior to it being called and as a
result frees and clears out the refcount pointer.
However, this is not necessarily true as some of the operations
in the NETDEV_UNREGISTER notifier handlers queue RCU callbacks for
invocation after a grace period. The IPv4 callback in_dev_rcu_put
tries to access the refcount after free_netdev is called which
leads to a null de-reference-
44837.761523: <6> Unable to handle kernel paging request at
virtual address 0000004a88287000
44837.761651: <2> pc : in_dev_finish_destroy+0x4c/0xc8
44837.761654: <2> lr : in_dev_finish_destroy+0x2c/0xc8
44837.762393: <2> Call trace:
44837.762398: <2> in_dev_finish_destroy+0x4c/0xc8
44837.762404: <2> in_dev_rcu_put+0x24/0x30
44837.762412: <2> rcu_nocb_kthread+0x43c/0x468
44837.762418: <2> kthread+0x118/0x128
44837.762424: <2> ret_from_fork+0x10/0x1c
Fix this by waiting for the completion of the call_rcu() in
case of register_netdevice errors.
Fixes: 93ee31f14f6f ("[NET]: Fix free_netdev on register_netdev failure.")
Cc: Sean Tranchetti <stranche@codeaurora.org>
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net/core/dev.c')
-rw-r--r-- | net/core/dev.c | 2 |
1 files changed, 2 insertions, 0 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index e4b4cb40da00..ddd8aab20adf 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -8562,6 +8562,8 @@ int register_netdevice(struct net_device *dev) ret = notifier_to_errno(ret); if (ret) { rollback_registered(dev); + rcu_barrier(); + dev->reg_state = NETREG_UNREGISTERED; } /* |