| From bippy-5f407fcff5a0 Mon Sep 17 00:00:00 2001 |
| From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| To: <linux-cve-announce@vger.kernel.org> |
| Reply-to: <cve@kernel.org>, <linux-kernel@vger.kernel.org> |
| Subject: CVE-2024-53680: ipvs: fix UB due to uninitialized stack access in ip_vs_protocol_init() |
| |
| Description |
| =========== |
| |
| In the Linux kernel, the following vulnerability has been resolved: |
| |
| ipvs: fix UB due to uninitialized stack access in ip_vs_protocol_init() |
| |
| Under certain kernel configurations when building with Clang/LLVM, the |
| compiler does not generate a return or jump as the terminator |
| instruction for ip_vs_protocol_init(), triggering the following objtool |
| warning during build time: |
| |
| vmlinux.o: warning: objtool: ip_vs_protocol_init() falls through to next function __initstub__kmod_ip_vs_rr__935_123_ip_vs_rr_init6() |
| |
| At runtime, this either causes an oops when trying to load the ipvs |
| module or a boot-time panic if ipvs is built-in. This same issue has |
| been reported by the Intel kernel test robot previously. |
| |
| Digging deeper into both LLVM and the kernel code reveals this to be a |
| undefined behavior problem. ip_vs_protocol_init() uses a on-stack buffer |
| of 64 chars to store the registered protocol names and leaves it |
| uninitialized after definition. The function calls strnlen() when |
| concatenating protocol names into the buffer. With CONFIG_FORTIFY_SOURCE |
| strnlen() performs an extra step to check whether the last byte of the |
| input char buffer is a null character (commit 3009f891bb9f ("fortify: |
| Allow strlen() and strnlen() to pass compile-time known lengths")). |
| This, together with possibly other configurations, cause the following |
| IR to be generated: |
| |
| define hidden i32 @ip_vs_protocol_init() local_unnamed_addr #5 section ".init.text" align 16 !kcfi_type !29 { |
| %1 = alloca [64 x i8], align 16 |
| ... |
| |
| 14: ; preds = %11 |
| %15 = getelementptr inbounds i8, ptr %1, i64 63 |
| %16 = load i8, ptr %15, align 1 |
| %17 = tail call i1 @llvm.is.constant.i8(i8 %16) |
| %18 = icmp eq i8 %16, 0 |
| %19 = select i1 %17, i1 %18, i1 false |
| br i1 %19, label %20, label %23 |
| |
| 20: ; preds = %14 |
| %21 = call i64 @strlen(ptr noundef nonnull dereferenceable(1) %1) #23 |
| ... |
| |
| 23: ; preds = %14, %11, %20 |
| %24 = call i64 @strnlen(ptr noundef nonnull dereferenceable(1) %1, i64 noundef 64) #24 |
| ... |
| } |
| |
| The above code calculates the address of the last char in the buffer |
| (value %15) and then loads from it (value %16). Because the buffer is |
| never initialized, the LLVM GVN pass marks value %16 as undefined: |
| |
| %13 = getelementptr inbounds i8, ptr %1, i64 63 |
| br i1 undef, label %14, label %17 |
| |
| This gives later passes (SCCP, in particular) more DCE opportunities by |
| propagating the undef value further, and eventually removes everything |
| after the load on the uninitialized stack location: |
| |
| define hidden i32 @ip_vs_protocol_init() local_unnamed_addr #0 section ".init.text" align 16 !kcfi_type !11 { |
| %1 = alloca [64 x i8], align 16 |
| ... |
| |
| 12: ; preds = %11 |
| %13 = getelementptr inbounds i8, ptr %1, i64 63 |
| unreachable |
| } |
| |
| In this way, the generated native code will just fall through to the |
| next function, as LLVM does not generate any code for the unreachable IR |
| instruction and leaves the function without a terminator. |
| |
| Zero the on-stack buffer to avoid this possible UB. |
| |
| The Linux kernel CVE team has assigned CVE-2024-53680 to this issue. |
| |
| |
| Affected and fixed versions |
| =========================== |
| |
| Issue introduced in 2.6.12 with commit 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 and fixed in 5.4.287 with commit 31d1ddc1ce8e8d3f101a679243abb42a313ee88a |
| Issue introduced in 2.6.12 with commit 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 and fixed in 5.10.231 with commit 0b2cbed82b7c6504a8a0fbd181f92dd56b432c12 |
| Issue introduced in 2.6.12 with commit 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 and fixed in 5.15.174 with commit d6e1776f51c95827142f1d7064118e255e2deec1 |
| Issue introduced in 2.6.12 with commit 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 and fixed in 6.1.120 with commit 664d0feab92495b6a27edc3d1119e232c0fe8b2b |
| Issue introduced in 2.6.12 with commit 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 and fixed in 6.6.66 with commit 124834133b32f9386bb2d8581d9ab92f65e951e4 |
| Issue introduced in 2.6.12 with commit 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 and fixed in 6.12.5 with commit 48130002e64fd191b7d18efeb4d253fcc23e4688 |
| Issue introduced in 2.6.12 with commit 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 and fixed in 6.13 with commit 146b6f1112eb30a19776d6c323c994e9d67790db |
| |
| Please see https://www.kernel.org for a full list of currently supported |
| kernel versions by the kernel community. |
| |
| Unaffected versions might change over time as fixes are backported to |
| older supported kernel versions. The official CVE entry at |
| https://cve.org/CVERecord/?id=CVE-2024-53680 |
| will be updated if fixes are backported, please check that for the most |
| up to date information about this issue. |
| |
| |
| Affected files |
| ============== |
| |
| The file(s) affected by this issue are: |
| net/netfilter/ipvs/ip_vs_proto.c |
| |
| |
| Mitigation |
| ========== |
| |
| The Linux kernel CVE team recommends that you update to the latest |
| stable kernel version for this, and many other bugfixes. Individual |
| changes are never tested alone, but rather are part of a larger kernel |
| release. Cherry-picking individual commits is not recommended or |
| supported by the Linux kernel community at all. If however, updating to |
| the latest release is impossible, the individual changes to resolve this |
| issue can be found at these commits: |
| https://git.kernel.org/stable/c/31d1ddc1ce8e8d3f101a679243abb42a313ee88a |
| https://git.kernel.org/stable/c/0b2cbed82b7c6504a8a0fbd181f92dd56b432c12 |
| https://git.kernel.org/stable/c/d6e1776f51c95827142f1d7064118e255e2deec1 |
| https://git.kernel.org/stable/c/664d0feab92495b6a27edc3d1119e232c0fe8b2b |
| https://git.kernel.org/stable/c/124834133b32f9386bb2d8581d9ab92f65e951e4 |
| https://git.kernel.org/stable/c/48130002e64fd191b7d18efeb4d253fcc23e4688 |
| https://git.kernel.org/stable/c/146b6f1112eb30a19776d6c323c994e9d67790db |