From d5bafc564e0b0afcf42cc0883e4b6f30c2e7e65a Mon Sep 17 00:00:00 2001 From: Andreas Wellving Date: Tue, 21 May 2019 15:03:30 +0200 Subject: net: CVE-2017-15129 net: Fix double free and memory corruption in get_net_ns_by_id() Reference: https://nvd.nist.gov/vuln/detail/CVE-2017-15129 https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=linux-4.14.y&id=dd9a2648b3e35c2369f580215d916baf7e23253a Change-Id: Ic5752e6a96995fae732eef5d51dc64e2988c8103 Signed-off-by: Andreas Wellving --- ...ble-free-and-memory-corruption-in-get_net.patch | 107 +++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 patches/cve/CVE-2017-15129-net-Fix-double-free-and-memory-corruption-in-get_net.patch diff --git a/patches/cve/CVE-2017-15129-net-Fix-double-free-and-memory-corruption-in-get_net.patch b/patches/cve/CVE-2017-15129-net-Fix-double-free-and-memory-corruption-in-get_net.patch new file mode 100644 index 0000000..18153db --- /dev/null +++ b/patches/cve/CVE-2017-15129-net-Fix-double-free-and-memory-corruption-in-get_net.patch @@ -0,0 +1,107 @@ +From dd9a2648b3e35c2369f580215d916baf7e23253a Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +Date: Tue, 19 Dec 2017 11:27:56 -0600 +Subject: [PATCH] net: Fix double free and memory corruption in + get_net_ns_by_id() + +[ Upstream commit 21b5944350052d2583e82dd59b19a9ba94a007f0 ] + +(I can trivially verify that that idr_remove in cleanup_net happens + after the network namespace count has dropped to zero --EWB) + +Function get_net_ns_by_id() does not check for net::count +after it has found a peer in netns_ids idr. + +It may dereference a peer, after its count has already been +finaly decremented. This leads to double free and memory +corruption: + +put_net(peer) rtnl_lock() +atomic_dec_and_test(&peer->count) [count=0] ... +__put_net(peer) get_net_ns_by_id(net, id) + spin_lock(&cleanup_list_lock) + list_add(&net->cleanup_list, &cleanup_list) + spin_unlock(&cleanup_list_lock) +queue_work() peer = idr_find(&net->netns_ids, id) + | get_net(peer) [count=1] + | ... + | (use after final put) + v ... + cleanup_net() ... + spin_lock(&cleanup_list_lock) ... + list_replace_init(&cleanup_list, ..) ... + spin_unlock(&cleanup_list_lock) ... + ... ... + ... put_net(peer) + ... atomic_dec_and_test(&peer->count) [count=0] + ... spin_lock(&cleanup_list_lock) + ... list_add(&net->cleanup_list, &cleanup_list) + ... spin_unlock(&cleanup_list_lock) + ... queue_work() + ... rtnl_unlock() + rtnl_lock() ... + for_each_net(tmp) { ... + id = __peernet2id(tmp, peer) ... + spin_lock_irq(&tmp->nsid_lock) ... + idr_remove(&tmp->netns_ids, id) ... + ... ... + net_drop_ns() ... + net_free(peer) ... + } ... + | + v + cleanup_net() + ... + (Second free of peer) + +Also, put_net() on the right cpu may reorder with left's cpu +list_replace_init(&cleanup_list, ..), and then cleanup_list +will be corrupted. + +Since cleanup_net() is executed in worker thread, while +put_net(peer) can happen everywhere, there should be +enough time for concurrent get_net_ns_by_id() to pick +the peer up, and the race does not seem to be unlikely. +The patch fixes the problem in standard way. + +(Also, there is possible problem in peernet2id_alloc(), which requires +check for net::count under nsid_lock and maybe_get_net(peer), but +in current stable kernel it's used under rtnl_lock() and it has to be +safe. Openswitch begun to use peernet2id_alloc(), and possibly it should +be fixed too. While this is not in stable kernel yet, so I'll send +a separate message to netdev@ later). + +CVE: CVE-2017-15129 +Upstream-Status: Backport [https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=linux-4.14.y&id=dd9a2648b3e35c2369f580215d916baf7e23253a] + +Cc: Nicolas Dichtel +Signed-off-by: Kirill Tkhai +Fixes: 0c7aecd4bde4 "netns: add rtnl cmd to add and get peer netns ids" +Reviewed-by: Andrey Ryabinin +Reviewed-by: "Eric W. Biederman" +Signed-off-by: Eric W. Biederman +Reviewed-by: Eric Dumazet +Acked-by: Nicolas Dichtel +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Andreas Wellving +--- + net/core/net_namespace.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c +index 6cfdc7c84c48..0dd6359e5924 100644 +--- a/net/core/net_namespace.c ++++ b/net/core/net_namespace.c +@@ -266,7 +266,7 @@ struct net *get_net_ns_by_id(struct net *net, int id) + spin_lock_bh(&net->nsid_lock); + peer = idr_find(&net->netns_ids, id); + if (peer) +- get_net(peer); ++ peer = maybe_get_net(peer); + spin_unlock_bh(&net->nsid_lock); + rcu_read_unlock(); + +-- +2.20.1 + -- cgit v1.2.3-54-g00ecf