Skip to content

Commit 3df275e

Browse files
congwangkuba-moo
authored andcommitted
net_sched: hfsc: Fix a UAF vulnerability in class handling
This patch fixes a Use-After-Free vulnerability in the HFSC qdisc class handling. The issue occurs due to a time-of-check/time-of-use condition in hfsc_change_class() when working with certain child qdiscs like netem or codel. The vulnerability works as follows: 1. hfsc_change_class() checks if a class has packets (q.qlen != 0) 2. It then calls qdisc_peek_len(), which for certain qdiscs (e.g., codel, netem) might drop packets and empty the queue 3. The code continues assuming the queue is still non-empty, adding the class to vttree 4. This breaks HFSC scheduler assumptions that only non-empty classes are in vttree 5. Later, when the class is destroyed, this can lead to a Use-After-Free The fix adds a second queue length check after qdisc_peek_len() to verify the queue wasn't emptied. Fixes: 21f4d5c ("net_sched/hfsc: fix curve activation in hfsc_change_class()") Reported-by: Gerrard Tai <gerrard.tai@starlabs.sg> Reviewed-by: Konstantin Khlebnikov <koct9i@gmail.com> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> Reviewed-by: Jamal Hadi Salim <jhs@mojatatu.com> Link: https://patch.msgid.link/20250417184732.943057-2-xiyou.wangcong@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent d861a5d commit 3df275e

File tree

1 file changed

+7
-2
lines changed

1 file changed

+7
-2
lines changed

net/sched/sch_hfsc.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -961,6 +961,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
961961

962962
if (cl != NULL) {
963963
int old_flags;
964+
int len = 0;
964965

965966
if (parentid) {
966967
if (cl->cl_parent &&
@@ -991,9 +992,13 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
991992
if (usc != NULL)
992993
hfsc_change_usc(cl, usc, cur_time);
993994

995+
if (cl->qdisc->q.qlen != 0)
996+
len = qdisc_peek_len(cl->qdisc);
997+
/* Check queue length again since some qdisc implementations
998+
* (e.g., netem/codel) might empty the queue during the peek
999+
* operation.
1000+
*/
9941001
if (cl->qdisc->q.qlen != 0) {
995-
int len = qdisc_peek_len(cl->qdisc);
996-
9971002
if (cl->cl_flags & HFSC_RSC) {
9981003
if (old_flags & HFSC_RSC)
9991004
update_ed(cl, len);

0 commit comments

Comments
 (0)