Received: by 2002:a25:4158:0:0:0:0:0 with SMTP id o85csp3583975yba; Mon, 8 Apr 2019 23:57:12 -0700 (PDT) X-Google-Smtp-Source: APXvYqy520lg3hWckEcEL3ct1xct//ltp5Td4m+f/+T3IctqGp1Yw0DKKtzWI0+5TDYIg+K8T8jg X-Received: by 2002:a63:c112:: with SMTP id w18mr33457453pgf.200.1554793032769; Mon, 08 Apr 2019 23:57:12 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1554793032; cv=none; d=google.com; s=arc-20160816; b=Jgr/icCpMS487QXGbhQi901JmVaiIfyIBBLiSmExCWNziwcO14l866UNMlI6bDwTIp kwyg7zMFut4EcbGF1nG4BZ75AOdqcJ959MdlJxJRDx3x69ca1ICIrK2RhFCN4OkDcVJX MXaXvAMk0ZV151jbvrsmreESst5bkLNHR8z12sQqo68AdlyVQwemeYgLh7cwVtfHNvcj GHIRYuNSinchAODKFzsj7Jt9AUUSXqRvE1ft9miz33wa5FZa/NiFc9Jdtv+5aEJljeZD BDHVg5uzuJLlo4W/R7wQfCVC/45tuwJqRuTywzPOuVe1rmcvRGGjJ6f309nCblNMG5S3 iwBQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from:dkim-signature; bh=g1CAhrs+XKcnO04tYd62P5aQHE9n2UfoCEcN1al9wbA=; b=RMQ4XZHEA0u3usZOig/55yYWq70TnegHdeXW8+m4hxek63SfSlLRMpkXAXYYnakrcp jJy+CkQ/UOhYU//YFMzZZAHtKxuH5F5NAROZJ929Vyq7JeMyrXavf8QNeSLHthuCScic PVZyBS/1T9SjXgoWoRCos7zxrQGI94iflIANio1GdifpWBVqUtyUfofc3jODnirB6KmP 2ZKjLE4TN1jXJKvxLNRqYe1kpkpVD6WiT8mnWsRK6QWOSTHwd08SflxlhT8mHBNBbdGQ EuZzaW+SB5h9ayltmK6FNijNRFkiV1e3IdGaj2vo/PdB+x0gAlptmA++VOCBf4XQAlv/ TsvA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=YAGurzXJ; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l190si14462893pgd.146.2019.04.08.23.56.56; Mon, 08 Apr 2019 23:57:12 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=YAGurzXJ; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726592AbfDIG4R (ORCPT + 99 others); Tue, 9 Apr 2019 02:56:17 -0400 Received: from mail-io1-f66.google.com ([209.85.166.66]:38571 "EHLO mail-io1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726220AbfDIG4Q (ORCPT ); Tue, 9 Apr 2019 02:56:16 -0400 Received: by mail-io1-f66.google.com with SMTP id v4so13330995ioj.5; Mon, 08 Apr 2019 23:56:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=g1CAhrs+XKcnO04tYd62P5aQHE9n2UfoCEcN1al9wbA=; b=YAGurzXJeGj/1GBjBd/jXslO4S7jXu0drLCwWbSl4Ff23U1myJ7lbxVYPXe3LVJCYR d37tlQLgTOzRzJMVfutOUWE+Hb87UpqZofmQOYHFw5YqBr0gAsRbuzRJB6nkRtjxqjYL rYjUs+AB9OXE81tj4uGMh67fa2wyy5TgGkHFrbkpzdLl7VShiZ2X+Vwjaz+SaDNM/Zz3 zJtFMhjWJJ1vsXD+LwECxFwAVlJkwEVAv9PvQqvkDEc2dJg4Lu/fqHW4vN1sHRlLo27w p5DtyY9wcYPeIcIe9GBxgRA/mAkNz/fg0Dn2yLKoWBwE943JLYvJPjDA0w6mESIRbLcN U91A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=g1CAhrs+XKcnO04tYd62P5aQHE9n2UfoCEcN1al9wbA=; b=CcLgawnl8yBNa2tYCH+BtCByAuQvepeCVaFiXi+Br12SrmW586UI7qiG03UppnLfng l4OiIbblgkZflFeXQuon5zVH+ojP3P49hl8buZHOxgb2Wo+u/sg9TVrDdpPQwhqtL9XI oOz6cmX/rmlNR4+UrI0Eo7OtlEFXyCv0JRVumDtkiTC87e6/yTWfumVud0kKTAWMqLCL az/1FyLs8IesRSCTiBkgdILOnVBQ756wiR0xhQ2pxFCeJPgem6Lp6pU32YJE5birdNDh efS0HIFEd0c+o4OShaXRZzZ1QDJeXsMRAF9+3eKolhdbLZj8gEArBOWyKEV/iJ96vuK6 ivRw== X-Gm-Message-State: APjAAAWt5vEi7glIioBdjUlQqa0fqyogcnL6aXMdMk3by1f2mM/GPxQd 0DvWmu5avSHzBAQc9gNtpmKYcVjXLyF4 X-Received: by 2002:a6b:6509:: with SMTP id z9mr23954838iob.43.1554792976033; Mon, 08 Apr 2019 23:56:16 -0700 (PDT) Received: from ip-172-31-35-247.us-east-2.compute.internal (ec2-52-15-165-154.us-east-2.compute.amazonaws.com. [52.15.165.154]) by smtp.gmail.com with ESMTPSA id 65sm6644927itw.1.2019.04.08.23.56.14 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 08 Apr 2019 23:56:15 -0700 (PDT) From: Rundong Ge To: pablo@netfilter.org Cc: kadlec@blackhole.kfki.hu, fw@strlen.de, roopa@cumulusnetworks.com, davem@davemloft.net, netfilter-devel@vger.kernel.org, coreteam@netfilter.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, rdong.ge@gmail.com Subject: [PATCH] netfilter: fix dangling pointer access of fake_rtable Date: Tue, 9 Apr 2019 06:56:12 +0000 Message-Id: <20190409065612.32652-1-rdong.ge@gmail.com> X-Mailer: git-send-email 2.17.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org With bridge-nf-call-iptables enabeled, Skbs go through the bridge and enqueued between and won't be flushed when bridge is down. Then _skb_refdst of skbs in the nfqueue become dangling pointer. Reproduce steps: 1.Create a bridge on the box. 2.echo 1 >/proc/sys/net/bridge/bridge-nf-call-iptables 3.Add a netfilter hook function to queue the packets to nfqueuenum 0. The hook point must between and . 4.Add a userspace process "nfqueue_rcv" to continuously read and set_verdict "NF_ACCEPT" to packets from queue 0. 5.Continuosly ping client1 from client0 6.Send "Ctrl + Z" to pause the "nfqueue_rcv" to simulate the queue congestion. 7.Using "ifconfig br0 down&&brctl delbr br0" to delete the bridge. 8.At this time the _skb_refdst of skbs in the nfqueue become dangling pointer. If we send "fg" to resume the "nfqueue_rcv", the kernel may try to access the freed memory. Debug log: Here I add debug logs in "netdev_freemem" and "dst_release" to prove the freed memory access. As the log shows, the "dst_release" accessed bridge's fake_rtable after the bridge was freed. Apr 8 22:25:14 raydon kernel: [62139.005062] netdev_freemem name:br0, fake_rtable:000000009d76cef0 Apr 8 22:25:21 raydon kernel: [62145.967133] dst_release dst:000000009d76cef0 dst->dev->name: řKU¡TH Apr 8 22:25:21 raydon kernel: [62145.967154] dst_release dst:000000009d76cef0 dst->dev->name: řKU¡TH Apr 8 22:25:21 raydon kernel: [62145.967180] dst_release dst:000000009d76cef0 dst->dev->name: řKU¡TH Apr 8 22:25:21 raydon kernel: [62145.967197] dst_release dst:000000009d76cef0 dst->dev->name: řKU¡TH The reason why the hook point should be after is skbs reference bridge's fake_rtable in "br_nf_pre_routing_finish" hooked at . And the reason why the hook point should be before is "br_nf_forward_ip" will set the state.out to bridge dev. After this hook point, the "nfqnl_dev_drop" triggered by the bridge's NETDEV_DOWN event can flush the queued skbs before bridge's memory is freed, because the state.out now matches the bridge's dev. Signed-off-by: Rundong Ge --- net/netfilter/nfnetlink_queue.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 0dcc359..57eb02d 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -905,13 +905,25 @@ static void free_entry(struct nf_queue_entry *entry) dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex) { #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) - int physinif, physoutif; + struct net_device *physindev, *physoutdev; + struct net_bridge_port *port; - physinif = nf_bridge_get_physinif(entry->skb); - physoutif = nf_bridge_get_physoutif(entry->skb); - - if (physinif == ifindex || physoutif == ifindex) - return 1; + physindev = nf_bridge_get_physindev(entry->skb); + physoutdev = nf_bridge_get_physoutdev(entry->skb); + if (physindev) { + if (physindev->ifindex == ifindex) + return 1; + port = br_port_get_rcu(physindev); + if (port && port->br->dev->ifindex == ifindex) + return 1; + } + if (physoutdev) { + if (physoutdev->ifindex == ifindex) + return 1; + port = br_port_get_rcu(physoutdev); + if (port && port->br->dev->ifindex == ifindex) + return 1; + } #endif if (entry->state.in) if (entry->state.in->ifindex == ifindex) -- 1.8.3.1