Skip to content

Conversation

pvts-mat
Copy link
Contributor

[LTS 9.2]
CVE-2023-4623
VULN-6712

Problem

https://www.cve.org/CVERecord?id=CVE-2023-4623

A use-after-free vulnerability in the Linux kernel's net/sched: sch_hfsc (HFSC qdisc traffic control) component can be exploited to achieve local privilege escalation. If a class with a link-sharing curve (i.e. with the HFSC_FSC flag set) has a parent without a link-sharing curve, then init_vf() will call vttree_insert() on the parent, but vttree_remove() will be skipped in update_vf(). This leaves a dangling pointer that can cause a use-after-free.

Analysis and solution

A single commit was identified as a fix for this issue: b3d26c5702c7d6c45456326e56d2ccf3f103e60f net/sched: sch_hfsc: Ensure inner classes have fsc curve.

The solution consisted of rejecting the addition of a class with a link-sharing curve to the class without it (see Specific tests for details):

[root@ciqlts92 pvts]# (
    tc qdisc add dev lo root handle 1: hfsc default 10
    tc class add dev lo parent 1: classid 1:1 hfsc rt m2 100kbps
    tc class add dev lo parent 1:1 classid 1:10 hfsc ls m2 50kbps
    echo $?
)

Error: Invalid parent - parent class must have FSC.
2

The fix introduced a problem with existing network setup scripts for some users https://lore.kernel.org/all/[email protected]/:

I upgraded from 6.1.38 to 6.1.55 this morning and it broke my traffic shaping script, leaving me with a non-functional uplink on a remote router.

It was decided to fix the problem without breaking backwards compatibility https://lore.kernel.org/all/[email protected]/:

Setting 'rt' as a parent is incorrect and the man page is explicit about
it as it doesn't make sense 'qdisc wise'. Being able to set it has
always been wrong unfortunately…

Sure but unfortunately "we don't break backward compat" means
we can't really argue. It will take us more time to debate this
than to fix it (assuming we understand the initial problem).

Frankly one can even argue whether "exploitable by root / userns"
is more important than single user's init scripts breaking.
The "security" issues for root are dime a dozen.

The solution was to change the erroneous qdisc hierarchy to a correct one when the possible UAF condition was detected https://lore.kernel.org/all/[email protected]/:

As reported [1] disallowing 'rt' inner curves breaks already existing
scripts. Even though it doesn't make sense 'qdisc wise' users have been
relying on this behaviour since the qdisc inception.

We need users to update the scripts/applications to use 'sc' or 'ls'
as a inner curve instead of 'rt', but also avoid the UAF found by
Budimir, which was present since the qdisc inception.

The fix of the fix is given in the commit a13b67c9a015c4e21601ef9aa4ec9c5d972df1b4 net/sched: sch_hfsc: upgrade 'rt' to 'sc' when it becomes a inner curve

While the changes could be squashed into a single commit it was decided to retain the sequence of two commits for more straightforward LTS 9.2 - mainline patches correspondence.

The same solution was used already in other "version 9" branches centos9, ciqlts9_4, rocky9_4, rocky9_5, sig-cloud-9/5.14.0-427.37.1.el9_4, sig-cloud-9/5.14.0-427.40.1.el9_4, sig-cloud-9/5.14.0-427.42.1.el9_4, sig-cloud-9/5.14.0-503.19.1.el9_5, sig-cloud-9/5.14.0-503.22.1.el9_5:

git --no-pager log --decorate  --format="%h %cd %d %s" --date=short -n 2 9950d4d93

9950d4d93 2023-10-26  net/sched: sch_hfsc: upgrade 'rt' to 'sc' when it becomes a inner curve
ff4452fb0 2023-10-26  net/sched: sch_hfsc: Ensure inner classes have fsc curve

kABI check: passed

CVE=CVE-2023-4623 ./ninja.sh  _kabi_checked_ciqlts9_2-CVE-2023-4623

ninja: Entering directory `/data/build/rocky-patching'
[0/2] Create worktree for branch 'el-9.2': '/data/src/ctrliq-github/kernel-dist-git-el-9.2' (main repo: '/data/src/ctrliq-github/kernel-dist-git')
+ rm -rf /data/src/ctrliq-github/kernel-dist-git-el-9.2
+ git -C /data/src/ctrliq-github/kernel-dist-git worktree prune
+ git -C /data/src/ctrliq-github/kernel-dist-git worktree add /data/src/ctrliq-github/kernel-dist-git-el-9.2 el-9.2
Preparing worktree (checking out 'el-9.2')
HEAD is now at d55abe0 import kernel-5.14.0-284.30.1.el9_2.92ciq_lts.3.1
[1/2] Check ABI of kernel [ciqlts9_2-CVE-2023-4623]	_kabi_checked_ciqlts9_2-CVE-2023-4623
+ python3 /data/src/ctrliq-github/kernel-dist-git-el-9.2/SOURCES/check-kabi -k /data/src/ctrliq-github/kernel-dist-git-el-9.2/SOURCES/Module.kabi_x86_64 -s vms/build-ciqlts9_2/build_files/kernel-src-tree-ciqlts9_2-CVE-2023-4623/Module.symvers
kABI check passed
+ touch state/kernels/ciqlts9_2-CVE-2023-4623/kabi_checked

Boot test: passed

Refer to Specific tests for implicit boot test passing.

Kselftests: passed relative

Methodology

A mix of kernel-selftests-internal and source-compiled tests were used:

  • kernel-selftests-internal: bpf tests, except:
    • bpf:test_kmod.sh: takes very long time to finish and always fails anyway,
    • bpf:test_progs: unstable, can crash the machine,
    • bpf:test_progs-no_alu32: unstable, can crash the machine.
  • source-compiled: all the rest.

Coverage

bpf, breakpoints, capabilities, clone3, core, cpu-hotplug, cpufreq, drivers/dma-buf, drivers/net/bonding, drivers/net/team, efivarfs, filesystems, filesystems/binderfs, filesystems/epoll, firmware, fpu, ftrace, futex, gpio, intel_pstate, ipc, ir, kcmp, kvm, landlock, lib, livepatch, membarrier, memfd, memory-hotplug, mincore, mount, mqueue, nci, net, net/forwarding, net/mptcp, netfilter, nsfs, openat2, pid_namespace, pidfd, pstore, ptrace, rlimits, rseq, rtc, seccomp, sgx, sigaltstack, size, splice, static_keys, sync, syscall_user_dispatch, sysctl, tc-testing, tdx, timens, timers, tmpfs, tpm2, user, vDSO, vm, x86, zram

Reference ciqlts9_2 (9331e3b170fdba0a2ea80f61199d38a49d028c1a)

Three test runs were conducted on the reference kernel.
kselftests–mixed–ciqlts9_2–run1.log
kselftests–mixed–ciqlts9_2–run2.log
kselftests–mixed–ciqlts9_2–run3.log

Patch ciqlts9_2-CVE-2023-4623 (6136c4ee4485aaff99b711284fb43154cabd94ff)

Two test runs were conducted on the patched kernel.
kselftests–mixed–ciqlts9_2-CVE-2023-4623–run1.log
kselftests–mixed–ciqlts9_2-CVE-2023-4623–run2.log

Comparison

ktests.xsh  table --where "Summary = 'diff'"  kselftests*.log

Column    File
--------  ----------------------------------------------------
Status0   kselftests--mixed--ciqlts9_2--run1.log
Status1   kselftests--mixed--ciqlts9_2--run2.log
Status2   kselftests--mixed--ciqlts9_2--run3.log
Status3   kselftests--mixed--ciqlts9_2-CVE-2023-4623--run1.log
Status4   kselftests--mixed--ciqlts9_2-CVE-2023-4623--run2.log

TestCase         Status0  Status1  Status2  Status3  Status4  Summary
rtc:rtctest      pass     fail     fail     fail     fail     diff
timers:raw_skew  pass     pass     pass     pass     skip     diff

The rtc:rtctest test showed inconsistent behavior in the reference tests set itself, also it was already known to be inconsistent before. Added to the list of "flappy" tests for the ciqlts8_8-rt platform.

The timers:raw_skew was skipped in the second run of patch testing because of apparent conflict with time syncing daemons

# selftests: timers: raw_skew
# Estimating clock drift: -9.492(est) -107.636(act)	[SKIP]
# 1..0 # SKIP The clock was adjusted externally. Shutdown NTPd or other time sync daemons
ok 7 selftests: timers: raw_skew # SKIP

The change in behavior is not related to the introduced patch. Ideally the testing environment should have any clock-adjusting services switched off. Added to the list of flappy tests for now.

Specific tests: passed

The potential UAF condition was found to be reproducible with the following tc commands sequence:

tc qdisc add dev lo root handle 1: hfsc default 10
# Inner hfsc class constructed with 'rt' - realtime service
tc class add dev lo parent 1: classid 1:1 hfsc rt m2 100kbps
# Leaf hfsc class constructed with 'ls' - linksharing service
tc class add dev lo parent 1:1 classid 1:10 hfsc ls m2 50kbps

The "100kbps", "50kbps" parts are arbitrary. What's important is the use of rt for the inner class and ls for the leaf class. While the exact UAF was not obtained the commands helped confirm the efficacy of the patch.

Reference

The incorrect qdisc hierarchy can be created without any guardrails.

[root@ciqlts92 pvts]# (
    tc qdisc add dev lo root handle 1: hfsc default 10
    tc class add dev lo parent 1: classid 1:1 hfsc rt m2 100kbps
    tc class add dev lo parent 1:1 classid 1:10 hfsc ls m2 50kbps
    echo $?
)
0
[root@ciqlts92 pvts]# tc -g class show dev lo
tc -g class show dev lo
+---(1:) hfsc 
     +---(1:1) hfsc rt m1 0bit d 0us m2 800Kbit 
          +---(1:10) hfsc ls m1 0bit d 0us m2 400Kbit 

Full logs:
fix-replicate–ciqlts9_2.log

Patch

Creating the incorrect qdisc hierarchy raises a warning, but succeeds. Notice the type of inner class being sc instead of rt as shown by tc -g class show dev lo command.

[root@ciqlts92 pvts]# (
    tc qdisc add dev lo root handle 1: hfsc default 10
    tc class add dev lo parent 1: classid 1:1 hfsc rt m2 100kbps
    tc class add dev lo parent 1:1 classid 1:10 hfsc ls m2 50kbps
    echo $?
)
Warning: Forced curve change on parent 'rt' to 'sc'.
0
[root@ciqlts92 pvts]# tc -g class show dev lo
tc -g class show dev lo
+---(1:) hfsc 
     +---(1:1) hfsc sc m1 0bit d 0us m2 800Kbit 
          +---(1:10) hfsc ls m1 0bit d 0us m2 400Kbit 

Full logs:
fix-replicate–ciqlts9_2-CVE-2023-4623.log

jira VULN-6712
cve CVE-2023-4623
commit-author Budimir Markovic <[email protected]>
commit b3d26c5

HFSC assumes that inner classes have an fsc curve, but it is currently
possible for classes without an fsc curve to become parents. This leads
to bugs including a use-after-free.

Don't allow non-root classes without HFSC_FSC to become parents.

Fixes: 1da177e ("Linux-2.6.12-rc2")
	Reported-by: Budimir Markovic <[email protected]>
	Signed-off-by: Budimir Markovic <[email protected]>
	Acked-by: Jamal Hadi Salim <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
	Signed-off-by: Jakub Kicinski <[email protected]>
(cherry picked from commit b3d26c5)
	Signed-off-by: Marcin Wcisło <[email protected]>
jira VULN-6712
cve CVE-2023-4623
commit-author Pedro Tammela <[email protected]>
commit a13b67c

Christian Theune says:
   I upgraded from 6.1.38 to 6.1.55 this morning and it broke my traffic shaping script,
   leaving me with a non-functional uplink on a remote router.

A 'rt' curve cannot be used as a inner curve (parent class), but we were
allowing such configurations since the qdisc was introduced. Such
configurations would trigger a UAF as Budimir explains:
   The parent will have vttree_insert() called on it in init_vf(),
   but will not have vttree_remove() called on it in update_vf()
   because it does not have the HFSC_FSC flag set.

The qdisc always assumes that inner classes have the HFSC_FSC flag set.
This is by design as it doesn't make sense 'qdisc wise' for an 'rt'
curve to be an inner curve.

Budimir's original patch disallows users to add classes with a 'rt'
parent, but this is too strict as it breaks users that have been using
'rt' as a inner class. Another approach, taken by this patch, is to
upgrade the inner 'rt' into a 'sc', warning the user in the process.
It avoids the UAF reported by Budimir while also being more permissive
to bad scripts/users/code using 'rt' as a inner class.

Users checking the `tc class ls [...]` or `tc class get [...]` dumps would
observe the curve change and are potentially breaking with this change.

v1->v2: https://lore.kernel.org/all/[email protected]/
- Correct 'Fixes' tag and merge with revert (Jakub)

	Cc: Christian Theune <[email protected]>
	Cc: Budimir Markovic <[email protected]>
Fixes: b3d26c5 ("net/sched: sch_hfsc: Ensure inner classes have fsc curve")
	Signed-off-by: Pedro Tammela <[email protected]>
	Acked-by: Jamal Hadi Salim <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
	Signed-off-by: Jakub Kicinski <[email protected]>
(cherry picked from commit a13b67c)
	Signed-off-by: Marcin Wcisło <[email protected]>
@gvrose8192
Copy link

Added reviewers - checks have all passed.

Copy link

@gvrose8192 gvrose8192 left a comment

Choose a reason for hiding this comment

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

Similar to others in the series and high confidence this is the correct solution. LGTM - Thanks!

Copy link
Collaborator

@bmastbergen bmastbergen left a comment

Choose a reason for hiding this comment

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

🥌

@gvrose8192
Copy link

All checks have passed and approved.

@gvrose8192 gvrose8192 merged commit 963fd18 into ctrliq:ciqlts9_2 Feb 21, 2025
2 checks passed
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.

3 participants