From nobody Mon Jun 15 19:04:20 2026 Received: from mail-pg1-f181.google.com (mail-pg1-f181.google.com [209.85.215.181]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CB7333A383B for ; Mon, 13 Apr 2026 09:44:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776073499; cv=none; b=lmPKAFdH7zIOSk5xY1F/a3Y0rxN8LnVQTn7/J1GIX46ELvtX6KcZq3MJvTv6vMPKgHJiJoj4RPGgk6Hyz8sRFbHKVdIIjXsZ8HtyHaSr+M9rIocmvuG2jAUj5/bZWGQhcwCCxVOwh02faqjvZb+hqmcVJOoojX8SA/xLirVF8sU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776073499; c=relaxed/simple; bh=Nc909uFZwrvDpDkljFoOIFDI9jBrVfDU0iQ79B6kD3M=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=tkmWaESxleGFwHmfw7VQ6wvopZFO9o/O0d6CxFk5tWDfbKIwLDh/BHEoUOb4sXqAbod3P+uliHpk9cdCbCG3EwK7ZSw8F4kF5DNLg2rH02QoVMEyosFeqdjPQlVnh2KfqqGoculKdQkBMFEbusDaijpLlSwtJ4EM+vwi6mgu1ww= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=BmarTFv1; arc=none smtp.client-ip=209.85.215.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="BmarTFv1" Received: by mail-pg1-f181.google.com with SMTP id 41be03b00d2f7-c76c60c7502so1591926a12.0 for ; Mon, 13 Apr 2026 02:44:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1776073497; x=1776678297; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=xnxXZAcBu9e0QRRC10glkhFgZL7i6Zh7Fpi2VeYiurs=; b=BmarTFv12Lxvd/mxjUjmJh/J0F8fORi5TfsuYUq/VBZkt4BpcHhRBfPmGm14pU9OKX O6i2WLxb1CzxRBky99xCA2qV+kWvlKXE8prJMzvGwogt5O/OYTsLcR3Q4ok0F/+UA14+ q92JXtUUJwzKxqk2sl3yMKz9hjBm2RLgCfbYmDbeji1TIGUS2SyuFtyqMDl1wQBxovDz E4HG/HdEprTXcAIlRGBJIHrx2wPseIXLf9nf9nuLo1nygTNNVLGkK8+Wu7rNk+e1Sa/N C+TiibLx6tiCSpzn3PvQyri+DcnCvtopOEucGXRCYzekuzD3+SSpkr+v9DMU4bd8xJu3 qzkw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776073497; x=1776678297; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=xnxXZAcBu9e0QRRC10glkhFgZL7i6Zh7Fpi2VeYiurs=; b=B9xuJv81/hbxELtaQ3oMu2YNofKFs8BpI+beGrYKzVVLvuzKv94T8UObENpX6hvMs2 1UtzaI377epiPaU9Mz4mOjthLknwdmYUogTR8TDk4ICu+GK9hWty9UjbUhjsSRHQFSEB UteFpB2h1oRcpn8WPcda9nqljF7FBYbogI6wOwMdztwrrcC4O/GWCV4kWMCIHLvl1ZPt OXmjIzuysJOKQa6oTmVLAdzP/XEcr2Hgy40lFf7uHqrx1MLWxU6p4OU7mQT63ZBlekFD yrs93Jse40tMghqjoCp844bK2PA3eXMZXywDbL9uZzA3fKQufvzYees38fQZbNJ9Xp8+ rgcg== X-Forwarded-Encrypted: i=1; AFNElJ+N6rfvRUkLCDKIzkv4GtoUAapPVE+9zaEUG7RIPGsFP5rQvsjDNkVA365NIEzYxCMlXJYJQe/26/VRYyg=@vger.kernel.org X-Gm-Message-State: AOJu0YyPewC8OYPGW8NCRAIL+GHBNGKcDaDtOrttbn7T6pmXHxqaEvdw JIu8HMO9YmFjxVNq7BpxONMQ5dn4t36Ug6OUaUKMyUv7IB9HAoluWUxr X-Gm-Gg: AeBDiesPuPxyKXEHbeEnX0GHFwoBbK2D3nEt/6fMpm4NQiFMQh1NBhef3WjlMMqanta MQjoch/5ZxiJMdfjfsQezTat5P+ngrONeE6x0zWpTCIytC1sj5dbD/JUGJoNua95cX5jKjjYU5I xas2ItH9uJUUUC3+apCggMYsNBfZAN9bGIqbWqReArX3KQryD8VN3L0fqRN68zS47ge5ARZEGJm eSzn62DB6ZA0LWcQL43D8o0hA0VyVi/VsAJfQ443MuTDJ0mw9S/1iSv8hurnJ5yN9qoNb1DNYxU PIpg9L35STFHZ1triDL+IyCTnLJf8RztcmzKJCEcOR/WFfRMiyQ2q9CrhZwLA4T+QzVdnLX216r kvHFaeTa1tROrpuMyeRijrucASKibLn8OMKz/3fikIlNpzZmvvib/h94ihiak6Ei/vXLvabae35 Dt7GDn6s2bXSd5or3VIzfj1PpSu2mWlSjf X-Received: by 2002:a05:6a20:12c5:b0:398:7daf:6d7e with SMTP id adf61e73a8af0-39fe4603847mr11679426637.17.1776073496997; Mon, 13 Apr 2026 02:44:56 -0700 (PDT) Received: from localhost.localdomain ([117.186.117.206]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-82f0c36130csm10711799b3a.24.2026.04.13.02.44.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 13 Apr 2026 02:44:56 -0700 (PDT) From: "Kito Xu (veritas501)" To: Jamal Hadi Salim , Jiri Pirko , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni Cc: Simon Horman , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, "Kito Xu (veritas501)" Subject: [PATCH] net: sched: teql: fix use-after-free in teql_master_xmit Date: Mon, 13 Apr 2026 17:44:47 +0800 Message-ID: <20260413094448.2263828-1-hxzene@gmail.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" teql_destroy() traverses the circular slave list to unlink a slave qdisc. It reads master->slaves as both the starting point and the do-while termination sentinel. However, the data-path writers teql_dequeue() and teql_master_xmit() concurrently modify master->slaves without holding RTNL, running in softirq or process context respectively. If master->slaves is overwritten to an already-visited node mid-traversal, the loop exits early without finding the target slave. The slave is never unlinked, but its memory is freed by call_rcu() -- leaving a dangling pointer in the circular list. The next teql_master_xmit() traversal dereferences freed memory. race condition: CPU 0 (teql_destroy, RTNL held) CPU 1 (teql_dequeue, softirq) ----------------------------------- ----------------------------- prev =3D master->slaves; // =3D A q =3D NEXT_SLAVE(A); // =3D B B =3D=3D A? No. prev =3D B; /* slave C's queue drains */ skb =3D=3D NULL -> dat->m->slaves =3D C; /* write! */ q =3D NEXT_SLAVE(B); // =3D C C =3D=3D A? No. prev =3D C; /* check: (prev=3DC) !=3D master->slaves(C)? FALSE -> loop exits! */ /* A never unlinked, freed by call_rcu */ CPU 0 (teql_master_xmit, later) ----------------------------------- q =3D NEXT_SLAVE(C); // =3D A (freed!) slave =3D qdisc_dev(A); // UAF! Fix this by saving master->slaves into a local `head` variable at the start of teql_destroy() and using it as a stable sentinel for the entire traversal. Also annotate all data-path accesses to master->slaves with READ_ONCE/WRITE_ONCE to prevent store-tearing and compiler-introduced re-reads. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D BUG: KASAN: slab-use-after-free in teql_master_xmit+0xeae/0x14a0 Read of size 8 at addr ffff888018074040 by task poc/162 CPU: 2 UID: 0 PID: 162 Comm: poc Not tainted 7.0.0-rc7-next-20260410 #10 PR= EEMPTLAZY Call Trace: dump_stack_lvl+0x64/0x80 print_report+0xd0/0x5e0 kasan_report+0xce/0x100 teql_master_xmit+0xeae/0x14a0 dev_hard_start_xmit+0xcd/0x5b0 sch_direct_xmit+0x12e/0xac0 __qdisc_run+0x3b1/0x1a70 __dev_queue_xmit+0x2257/0x3100 ip_finish_output2+0x615/0x19c0 ip_output+0x158/0x2b0 ip_send_skb+0x11b/0x160 udp_send_skb+0x64b/0xd80 udp_sendmsg+0x138c/0x1ec0 __sys_sendto+0x331/0x3a0 __x64_sys_sendto+0xe0/0x1c0 do_syscall_64+0x64/0x680 entry_SYSCALL_64_after_hwframe+0x76/0x7e The buggy address belongs to the object at ffff888018074000 which belongs to the cache kmalloc-512 of size 512 The buggy address is located 64 bytes inside of freed 512-byte region [ffff888018074000, ffff888018074200) =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Kito Xu (veritas501) --- net/sched/sch_teql.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index ec4039a201a2..2e86397a5219 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -101,7 +101,7 @@ teql_dequeue(struct Qdisc *sch) if (skb =3D=3D NULL) { struct net_device *m =3D qdisc_dev(q); if (m) { - dat->m->slaves =3D sch; + WRITE_ONCE(dat->m->slaves, sch); netif_wake_queue(m); } } else { @@ -136,19 +136,23 @@ teql_destroy(struct Qdisc *sch) if (!master) return; =20 - prev =3D master->slaves; + prev =3D READ_ONCE(master->slaves); if (prev) { + struct Qdisc *head =3D prev; + do { q =3D NEXT_SLAVE(prev); if (q =3D=3D sch) { NEXT_SLAVE(prev) =3D NEXT_SLAVE(q); - if (q =3D=3D master->slaves) { - master->slaves =3D NEXT_SLAVE(q); - if (q =3D=3D master->slaves) { + if (q =3D=3D head) { + WRITE_ONCE(master->slaves, + NEXT_SLAVE(q)); + if (q =3D=3D NEXT_SLAVE(q)) { struct netdev_queue *txq; =20 txq =3D netdev_get_tx_queue(master->dev, 0); - master->slaves =3D NULL; + WRITE_ONCE(master->slaves, + NULL); =20 dev_reset_queue(master->dev, txq, NULL); @@ -158,7 +162,7 @@ teql_destroy(struct Qdisc *sch) break; } =20 - } while ((prev =3D q) !=3D master->slaves); + } while ((prev =3D q) !=3D head); } } =20 @@ -285,7 +289,7 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb= , struct net_device *dev) int subq =3D skb_get_queue_mapping(skb); struct sk_buff *skb_res =3D NULL; =20 - start =3D master->slaves; + start =3D READ_ONCE(master->slaves); =20 restart: nores =3D 0; @@ -317,7 +321,7 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb= , struct net_device *dev) netdev_start_xmit(skb, slave, slave_txq, false) =3D=3D NETDEV_TX_OK) { __netif_tx_unlock(slave_txq); - master->slaves =3D NEXT_SLAVE(q); + WRITE_ONCE(master->slaves, NEXT_SLAVE(q)); netif_wake_queue(dev); master->tx_packets++; master->tx_bytes +=3D length; @@ -329,7 +333,7 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb= , struct net_device *dev) busy =3D 1; break; case 1: - master->slaves =3D NEXT_SLAVE(q); + WRITE_ONCE(master->slaves, NEXT_SLAVE(q)); return NETDEV_TX_OK; default: nores =3D 1; --=20 2.43.0