CVE-2024-53680

Severity CVSS v4.0:
Pending analysis
Type:
Unavailable / Other
Publication date:
11/01/2025
Last modified:
03/11/2025

Description

In the Linux kernel, the following vulnerability has been resolved:<br /> <br /> ipvs: fix UB due to uninitialized stack access in ip_vs_protocol_init()<br /> <br /> Under certain kernel configurations when building with Clang/LLVM, the<br /> compiler does not generate a return or jump as the terminator<br /> instruction for ip_vs_protocol_init(), triggering the following objtool<br /> warning during build time:<br /> <br /> vmlinux.o: warning: objtool: ip_vs_protocol_init() falls through to next function __initstub__kmod_ip_vs_rr__935_123_ip_vs_rr_init6()<br /> <br /> At runtime, this either causes an oops when trying to load the ipvs<br /> module or a boot-time panic if ipvs is built-in. This same issue has<br /> been reported by the Intel kernel test robot previously.<br /> <br /> Digging deeper into both LLVM and the kernel code reveals this to be a<br /> undefined behavior problem. ip_vs_protocol_init() uses a on-stack buffer<br /> of 64 chars to store the registered protocol names and leaves it<br /> uninitialized after definition. The function calls strnlen() when<br /> concatenating protocol names into the buffer. With CONFIG_FORTIFY_SOURCE<br /> strnlen() performs an extra step to check whether the last byte of the<br /> input char buffer is a null character (commit 3009f891bb9f ("fortify:<br /> Allow strlen() and strnlen() to pass compile-time known lengths")).<br /> This, together with possibly other configurations, cause the following<br /> IR to be generated:<br /> <br /> define hidden i32 @ip_vs_protocol_init() local_unnamed_addr #5 section ".init.text" align 16 !kcfi_type !29 {<br /> %1 = alloca [64 x i8], align 16<br /> ...<br /> <br /> 14: ; preds = %11<br /> %15 = getelementptr inbounds i8, ptr %1, i64 63<br /> %16 = load i8, ptr %15, align 1<br /> %17 = tail call i1 @llvm.is.constant.i8(i8 %16)<br /> %18 = icmp eq i8 %16, 0<br /> %19 = select i1 %17, i1 %18, i1 false<br /> br i1 %19, label %20, label %23<br /> <br /> 20: ; preds = %14<br /> %21 = call i64 @strlen(ptr noundef nonnull dereferenceable(1) %1) #23<br /> ...<br /> <br /> 23: ; preds = %14, %11, %20<br /> %24 = call i64 @strnlen(ptr noundef nonnull dereferenceable(1) %1, i64 noundef 64) #24<br /> ...<br /> }<br /> <br /> The above code calculates the address of the last char in the buffer<br /> (value %15) and then loads from it (value %16). Because the buffer is<br /> never initialized, the LLVM GVN pass marks value %16 as undefined:<br /> <br /> %13 = getelementptr inbounds i8, ptr %1, i64 63<br /> br i1 undef, label %14, label %17<br /> <br /> This gives later passes (SCCP, in particular) more DCE opportunities by<br /> propagating the undef value further, and eventually removes everything<br /> after the load on the uninitialized stack location:<br /> <br /> define hidden i32 @ip_vs_protocol_init() local_unnamed_addr #0 section ".init.text" align 16 !kcfi_type !11 {<br /> %1 = alloca [64 x i8], align 16<br /> ...<br /> <br /> 12: ; preds = %11<br /> %13 = getelementptr inbounds i8, ptr %1, i64 63<br /> unreachable<br /> }<br /> <br /> In this way, the generated native code will just fall through to the<br /> next function, as LLVM does not generate any code for the unreachable IR<br /> instruction and leaves the function without a terminator.<br /> <br /> Zero the on-stack buffer to avoid this possible UB.

Vulnerable products and versions

CPE From Up to
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 2.6.13 (including) 5.4.287 (excluding)
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 5.5 (including) 5.10.231 (excluding)
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 5.11 (including) 5.15.174 (excluding)
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 5.16 (including) 6.1.120 (excluding)
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 6.2 (including) 6.6.66 (excluding)
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 6.7 (including) 6.12.5 (excluding)
cpe:2.3:o:linux:linux_kernel:2.6.12:-:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:2.6.12:rc2:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:2.6.12:rc3:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:2.6.12:rc4:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:2.6.12:rc5:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.13:rc1:*:*:*:*:*:*