From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from n169-113.mail.139.com (n169-113.mail.139.com [120.232.169.113]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D21313E6392 for ; Tue, 14 Apr 2026 12:12:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=120.232.169.113 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776168726; cv=none; b=D5PEAg2EHEXxFED/mjkNaLxDsO78sABNGPKz+9i4cWrjuha/TfOLAOR6I20Vjhg9PCrkPCOHAL3i2Ysp185534Ine40Se+NQRec/AQUtti/u8kHaGxFZieIukWgk9pfkn59sonjXjEgTs6duWxpcVKQwrdcD7C8TQY45cplPOLg= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776168726; c=relaxed/simple; bh=dnqYeb7F2F/8s2H+3B3bu1uWhhShRiJKzAH55M9kyWs=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=GBcNDuCVlA8IF+UHz6GLkNKj9/DqEKggVXF6G3c2eMVLG56Z6PsZT+ltfuTg73TRx/rwVd2gyaf0QHja9TBKLbZCjqHRg1VxEM1pwZojRyv4P7pywc2bFXaEmn6kqE1VXob/TW/gzu8jxvSaMADfuuFfhjJ11VoiyLZJWvLj7Zk= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=139.com; spf=pass smtp.mailfrom=139.com; dkim=pass (1024-bit key) header.d=139.com header.i=@139.com header.b=rcbBc/yu; arc=none smtp.client-ip=120.232.169.113 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=139.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=139.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=139.com header.i=@139.com header.b="rcbBc/yu" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=139.com; s=dkim; l=0; h=from:subject:message-id:to:cc:mime-version; bh=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=; b=rcbBc/yu2URWHY8bUHwTatY1FiSBJmiM3kSDAmailBX8UQm5YUVU5WzSO0Jl7ggjNJwek3f/EG8eD xE5Oq8AoXz1iLSHIfGRnLDGY/dRO+YjHrGSwUG93K3xScVNoW+uU/FeV/Jtl2K8y3PCuupVGkyy8oz g1g9m7Wts5Jsctko= X-RM-TagInfo: emlType=0 X-RM-SPAM: X-RM-SPAM-FLAG:00000000 Received:from China-kernel-team (unknown[2409:8A00:DD3:9760:3124:E06F:F702:B772]) by rmsmtp-lg-appmail-28-12033 (RichMail) with SMTP id 2f0169de2f00582-025b3; Tue, 14 Apr 2026 20:11:49 +0800 (CST) X-RM-TRANSID:2f0169de2f00582-025b3 From: XiaoHua Wang <561399680@139.com> To: gregkh@linuxfoundation.org, sashal@kernel.org, stable@vger.kernel.org Cc: Eric Dumazet , Yin Fengwei , Dong Chenchen , Willem de Bruijn , Jakub Kicinski , XiaoHua Wang <561399680@139.com> Subject: [PATCH 6.6.y] net: add proper RCU protection to /proc/net/ptype Date: Tue, 14 Apr 2026 20:11:18 +0800 Message-ID: <20260414121118.4227-1-561399680@139.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: stable@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Eric Dumazet [ Upstream commit f613e8b4afea0cd17c7168e8b00e25bc8d33175d ] Yin Fengwei reported an RCU stall in ptype_seq_show() and provided a patch. Real issue is that ptype_seq_next() and ptype_seq_show() violate RCU rules. ptype_seq_show() runs under rcu_read_lock(), and reads pt->dev to get device name without any barrier. At the same time, concurrent writers can remove a packet_type structure (which is correctly freed after an RCU grace period) and clear pt->dev without an RCU grace period. Define ptype_iter_state to carry a dev pointer along seq_net_private: struct ptype_iter_state { struct seq_net_private p; struct net_device *dev; // added in this patch }; We need to record the device pointer in ptype_get_idx() and ptype_seq_next() so that ptype_seq_show() is safe against concurrent pt->dev changes. We also need to add full RCU protection in ptype_seq_next(). (Missing READ_ONCE() when reading list.next values) Many thanks to Dong Chenchen for providing a repro. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Fixes: 1d10f8a1f40b ("net-procfs: show net devices bound packet types") Fixes: c353e8983e0d ("net: introduce per netns packet chains") Reported-by: Yin Fengwei Reported-by: Dong Chenchen Closes: https://lore.kernel.org/netdev/CANn89iKRRKPnWjJmb-_3a=sq+9h6DvTQM4DBZHT5ZRGPMzQaiA@mail.gmail.com/T/#m7b80b9fc9b9267f90e0b7aad557595f686f9c50d Signed-off-by: Eric Dumazet Reviewed-by: Willem de Bruijn Tested-by: Yin Fengwei Link: https://patch.msgid.link/20260202205217.2881198-1-edumazet@google.com Signed-off-by: Jakub Kicinski [ Some adjustments have been made. ] Signed-off-by: XiaoHua Wang <561399680@139.com> --- net/core/net-procfs.c | 49 +++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/net/core/net-procfs.c b/net/core/net-procfs.c index 09f7ed1a04e8..d6d139b49384 100644 --- a/net/core/net-procfs.c +++ b/net/core/net-procfs.c @@ -200,8 +200,14 @@ static const struct seq_operations softnet_seq_ops = { .show = softnet_seq_show, }; +struct ptype_iter_state { + struct seq_net_private p; + struct net_device *dev; +}; + static void *ptype_get_idx(struct seq_file *seq, loff_t pos) { + struct ptype_iter_state *iter = seq->private; struct list_head *ptype_list = NULL; struct packet_type *pt = NULL; struct net_device *dev; @@ -211,12 +217,16 @@ static void *ptype_get_idx(struct seq_file *seq, loff_t pos) for_each_netdev_rcu(seq_file_net(seq), dev) { ptype_list = &dev->ptype_all; list_for_each_entry_rcu(pt, ptype_list, list) { - if (i == pos) + if (i == pos) { + iter->dev = dev; return pt; + } ++i; } } + iter->dev = NULL; + list_for_each_entry_rcu(pt, &ptype_all, list) { if (i == pos) return pt; @@ -242,6 +252,7 @@ static void *ptype_seq_start(struct seq_file *seq, loff_t *pos) static void *ptype_seq_next(struct seq_file *seq, void *v, loff_t *pos) { + struct ptype_iter_state *iter = seq->private; struct net_device *dev; struct packet_type *pt; struct list_head *nxt; @@ -252,20 +263,21 @@ static void *ptype_seq_next(struct seq_file *seq, void *v, loff_t *pos) return ptype_get_idx(seq, 0); pt = v; - nxt = pt->list.next; - if (pt->dev) { - if (nxt != &pt->dev->ptype_all) + nxt = READ_ONCE(pt->list.next); + dev = iter->dev; + if (dev) { + if (nxt != &dev->ptype_all) goto found; - dev = pt->dev; for_each_netdev_continue_rcu(seq_file_net(seq), dev) { - if (!list_empty(&dev->ptype_all)) { - nxt = dev->ptype_all.next; + nxt = READ_ONCE(dev->ptype_all.next); + if (nxt != &dev->ptype_all) { + iter->dev = dev; goto found; } } - - nxt = ptype_all.next; + iter->dev = NULL; + nxt = READ_ONCE(ptype_all.next); goto ptype_all; } @@ -274,14 +286,14 @@ static void *ptype_seq_next(struct seq_file *seq, void *v, loff_t *pos) if (nxt != &ptype_all) goto found; hash = 0; - nxt = ptype_base[0].next; + nxt = READ_ONCE(ptype_base[0].next); } else hash = ntohs(pt->type) & PTYPE_HASH_MASK; while (nxt == &ptype_base[hash]) { if (++hash >= PTYPE_HASH_SIZE) return NULL; - nxt = ptype_base[hash].next; + nxt = READ_ONCE(ptype_base[hash].next); } found: return list_entry(nxt, struct packet_type, list); @@ -295,19 +307,24 @@ static void ptype_seq_stop(struct seq_file *seq, void *v) static int ptype_seq_show(struct seq_file *seq, void *v) { + struct ptype_iter_state *iter = seq->private; struct packet_type *pt = v; + struct net_device *dev; - if (v == SEQ_START_TOKEN) + if (v == SEQ_START_TOKEN) { seq_puts(seq, "Type Device Function\n"); - else if ((!pt->af_packet_net || net_eq(pt->af_packet_net, seq_file_net(seq))) && - (!pt->dev || net_eq(dev_net(pt->dev), seq_file_net(seq)))) { + return 0; + } + dev = iter->dev; + if ((!pt->af_packet_net || net_eq(pt->af_packet_net, seq_file_net(seq))) && + (!dev || net_eq(dev_net(dev), seq_file_net(seq)))) { if (pt->type == htons(ETH_P_ALL)) seq_puts(seq, "ALL "); else seq_printf(seq, "%04x", ntohs(pt->type)); seq_printf(seq, " %-8s %ps\n", - pt->dev ? pt->dev->name : "", pt->func); + dev ? dev->name : "", pt->func); } return 0; @@ -331,7 +348,7 @@ static int __net_init dev_proc_net_init(struct net *net) &softnet_seq_ops)) goto out_dev; if (!proc_create_net("ptype", 0444, net->proc_net, &ptype_seq_ops, - sizeof(struct seq_net_private))) + sizeof(struct ptype_iter_state))) goto out_softnet; if (wext_proc_init(net)) -- 2.43.0