Skip to content

[LTS 8.6] net: mdio: fix undefined behavior in bit shift for __mdiobus_register #359

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 24, 2025

Conversation

pvts-mat
Copy link
Contributor

[LTS 8.6]
CVE-2022-49907
VULN-66411

Problem

https://www.cve.org/CVERecord?id=CVE-2022-49907

In the Linux kernel, the following vulnerability has been resolved:

net: mdio: fix undefined behavior in bit shift for __mdiobus_register

Shifting signed 32-bit value by 31 bits is undefined, so changing
significant bit to unsigned. The UBSAN warning calltrace like below:

UBSAN: shift-out-of-bounds in drivers/net/phy/mdio_bus.c:586:27
left shift of 1 by 31 places cannot be represented in type 'int'
Call Trace:
 <TASK>
 dump_stack_lvl+0x7d/0xa5
 dump_stack+0x15/0x1b
 ubsan_epilogue+0xe/0x4e
 __ubsan_handle_shift_out_of_bounds+0x1e7/0x20c
 __mdiobus_register+0x49d/0x4e0
 fixed_mdio_bus_init+0xd8/0x12d
 do_one_initcall+0x76/0x430
 kernel_init_freeable+0x3b3/0x422
 kernel_init+0x24/0x1e0
 ret_from_fork+0x1f/0x30
 </TASK>

Applicability: yes (similar as in #358)

The bug applies to LTS 8.6: the affected MDIO bus driver is central to the control of any ethernet interface device. The patch 40e4eb3 is not backported onto LTS 8.6, yet it is backported onto its mainline sibling stable 4.19 in a3fafc9.

Solution (same as in #358)

The solution in 40e4eb3 involves using the BIT(i) macro instead of the raw bit shift 1 << i to obtain an int with i -th bit set. The fully expanded BIT(i) macro boils down to 1UL << i construct operating on unsigned type where the left shit is defined for the full range of the type's bits (see include/vdso/bits.h, include/uapi/linux/const.h, include/linux/bits.h).

kABI check: passed

DEBUG=1 CVE=CVE-2022-49907 ./ninja.sh _kabi_checked__x86_64--test--ciqlts8_6-CVE-2022-49907

ninja: Entering directory `/data/build/rocky-patching'
[0/1] Check ABI of kernel [ciqlts8_6-CVE-2022-49907]
++ uname -m
+ python3 /data/src/ctrliq-github/kernel-dist-git-el-8.6/SOURCES/check-kabi -k /data/src/ctrliq-github/kernel-dist-git-el-8.6/SOURCES/Module.kabi_x86_64 -s vms/x86_64--build--ciqlts8_6/build_files/kernel-src-tree-ciqlts8_6-CVE-2022-49907/Module.symvers
kABI check passed
+ touch state/kernels/ciqlts8_6-CVE-2022-49907/x86_64/kabi_checked

Boot test: passed

boot-test.log

Kselftests: passed relative

Coverage

All the network-related tests (except the unstable ones):

net/forwarding (except sch_tbf_ets.sh, sch_tbf_root.sh, tc_actions.sh, mirror_gre_vlan_bridge_1q.sh, sch_tbf_prio.sh, sch_ets.sh, ipip_hier_gre_keys.sh, mirror_gre_bridge_1d_vlan.sh), net/mptcp (except simult_flows.sh), net (except reuseaddr_conflict, reuseport_addr_any.sh, xfrm_policy.sh, ip_defrag.sh, gro.sh, udpgro_fwd.sh, txtimestamp.sh, udpgso_bench.sh), netfilter (except nft_trans_stress.sh)

Reference

kselftests–ciqlts8_6–run1.log

Patch

kselftests–ciqlts8_6-CVE-2022-49907–run1.log

Comparison

The tests results for patch and reference are the same

$ ktests.xsh diff -d kselftests*.log

Column    File
--------  ----------------------------------------------
Status0   kselftests--ciqlts8_6--run1.log
Status1   kselftests--ciqlts8_6-CVE-2022-49907--run1.log

Specific tests: could not replicate (similar as in #358)

An attempt was made to replicate the bug by compiling the kernel with CONFIG_UBSAN=y. Unfortunately, the integer overflows resulting from bit shifts were not being captured by UBSAN, not only in the affected driver, but in general, as could have been demonstrated with the modified test_ubsan module (enabled with CONFIG_TEST_UBSAN=y) where, along the original test_ubsan_shift_out_of_bounds function:

static void test_ubsan_shift_out_of_bounds(void)
{
	volatile int val = -1;
	int val2 = 10;

	val2 <<= val;
}

an additional test_ubsan_shift_out_of_bounds1 was defined testing the exact situation as described in the CVE:

static void test_ubsan_shift_out_of_bounds1(void)
{
	volatile int val = 31;
	int val2 = 1;

	val2 <<= val;
}

The added test_ubsan_shift_out_of_bounds1 test was ignored by UBSAN at runtime (as well as original tests for {add, sub, mul, negate} overflows), which only kicked in during the division by zero test test_ubsan_divrem_overflow and the kernel rebooted immediately after:

[root@ciqlts-8-6 pvts]# modprobe test_ubsan
[  161.391007] ================================================================================
[  161.395529] UBSAN: Undefined behaviour in /mnt/code/kernel-src-tree-ciqlts8_6-ubsan/lib/test_ubsan.c:50:6
[  161.399017] division by zero
[  161.400090] CPU: 8 PID: 1502 Comm: modprobe Kdump: loaded Not tainted 4.18.0-ciqlts8_6-ubsan #1
[  161.403142] Hardware name: Red Hat KVM/RHEL, BIOS 1.16.3-2.el9_5.1 04/01/2014
[  161.405607] Call Trace:
[  161.406277]  dump_stack+0x41/0x60
[  161.407138]  ubsan_epilogue+0x5/0x25
[  161.408055]  __ubsan_handle_divrem_overflow.cold.15+0x23/0x49
[  161.409496]  ? kfree+0x1b4/0x200
[  161.410322]  test_ubsan_divrem_overflow+0x82/0x90 [test_ubsan]
[  161.411788]  test_ubsan_init+0x57/0x1000 [test_ubsan]
[  161.413060]  ? 0xffffffffc025e000
[  161.413906]  do_one_initcall+0x46/0x1d0
[  161.414892]  ? kmem_cache_alloc_trace+0x4c/0x390
[  161.415981]  ? load_module+0x152e/0x1b30
[  161.416706]  do_init_module+0x5a/0x230
[  161.417406]  load_module+0x153b/0x1b30
[  161.418097]  ? __do_sys_finit_module+0xa8/0x110
[  161.418928]  __do_sys_finit_module+0xa8/0x110
[  161.419728]  do_syscall_64+0x5b/0x1b0
[  161.420407]  entry_SYSCALL_64_after_hwframe+0x61/0xc6
[  161.421355] RIP: 0033:0x7f7e6bc559bd
[  161.422103] Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 9b 54 38 00 f7 d8 64 89 01 48
[  161.425618] RSP: 002b:00007ffea762ff58 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
[  161.426870] RAX: ffffffffffffffda RBX: 0000563ae91e0c00 RCX: 00007f7e6bc559bd
[  161.428045] RDX: 0000000000000000 RSI: 0000563ae7bc08b6 RDI: 0000000000000003
[  161.429235] RBP: 0000563ae7bc08b6 R08: 0000000000000000 R09: 0000563ae91e2780
[  161.430407] R10: 0000000000000003 R11: 0000000000000246 R12: 0000000000000000
[  161.431582] R13: 0000563ae91e0da0 R14: 0000000000040000 R15: 0000000000000000
[  161.432773] ================================================================================
[  161.434189] divide error: 0000 [#1] SMP PTI
[  161.434891] CPU: 8 PID: 1502 Comm: modprobe Kdump: loaded Not tainted 4.18.0-ciqlts8_6-ubsan #1
[  161.436339] Hardware name: Red Hat KVM/RHEL, BIOS 1.16.3-2.el9_5.1 04/01/2014
[  161.437496] RIP: 0010:test_ubsan_divrem_overflow+0x44/0x90 [test_ubsan]
[  161.438563] Code: 00 00 00 c7 44 24 0c 00 00 00 00 8b 5c 24 0c 8b 44 24 08 3d 00 00 00 80 0f 94 c1 83 fb ff 0f 94 c2 84 d1 75 2a 85 db 74 26 99 <f7> fb 89 44 24 08 48 8b 44 24 10 65 48 33 04 25 28 00 00 00 75 0a
[  161.441629] RSP: 0018:ffffb07583e6fc50 EFLAGS: 00010246
[  161.442489] RAX: 0000000000000010 RBX: 0000000000000000 RCX: 0000000000000000
[  161.443643] RDX: 0000000000000000 RSI: ffff9652dfc16758 RDI: ffff9652dfc16758
[  161.444806] RBP: 0000000000000030 R08: 0000000000000000 R09: ffffffffa701cda8
[  161.445969] R10: 3d3d3d3d3d3d3d3d R11: 3d3d3d3d3d3d3d3d R12: 0000000000000030
[  161.447098] R13: ffffffffc034a040 R14: ffffffffc034a718 R15: ffffffffc034a8d0
[  161.448239] FS:  00007f7e6cd42740(0000) GS:ffff9652dfc00000(0000) knlGS:0000000000000000
[  161.449520] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  161.450433] CR2: 00007ffea762dfd0 CR3: 0000000117a18002 CR4: 0000000000370ee0
[  161.451568] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[  161.452700] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[  161.453826] Call Trace:
[  161.454227]  test_ubsan_init+0x57/0x1000 [test_ubsan]
[  161.455025]  ? 0xffffffffc025e000
[  161.455585]  do_one_initcall+0x46/0x1d0
[  161.456199]  ? kmem_cache_alloc_trace+0x4c/0x390
[  161.456920]  ? load_module+0x152e/0x1b30
[  161.457541]  do_init_module+0x5a/0x230
[  161.458135]  load_module+0x153b/0x1b30
[  161.458727]  ? __do_sys_finit_module+0xa8/0x110
[  161.459436]  __do_sys_finit_module+0xa8/0x110
[  161.460123]  do_syscall_64+0x5b/0x1b0
[  161.460710]  entry_SYSCALL_64_after_hwframe+0x61/0xc6
[  161.461505] RIP: 0033:0x7f7e6bc559bd
[  161.462075] Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 9b 54 38 00 f7 d8 64 89 01 48
[  161.465158] RSP: 002b:00007ffea762ff58 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
[  161.466517] RAX: ffffffffffffffda RBX: 0000563ae91e0c00 RCX: 00007f7e6bc559bd
[  161.467756] RDX: 0000000000000000 RSI: 0000563ae7bc08b6 RDI: 0000000000000003
[  161.468997] RBP: 0000563ae7bc08b6 R08: 0000000000000000 R09: 0000563ae91e2780
[  161.470253] R10: 0000000000000003 R11: 0000000000000246 R12: 0000000000000000
[  161.471497] R13: 0000563ae91e0da0 R14: 0000000000040000 R15: 0000000000000000
[  161.472738] Modules linked in: test_ubsan(+) intel_rapl_msr intel_rapl_common isst_if_common nfit libnvdimm kvm_intel iTCO_wdt kvm iTCO_vendor_support irqbypass rapl joydev virtio_gpu pcspkr drm_kms_helper syscopyarea sysfillrect sysimgblt virtio_balloon i2c_i801 fb_sys_fops drm lpc_ich xfs libcrc32c sr_mod cdrom sg ahci libahci crct10dif_pclmul crc32_pclmul crc32c_intel ghash_clmulni_intel virtio_blk libata serio_raw virtio_console virtio_net net_failover failover virtiofs sunrpc dm_mirror dm_region_hash dm_log dm_mod fuse
[  161.480689] kvm-guest: disable async PF for cpu 8
[    0.000000] Linux version 4.18.0-ciqlts8_6-ubsan (pvts@ciqlts-8-6) (gcc version 8.5.0 20210514 (Red Hat 8.5.0-26) (GCC)) #1 SMP Mon Jun 23 04:30:21 UTC 2025
…

After this unsuccessful replication attempt the specific testing efforts were then abandoned.

jira VULN-66411
cve CVE-2022-49907
commit-author Gaosheng Cui <[email protected]>
commit 40e4eb3

Shifting signed 32-bit value by 31 bits is undefined, so changing
significant bit to unsigned. The UBSAN warning calltrace like below:

UBSAN: shift-out-of-bounds in drivers/net/phy/mdio_bus.c:586:27
left shift of 1 by 31 places cannot be represented in type 'int'
Call Trace:
 <TASK>
 dump_stack_lvl+0x7d/0xa5
 dump_stack+0x15/0x1b
 ubsan_epilogue+0xe/0x4e
 __ubsan_handle_shift_out_of_bounds+0x1e7/0x20c
 __mdiobus_register+0x49d/0x4e0
 fixed_mdio_bus_init+0xd8/0x12d
 do_one_initcall+0x76/0x430
 kernel_init_freeable+0x3b3/0x422
 kernel_init+0x24/0x1e0
 ret_from_fork+0x1f/0x30
 </TASK>

Fixes: 4fd5f81 ("phylib: allow incremental scanning of an mii bus")
	Signed-off-by: Gaosheng Cui <[email protected]>
	Reviewed-by: Andrew Lunn <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
	Signed-off-by: Jakub Kicinski <[email protected]>
(cherry picked from commit 40e4eb3)
	Signed-off-by: Marcin Wcisło <[email protected]>
@pvts-mat pvts-mat changed the title net: mdio: fix undefined behavior in bit shift for __mdiobus_register [LTS 8.6] net: mdio: fix undefined behavior in bit shift for __mdiobus_register Jun 23, 2025
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:

Copy link

@thefossguy-ciq thefossguy-ciq left a comment

Choose a reason for hiding this comment

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

🚤

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.

🥌

@PlaidCat PlaidCat merged commit 42dab7b into ctrliq:ciqlts8_6 Jun 24, 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.

4 participants