Skip to content

Commit fc68953

Browse files
author
Paolo Abeni
committed
Merge branch 'net_sched-hfsc-address-reentrant-enqueue-adding-class-to-eltree-twice'
Pedro Tammela says: ==================== net_sched: hfsc: Address reentrant enqueue adding class to eltree twice Savino says: "We are writing to report that this recent patch (141d343) can be bypassed, and a UAF can still occur when HFSC is utilized with NETEM. The patch only checks the cl->cl_nactive field to determine whether it is the first insertion or not, but this field is only incremented by init_vf. By using HFSC_RSC (which uses init_ed), it is possible to bypass the check and insert the class twice in the eltree. Under normal conditions, this would lead to an infinite loop in hfsc_dequeue for the reasons we already explained in this report. However, if TBF is added as root qdisc and it is configured with a very low rate, it can be utilized to prevent packets from being dequeued. This behavior can be exploited to perform subsequent insertions in the HFSC eltree and cause a UAF." To fix both the UAF and the infinite loop, with netem as an hfsc child, check explicitly in hfsc_enqueue whether the class is already in the eltree whenever the HFSC_RSC flag is set. Also add a TDC test to reproduce the UAF scenario. ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents 67af4ec + 2945ff7 commit fc68953

File tree

2 files changed

+43
-1
lines changed

2 files changed

+43
-1
lines changed

net/sched/sch_hfsc.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,11 @@ struct hfsc_sched {
175175

176176
#define HT_INFINITY 0xffffffffffffffffULL /* infinite time value */
177177

178+
static bool cl_in_el_or_vttree(struct hfsc_class *cl)
179+
{
180+
return ((cl->cl_flags & HFSC_FSC) && cl->cl_nactive) ||
181+
((cl->cl_flags & HFSC_RSC) && !RB_EMPTY_NODE(&cl->el_node));
182+
}
178183

179184
/*
180185
* eligible tree holds backlogged classes being sorted by their eligible times.
@@ -1040,6 +1045,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
10401045
if (cl == NULL)
10411046
return -ENOBUFS;
10421047

1048+
RB_CLEAR_NODE(&cl->el_node);
1049+
10431050
err = tcf_block_get(&cl->block, &cl->filter_list, sch, extack);
10441051
if (err) {
10451052
kfree(cl);
@@ -1572,7 +1579,7 @@ hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free)
15721579
sch->qstats.backlog += len;
15731580
sch->q.qlen++;
15741581

1575-
if (first && !cl->cl_nactive) {
1582+
if (first && !cl_in_el_or_vttree(cl)) {
15761583
if (cl->cl_flags & HFSC_RSC)
15771584
init_ed(cl, len);
15781585
if (cl->cl_flags & HFSC_FSC)

tools/testing/selftests/tc-testing/tc-tests/infra/qdiscs.json

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,5 +600,40 @@
600600
"matchPattern": "qdisc hfsc",
601601
"matchCount": "1",
602602
"teardown": ["$TC qdisc del dev $DEV1 root handle 1: drr"]
603+
},
604+
{
605+
"id": "309e",
606+
"name": "Test HFSC eltree double add with reentrant enqueue behaviour on netem",
607+
"category": [
608+
"qdisc",
609+
"hfsc"
610+
],
611+
"plugins": {
612+
"requires": "nsPlugin"
613+
},
614+
"setup": [
615+
"$IP link set dev $DUMMY up || true",
616+
"$IP addr add 10.10.11.10/24 dev $DUMMY || true",
617+
"$TC qdisc add dev $DUMMY root handle 1: tbf rate 8bit burst 100b latency 1s",
618+
"$TC qdisc add dev $DUMMY parent 1:0 handle 2:0 hfsc",
619+
"ping -I $DUMMY -f -c10 -s48 -W0.001 10.10.11.1 || true",
620+
"$TC class add dev $DUMMY parent 2:0 classid 2:1 hfsc rt m2 20Kbit",
621+
"$TC qdisc add dev $DUMMY parent 2:1 handle 3:0 netem duplicate 100%",
622+
"$TC class add dev $DUMMY parent 2:0 classid 2:2 hfsc rt m2 20Kbit",
623+
"$TC filter add dev $DUMMY parent 2:0 protocol ip prio 1 u32 match ip dst 10.10.11.2/32 flowid 2:1",
624+
"$TC filter add dev $DUMMY parent 2:0 protocol ip prio 2 u32 match ip dst 10.10.11.3/32 flowid 2:2",
625+
"ping -c 1 10.10.11.2 -I$DUMMY > /dev/null || true",
626+
"$TC filter del dev $DUMMY parent 2:0 protocol ip prio 1",
627+
"$TC class del dev $DUMMY classid 2:1",
628+
"ping -c 1 10.10.11.3 -I$DUMMY > /dev/null || true"
629+
],
630+
"cmdUnderTest": "$TC class change dev $DUMMY parent 2:0 classid 2:2 hfsc sc m2 20Kbit",
631+
"expExitCode": "0",
632+
"verifyCmd": "$TC -j class ls dev $DUMMY classid 2:1",
633+
"matchJSON": [],
634+
"teardown": [
635+
"$TC qdisc del dev $DUMMY handle 1:0 root",
636+
"$IP addr del 10.10.10.10/24 dev $DUMMY || true"
637+
]
603638
}
604639
]

0 commit comments

Comments
 (0)