From nobody Fri Sep 25 13:54:12 2026 Received: from outboundhk.mxmail.xiaomi.com (outboundhk.mxmail.xiaomi.com [207.226.244.123]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 1B1A038DC6C; Fri, 11 Sep 2026 17:18:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=207.226.244.123 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789147087; cv=none; b=nZK3YvdsGHdVjj1YokBNfMNSGEJ5f0yx1jviG1SgFHLirJgQ6DQl+R1tXoEwVuJQeQXe5Mr2xLvPPQHL4PDzdIVFAwS/pohk+xpnRgJ5zfIcqo/mUogK0SGzjUdjXrXp/VYnkJAQEwRGRBdmOGZJGOe7ypHgWP8bEjtHLAURIaM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789147087; c=relaxed/simple; bh=YS5uo5DloeGRIVXajvRxTCJkecqjh+eSBOyNZmMKuEE=; h=From:To:CC:Subject:Date:Message-ID:Content-Type:MIME-Version; b=UYWijD65G+TnfFVeLCT/LvvUzG8C5pXLOFQDiRPoiAqpZuRiyrTfD/ymS/TbljC/cQ9wyDjdg0Yz3Io2QM4NZR26WOc0Nu8k55Uw8aW2PPGXSnUJDVqFqIDxCkdtfU9v2E0Z2g1jnjq3yyMI6ph9FoUY/U/jqoXBarsvojMJFF8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=xiaomi.com; spf=pass smtp.mailfrom=xiaomi.com; arc=none smtp.client-ip=207.226.244.123 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=xiaomi.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=xiaomi.com X-CSE-ConnectionGUID: a0ACOuSsRxSd6HdC8l9/AQ== X-CSE-MsgGUID: nBGPCgqnRZe6e8CgfTz6zA== X-IronPort-AV: E=Sophos;i="6.27,97,1786982400"; d="scan'208";a="188644074" From: =?gb2312?B?wO7Hvw==?= To: "vinicius.gomes@intel.com" CC: "jhs@mojatatu.com" , "jiri@resnulli.us" , "davem@davemloft.net" , "edumazet@google.com" , "kuba@kernel.org" , "pabeni@redhat.com" , "horms@kernel.org" , "netdev@vger.kernel.org" , "linux-kernel@vger.kernel.org" Subject: [PATCH net] net/sched: taprio: fix infinite loop in taprio_dequeue_tc_priority() Thread-Topic: [PATCH net] net/sched: taprio: fix infinite loop in taprio_dequeue_tc_priority() Thread-Index: AQHdQhEMcFkoIUEhqkujbx/7hdrLVg== Date: Fri, 11 Sep 2026 17:18:02 +0000 Message-ID: <6a248e46f1654ddfaf074cdfffab1349@xiaomi.com> Accept-Language: zh-CN, en-US Content-Language: zh-CN X-MS-Has-Attach: X-MS-TNEF-Correlator: Content-Transfer-Encoding: quoted-printable Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Dear All, I am writing this email to report an infinite loop bug in taprio_dequeue_tc= _priority() while fuzzing the Linux Ethernet networking stack on embedded d= evices. taprio_dequeue_tc_priority() contains a do-while loop that iterates over TX= Qs belonging to a traffic class using a persistent cursor (q->cur_txq[tc]).= The loop termination condition compares the current cursor position with i= ts initial value (first_txq). However, taprio_next_tc_txq() reads the TC-to-TXQ mapping from dev->tc_to_t= xq[tc], which is a per-device shared field. When another qdisc (e.g., mqpri= o) is grafted onto the same device with a different queue mapping, dev->tc_= to_txq[] is updated but taprio's private cur_txq[] retains the stale value = from the old mapping. This creates a situation where first_txq (from old mapping A) falls outside= the new [offset, offset+count) range (from new mapping B). The wrap logic = in taprio_next_tc_txq() confines the cursor to the new range, so it can nev= er reach first_txq, causing an infinite loop in softirq context with interrupts disabled. The loop manifests as a hard CPU lockup: the affected core spins indefinite= ly in taprio_dequeue_from_txq(), timer ticks stop, RCU stalls, and the rtnl_lock is held forever -- blocking all network configura= tion (tc, ip, netlink) and even reboot. Only SysRq hard reset can recover the system. This is 100% deterministic with just 2 tc commands and zero network traffic: tc qdisc replace dev eth0 root taprio \ num_tc 3 map 0 0 1 1 2 2 0 0 0 0 0 0 0 0 0 0 \ queues 1@0 1@1 1@2 base-time 0 \ sched-entry S ff 1000000 clockid CLOCK_TAI tc qdisc replace dev eth0 root mqprio \ num_tc 3 map 0 0 1 1 2 2 0 0 0 0 0 0 0 0 0 0 \ queues 1@1 1@2 1@3 The second command triggers the graft path: mqprio writes dev->tc_to_txq[] = with the new mapping, then dev_deactivate() fires a pending TX softirq that calls taprio's dequeue with the stale cursor -- i= nstant deadloop. Tested on: - aarch64 (6.12.73-rt15+, stmmac physical NIC): 6.5h lockup - x86_64 (6.8.0-138-generic, veth virtual NIC): instant lockup Fix by clamping first_txq into the current [offset, offset+count) range rea= d from dev->tc_to_txq[tc] at the start of each TC iteration. If the cursor = is outside the valid range, reset it to offset. This adds a single READ_ONC= E + branch per TC per dequeue call with negligible overhead. Fixes: 2f530df76c8c ("net/sched: taprio: give higher priority to higher TCs= in software dequeue mode") Signed-off-by: LiQiang --- net/sched/sch_taprio.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c index 39ac5b97a..9ae0de007 100644 --- a/net/sched/sch_taprio.c +++ b/net/sched/sch_taprio.c @@ -781,6 +781,7 @@ static struct sk_buff *taprio_dequeue_tc_priority(struc= t Qdisc *sch, struct taprio_sched *q =3D qdisc_priv(sch); struct net_device *dev =3D qdisc_dev(sch); int num_tc =3D netdev_get_num_tc(dev); + struct netdev_tc_txq tc_txq; struct sk_buff *skb; int tc; @@ -790,6 +791,19 @@ static struct sk_buff *taprio_dequeue_tc_priority(stru= ct Qdisc *sch, if (!(gate_mask & BIT(tc))) continue; + /* Clamp the persistent cursor into the current tc_to_txq + * range. Another qdisc (e.g. mqprio) grafted onto the same + * device may have rewritten dev->tc_to_txq[] since taprio + * last set cur_txq[], making first_txq fall outside the new + * [offset, offset+count) interval and the do-while exit + * condition unreachable -- an infinite loop. + */ + tc_txq.combined =3D READ_ONCE(dev->tc_to_txq[tc].combined); + if (tc_txq.count =3D=3D 0 || + first_txq < tc_txq.offset || + first_txq >=3D tc_txq.offset + tc_txq.count) + q->cur_txq[tc] =3D first_txq =3D tc_txq.offset; + do { skb =3D taprio_dequeue_from_txq(sch, q->cur_txq[tc], entry, gate_mask); -- 2.50.1 Best regards, LiQiang Xiaomi ShadowBlade Security Lab #/******=E6=9C=AC=E9=82=AE=E4=BB=B6=E5=8F=8A=E5=85=B6=E9=99=84=E4=BB=B6=E5= =90=AB=E6=9C=89=E5=B0=8F=E7=B1=B3=E5=85=AC=E5=8F=B8=E7=9A=84=E4=BF=9D=E5=AF= =86=E4=BF=A1=E6=81=AF=EF=BC=8C=E4=BB=85=E9=99=90=E4=BA=8E=E5=8F=91=E9=80=81= =E7=BB=99=E4=B8=8A=E9=9D=A2=E5=9C=B0=E5=9D=80=E4=B8=AD=E5=88=97=E5=87=BA=E7= =9A=84=E4=B8=AA=E4=BA=BA=E6=88=96=E7=BE=A4=E7=BB=84=E3=80=82=E7=A6=81=E6=AD= =A2=E4=BB=BB=E4=BD=95=E5=85=B6=E4=BB=96=E4=BA=BA=E4=BB=A5=E4=BB=BB=E4=BD=95= =E5=BD=A2=E5=BC=8F=E4=BD=BF=E7=94=A8=EF=BC=88=E5=8C=85=E6=8B=AC=E4=BD=86=E4= =B8=8D=E9=99=90=E4=BA=8E=E5=85=A8=E9=83=A8=E6=88=96=E9=83=A8=E5=88=86=E5=9C= =B0=E6=B3=84=E9=9C=B2=E3=80=81=E5=A4=8D=E5=88=B6=E3=80=81=E6=88=96=E6=95=A3= =E5=8F=91=EF=BC=89=E6=9C=AC=E9=82=AE=E4=BB=B6=E4=B8=AD=E7=9A=84=E4=BF=A1=E6= =81=AF=E3=80=82=E5=A6=82=E6=9E=9C=E6=82=A8=E9=94=99=E6=94=B6=E4=BA=86=E6=9C= =AC=E9=82=AE=E4=BB=B6=EF=BC=8C=E8=AF=B7=E6=82=A8=E7=AB=8B=E5=8D=B3=E7=94=B5= =E8=AF=9D=E6=88=96=E9=82=AE=E4=BB=B6=E9=80=9A=E7=9F=A5=E5=8F=91=E4=BB=B6=E4= =BA=BA=E5=B9=B6=E5=88=A0=E9=99=A4=E6=9C=AC=E9=82=AE=E4=BB=B6=EF=BC=81 This = e-mail and its attachments contain confidential information from XIAOMI, wh= ich is intended only for the person or entity whose address is listed above= . Any use of the information contained herein in any way (including, but no= t limited to, total or partial disclosure, reproduction, or dissemination) = by persons other than the intended recipient(s) is prohibited. If you recei= ve this e-mail in error, please notify the sender by phone or email immedia= tely and delete it!******/#