Skip to content

Conversation

@bmastbergen
Copy link
Collaborator

Background

There is interdiff output for every commit in this PR (Yay!). So I'll just tell the story of these commits via the interdiff output:

brett@iconium ~/ciq/kernel-src-tree-tools
 % python ./run_interdiff.py --repo ~/ciq/kernel-src-tree --pr_branch bmastbergen_ciqcbr7_9/many-vulns-10-23-25 --base_branch origin/ciqcbr7_9 --interdiff /home/brett/ciq/interdiff/patchutils/src/interdiff

The upstream ext4 commit below is using the ext4_has_feature_bigalloc helper, but that doesn't exist in this old kernel. There are macros that do the same thing, so I used those instead

[DIFF] PR commit 22b4375884061 (ext4: avoid resizing to a partial cluster size) → upstream 69cb8e9d8cd9
Differences found:

  diff -u b/fs/ext4/resize.c b/fs/ext4/resize.c
  --- b/fs/ext4/resize.c
  +++ b/fs/ext4/resize.c
  @@ -1907,7 +1907,7 @@
         * callers that blindly resize the filesystem to the full size of
         * the underlying block device.
         */
  -     if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_BIGALLOC))
  +     if (ext4_has_feature_bigalloc(sb))
                n_blocks_count &= ~((1 << EXT4_CLUSTER_BITS(sb)) - 1);

   retry:

I picked up the commit below as a prerequisite for CVE-2025-38000. It made the fix apply cleaner and it addresses some potential use-after-free (but it doesn't have its own CVE). There is a diff to upstream because sch_cbs doesn't have child qdisc support in this kernel, so that part of the commit was just left out.

[DIFF] PR commit 5caf5926133f6 (sched: Avoid dereferencing skb pointer after child enqueue) → upstream f6bab199315b
Differences found:

  only in patch2:
  unchanged:
  --- a/net/sched/sch_cbs.c
  +++ b/net/sched/sch_cbs.c
  @@ -88,13 +88,14 @@ static int cbs_child_enqueue(struct sk_buff *skb, struct Qdisc *sch,
                             struct Qdisc *child,
                             struct sk_buff **to_free)
   {
  +     unsigned int len = qdisc_pkt_len(skb);
        int err;

        err = child->ops->enqueue(skb, child, to_free);
        if (err != NET_XMIT_SUCCESS)
                return err;

  -     qdisc_qstats_backlog_inc(sch, skb);
  +     sch->qstats.backlog += len;
        sch->q.qlen++;

        return NET_XMIT_SUCCESS;

Even with the prerequisite commit there was a conflict in the file below because the conditional in hfsc_enqueue is slightly different in this kernel versus upstream.

if (first && !cl->cl_nactive) {
vs.
if (cl->qdisc->q.qlen == 1) {

[DIFF] PR commit 88a736d16a2ff (sch_hfsc: Fix qlen accounting bug when using peek in hfsc_enqueue()) → upstream 3f981138109f
Differences found:

  diff -u b/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
  --- b/net/sched/sch_hfsc.c
  +++ b/net/sched/sch_hfsc.c
  @@ -1569,6 +1569,9 @@
                return err;
        }

  +     sch->qstats.backlog += len;
  +     sch->q.qlen++;
  +
        if (first && !cl->cl_nactive) {
                if (cl->cl_flags & HFSC_RSC)
                        init_ed(cl, len);

The commit below is a bugfix for the prior commit and is associated with CVE-2025-38350 itself. It cleanly applied, but interdiff did flag some differences in the surrounding context. The function signature is different:

void qdisc_tree_reduce_backlog(struct Qdisc *sch, int n, int len)
vs
void qdisc_tree_reduce_backlog(struct Qdisc *sch, unsigned int n, unsigned int len)

And qdisc lookup is preformed slightly different:

sch = qdisc_lookup_rcu(qdisc_dev(sch), TC_H_MAJ(parentid));
vs
sch = qdisc_lookup(qdisc_dev(sch), TC_H_MAJ(parentid));

[DIFF] PR commit a6a76d7d7562f (net/sched: Always pass notifications when child class becomes empty) → upstream 103406b38c60
Differences found:

  diff -u b/net/sched/sch_api.c b/net/sched/sch_api.c
  --- b/net/sched/sch_api.c
  +++ b/net/sched/sch_api.c
  @@ -780,15 +780,12 @@

   void qdisc_tree_reduce_backlog(struct Qdisc *sch, int n, int len)
   {
  -     bool qdisc_is_offloaded = sch->flags & TCQ_F_OFFLOADED;
        const struct Qdisc_class_ops *cops;
        unsigned long cl;
        u32 parentid;
        bool notify;
        int drops;

  -     if (n == 0 && len == 0)
  -             return;
        drops = max_t(int, n, 0);
        rcu_read_lock();
        while ((parentid = sch->parent)) {
  @@ -797,17 +794,8 @@

                if (sch->flags & TCQ_F_NOPARENT)
                        break;
  -             /* Notify parent qdisc only if child qdisc becomes empty.
  -              *
  -              * If child was empty even before update then backlog
  -              * counter is screwed and we skip notification because
  -              * parent class is already passive.
  -              *
  -              * If the original child was offloaded then it is allowed
  -              * to be seem as empty, so the parent is notified anyway.
  -              */
  -             notify = !sch->q.qlen && !WARN_ON_ONCE(!n &&
  -                                                    !qdisc_is_offloaded);
  +             /* Notify parent qdisc only if child qdisc becomes empty. */
  +             notify = !sch->q.qlen;
                /* TODO: perform the search on a per txq basis */
                sch = qdisc_lookup_rcu(qdisc_dev(sch), TC_H_MAJ(parentid));
                if (sch == NULL) {

brett@iconium ~/ciq/kernel-src-tree-tools
 %

Commits

    ext4: avoid resizing to a partial cluster size

    jira VULN-135014
    cve CVE-2022-50020
    commit-author Kiselev, Oleg <[email protected]>
    commit 69cb8e9d8cd97cdf5e293b26d70a9dee3e35e6bd
    upstream-diff This kernel doesn't have the ext4_feature_has_bigalloc
                  helper, so this commit uses the EXT4_HAS_RO_COMPAT_FEATURE
                  macro which does the same thing
    sched: Avoid dereferencing skb pointer after child enqueue

    jira VULN-68349
    cve-pre CVE-2025-38000
    commit-author Toke Høiland-Jørgensen <[email protected]>
    commit f6bab199315b70fd83fe3ee0947bc84c7a35f3d4
    upstream-diff No changes were made to sch_cbs.c because it doesn't
                  support child qdiscs in this kernel because it lacks
                  "990e35ecba1c cbs: Add support for graft function"
    sch_hfsc: Fix qlen accounting bug when using peek in hfsc_enqueue()

    jira VULN-68349
    cve CVE-2025-38000
    commit-author Cong Wang <[email protected]>
    commit 3f981138109f63232a5fb7165938d4c945cc1b9d
    upstream-diff Minor conflict when applying because the conditional
                  in hfsc_enqueue is slightly different in this version
                  of the kernel.
    net/sched: Always pass notifications when child class becomes empty

    jira VULN-136681
    cve CVE-2025-38350
    commit-author Lion Ackermann <[email protected]>
    commit 103406b38c600fec1fe375a77b27d87e314aea09

Build Log

/home/brett/kernel-src-tree
Running make mrproper...
[TIMER]{MRPROPER}: 8s
x86_64 architecture detected, copying config
‘configs/kernel-3.10.0-x86_64.config’ -> ‘.config’
Setting Local Version for build
CONFIG_LOCALVERSION="-bmastbergen_ciqcbr7_9_many-vulns-10-23-25-a6a76d7"
Making olddefconfig
--
  HOSTLD  scripts/kconfig/conf
scripts/kconfig/conf --olddefconfig Kconfig
#
# configuration written to .config
#
Starting Build
scripts/kconfig/conf --silentoldconfig Kconfig
  SYSHDR  arch/x86/syscalls/../include/generated/uapi/asm/unistd_32.h
  SYSHDR  arch/x86/syscalls/../include/generated/uapi/asm/unistd_64.h
  SYSHDR  arch/x86/syscalls/../include/generated/uapi/asm/unistd_x32.h
  SYSTBL  arch/x86/syscalls/../include/generated/asm/syscalls_32.h
--
  H16TOFW firmware/edgeport/down2.fw
  IHEX2FW firmware/whiteheat.fw
  IHEX2FW firmware/whiteheat_loader.fw
  IHEX2FW firmware/keyspan_pda/keyspan_pda.fw
  IHEX2FW firmware/keyspan_pda/xircom_pgs.fw
[TIMER]{BUILD}: 495s
Making Modules
  INSTALL arch/x86/crypto/ablk_helper.ko
  INSTALL arch/x86/crypto/aesni-intel.ko
  INSTALL arch/x86/crypto/blowfish-x86_64.ko
  INSTALL arch/x86/crypto/camellia-aesni-avx-x86_64.ko
--
  INSTALL /lib/firmware/whiteheat_loader.fw
  INSTALL /lib/firmware/whiteheat.fw
  INSTALL /lib/firmware/keyspan_pda/keyspan_pda.fw
  INSTALL /lib/firmware/keyspan_pda/xircom_pgs.fw
  DEPMOD  3.10.0-bmastbergen_ciqcbr7_9_many-vulns-10-23-25-a6a76d7+
[TIMER]{MODULES}: 13s
Making Install
sh ./arch/x86/boot/install.sh 3.10.0-bmastbergen_ciqcbr7_9_many-vulns-10-23-25-a6a76d7+ arch/x86/boot/bzImage \
	System.map "/boot"
[TIMER]{INSTALL}: 42s
Checking kABI
kABI check passed
Setting Default Kernel to /boot/vmlinuz-3.10.0-bmastbergen_ciqcbr7_9_many-vulns-10-23-25-a6a76d7+ and Index to 0
Hopefully Grub2.0 took everything ... rebooting after time metrices
[TIMER]{MRPROPER}: 8s
[TIMER]{BUILD}: 495s
[TIMER]{MODULES}: 13s
[TIMER]{INSTALL}: 42s
[TIMER]{TOTAL} 565s
Rebooting in 10 seconds

Testing

selftest-3.10.0-1160.119.1.el7_9.ciqcbr.9.1.x86_64-1.log

selftest-3.10.0-bmastbergen_ciqcbr7_9_many-vulns-10-23-25-a6a76d7+-1.log

brett@lycia ~/ciq/many-79-vulns-10-23-25
 % grep ^ok selftest-3.10.0-1160.119.1.el7_9.ciqcbr.9.1.x86_64-1.log | wc -l
4
brett@lycia ~/ciq/many-79-vulns-10-23-25
 % grep ^ok selftest-3.10.0-bmastbergen_ciqcbr7_9_many-vulns-10-23-25-a6a76d7+-1.log | wc -l
4
brett@lycia ~/ciq/many-79-vulns-10-23-25
 % grep ok <(diff -adU0 <(grep -a ^ok selftest-3.10.0-1160.119.1.el7_9.ciqcbr.9.1.x86_64-1.log | sort -h) <(grep -a ^ok selftest-3.10.0-bmastbergen_ciqcbr7_9_many-vulns-10-23-25-a6a76d7+-1.log | sort -h))
brett@lycia ~/ciq/many-79-vulns-10-23-25
 %

jira VULN-135014
cve CVE-2022-50020
commit-author Kiselev, Oleg <[email protected]>
commit 69cb8e9
upstream-diff This kernel doesn't have the ext4_feature_has_bigalloc
              helper, so this commit uses the EXT4_HAS_RO_COMPAT_FEATURE
              macro which does the same thing

This patch avoids an attempt to resize the filesystem to an
unaligned cluster boundary.  An online resize to a size that is not
integral to cluster size results in the last iteration attempting to
grow the fs by a negative amount, which trips a BUG_ON and leaves the fs
with a corrupted in-memory superblock.

	Signed-off-by: Oleg Kiselev <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
	Signed-off-by: Theodore Ts'o <[email protected]>
(cherry picked from commit 69cb8e9)
	Signed-off-by: Brett Mastbergen <[email protected]>
jira VULN-68349
cve-pre CVE-2025-38000
commit-author Toke Høiland-Jørgensen <[email protected]>
commit f6bab19
upstream-diff No changes were made to sch_cbs.c because it doesn't
              support child qdiscs in this kernel because it lacks
              "990e35ecba1c cbs: Add support for graft function"

Parent qdiscs may dereference the pointer to the enqueued skb after
enqueue. However, both CAKE and TBF call consume_skb() on the original skb
when splitting GSO packets, leading to a potential use-after-free in the
parent. Fix this by avoiding dereferencing the skb pointer after enqueueing
to the child.

	Signed-off-by: Toke Høiland-Jørgensen <[email protected]>
	Signed-off-by: David S. Miller <[email protected]>
(cherry picked from commit f6bab19)
	Signed-off-by: Brett Mastbergen <[email protected]>
jira VULN-68349
cve CVE-2025-38000
commit-author Cong Wang <[email protected]>
commit 3f98113
upstream-diff Minor conflict when applying because the conditional
              in hfsc_enqueue is slightly different in this version
              of the kernel.

When enqueuing the first packet to an HFSC class, hfsc_enqueue() calls the
child qdisc's peek() operation before incrementing sch->q.qlen and
sch->qstats.backlog. If the child qdisc uses qdisc_peek_dequeued(), this may
trigger an immediate dequeue and potential packet drop. In such cases,
qdisc_tree_reduce_backlog() is called, but the HFSC qdisc's qlen and backlog
have not yet been updated, leading to inconsistent queue accounting. This
can leave an empty HFSC class in the active list, causing further
consequences like use-after-free.

This patch fixes the bug by moving the increment of sch->q.qlen and
sch->qstats.backlog before the call to the child qdisc's peek() operation.
This ensures that queue length and backlog are always accurate when packet
drops or dequeues are triggered during the peek.

Fixes: 12d0ad3 ("net/sched/sch_hfsc.c: handle corner cases where head may change invalidating calculated deadline")
	Reported-by: Mingi Cho <[email protected]>
	Signed-off-by: Cong Wang <[email protected]>
	Reviewed-by: Simon Horman <[email protected]>
Link: https://patch.msgid.link/[email protected]
	Reviewed-by: Jamal Hadi Salim <[email protected]>
	Signed-off-by: Paolo Abeni <[email protected]>
(cherry picked from commit 3f98113)
	Signed-off-by: Brett Mastbergen <[email protected]>
jira VULN-136681
cve CVE-2025-38350
commit-author Lion Ackermann <[email protected]>
commit 103406b

Certain classful qdiscs may invoke their classes' dequeue handler on an
enqueue operation. This may unexpectedly empty the child qdisc and thus
make an in-flight class passive via qlen_notify(). Most qdiscs do not
expect such behaviour at this point in time and may re-activate the
class eventually anyways which will lead to a use-after-free.

The referenced fix commit attempted to fix this behavior for the HFSC
case by moving the backlog accounting around, though this turned out to
be incomplete since the parent's parent may run into the issue too.
The following reproducer demonstrates this use-after-free:

    tc qdisc add dev lo root handle 1: drr
    tc filter add dev lo parent 1: basic classid 1:1
    tc class add dev lo parent 1: classid 1:1 drr
    tc qdisc add dev lo parent 1:1 handle 2: hfsc def 1
    tc class add dev lo parent 2: classid 2:1 hfsc rt m1 8 d 1 m2 0
    tc qdisc add dev lo parent 2:1 handle 3: netem
    tc qdisc add dev lo parent 3:1 handle 4: blackhole

    echo 1 | socat -u STDIN UDP4-DATAGRAM:127.0.0.1:8888
    tc class delete dev lo classid 1:1
    echo 1 | socat -u STDIN UDP4-DATAGRAM:127.0.0.1:8888

Since backlog accounting issues leading to a use-after-frees on stale
class pointers is a recurring pattern at this point, this patch takes
a different approach. Instead of trying to fix the accounting, the patch
ensures that qdisc_tree_reduce_backlog always calls qlen_notify when
the child qdisc is empty. This solves the problem because deletion of
qdiscs always involves a call to qdisc_reset() and / or
qdisc_purge_queue() which ultimately resets its qlen to 0 thus causing
the following qdisc_tree_reduce_backlog() to report to the parent. Note
that this may call qlen_notify on passive classes multiple times. This
is not a problem after the recent patch series that made all the
classful qdiscs qlen_notify() handlers idempotent.

Fixes: 3f98113 ("sch_hfsc: Fix qlen accounting bug when using peek in hfsc_enqueue()")
	Signed-off-by: Lion Ackermann <[email protected]>
	Reviewed-by: Jamal Hadi Salim <[email protected]>
	Acked-by: Cong Wang <[email protected]>
	Acked-by: Jamal Hadi Salim <[email protected]>
Link: https://patch.msgid.link/[email protected]
	Signed-off-by: Jakub Kicinski <[email protected]>
(cherry picked from commit 103406b)
	Signed-off-by: Brett Mastbergen <[email protected]>
@github-actions
Copy link

🔍 Upstream Linux Kernel Commit Check

  • ⚠️ PR commit a6a76d7d7562 (net/sched: Always pass notifications when child class becomes empty) references upstream commit
    103406b38c60 which has been referenced by a Fixes: tag in the upstream
    Linux kernel:
    87c6efc5ce9c net/sched: ets: use old 'nbands' while purging unused classes (Davide Caratti)

This is an automated message from the kernel commit checker workflow.

@bmastbergen
Copy link
Collaborator Author

🔍 Upstream Linux Kernel Commit Check

  • ⚠️ PR commit a6a76d7d7562 (net/sched: Always pass notifications when child class becomes empty) references upstream commit
    103406b38c60 which has been referenced by a Fixes: tag in the upstream
    Linux kernel:
    87c6efc5ce9c net/sched: ets: use old 'nbands' while purging unused classes (Davide Caratti)

This is an automated message from the kernel commit checker workflow.

This does not apply as this kernel does not have sch_ets

Copy link
Collaborator

@PlaidCat PlaidCat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@bmastbergen bmastbergen merged commit 409c085 into ciqcbr7_9 Oct 28, 2025
2 checks passed
@bmastbergen bmastbergen deleted the bmastbergen_ciqcbr7_9/many-vulns-10-23-25 branch October 28, 2025 13:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants