| 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-50194: arm64: probes: Fix uprobes for big-endian kernels |
| |
| Description |
| =========== |
| |
| In the Linux kernel, the following vulnerability has been resolved: |
| |
| arm64: probes: Fix uprobes for big-endian kernels |
| |
| The arm64 uprobes code is broken for big-endian kernels as it doesn't |
| convert the in-memory instruction encoding (which is always |
| little-endian) into the kernel's native endianness before analyzing and |
| simulating instructions. This may result in a few distinct problems: |
| |
| * The kernel may may erroneously reject probing an instruction which can |
| safely be probed. |
| |
| * The kernel may erroneously erroneously permit stepping an |
| instruction out-of-line when that instruction cannot be stepped |
| out-of-line safely. |
| |
| * The kernel may erroneously simulate instruction incorrectly dur to |
| interpretting the byte-swapped encoding. |
| |
| The endianness mismatch isn't caught by the compiler or sparse because: |
| |
| * The arch_uprobe::{insn,ixol} fields are encoded as arrays of u8, so |
| the compiler and sparse have no idea these contain a little-endian |
| 32-bit value. The core uprobes code populates these with a memcpy() |
| which similarly does not handle endianness. |
| |
| * While the uprobe_opcode_t type is an alias for __le32, both |
| arch_uprobe_analyze_insn() and arch_uprobe_skip_sstep() cast from u8[] |
| to the similarly-named probe_opcode_t, which is an alias for u32. |
| Hence there is no endianness conversion warning. |
| |
| Fix this by changing the arch_uprobe::{insn,ixol} fields to __le32 and |
| adding the appropriate __le32_to_cpu() conversions prior to consuming |
| the instruction encoding. The core uprobes copies these fields as opaque |
| ranges of bytes, and so is unaffected by this change. |
| |
| At the same time, remove MAX_UINSN_BYTES and consistently use |
| AARCH64_INSN_SIZE for clarity. |
| |
| Tested with the following: |
| |
| | #include <stdio.h> |
| | #include <stdbool.h> |
| | |
| | #define noinline __attribute__((noinline)) |
| | |
| | static noinline void *adrp_self(void) |
| | { |
| | void *addr; |
| | |
| | asm volatile( |
| | " adrp %x0, adrp_self\n" |
| | " add %x0, %x0, :lo12:adrp_self\n" |
| | : "=r" (addr)); |
| | } |
| | |
| | |
| | int main(int argc, char *argv) |
| | { |
| | void *ptr = adrp_self(); |
| | bool equal = (ptr == adrp_self); |
| | |
| | printf("adrp_self => %p\n" |
| | "adrp_self() => %p\n" |
| | "%s\n", |
| | adrp_self, ptr, equal ? "EQUAL" : "NOT EQUAL"); |
| | |
| | return 0; |
| | } |
| |
| .... where the adrp_self() function was compiled to: |
| |
| | 00000000004007e0 <adrp_self>: |
| | 4007e0: 90000000 adrp x0, 400000 <__ehdr_start> |
| | 4007e4: 911f8000 add x0, x0, #0x7e0 |
| | 4007e8: d65f03c0 ret |
| |
| Before this patch, the ADRP is not recognized, and is assumed to be |
| steppable, resulting in corruption of the result: |
| |
| | # ./adrp-self |
| | adrp_self => 0x4007e0 |
| | adrp_self() => 0x4007e0 |
| | EQUAL |
| | # echo 'p /root/adrp-self:0x007e0' > /sys/kernel/tracing/uprobe_events |
| | # echo 1 > /sys/kernel/tracing/events/uprobes/enable |
| | # ./adrp-self |
| | adrp_self => 0x4007e0 |
| | adrp_self() => 0xffffffffff7e0 |
| | NOT EQUAL |
| |
| After this patch, the ADRP is correctly recognized and simulated: |
| |
| | # ./adrp-self |
| | adrp_self => 0x4007e0 |
| | adrp_self() => 0x4007e0 |
| | EQUAL |
| | # |
| | # echo 'p /root/adrp-self:0x007e0' > /sys/kernel/tracing/uprobe_events |
| | # echo 1 > /sys/kernel/tracing/events/uprobes/enable |
| | # ./adrp-self |
| | adrp_self => 0x4007e0 |
| | adrp_self() => 0x4007e0 |
| | EQUAL |
| |
| The Linux kernel CVE team has assigned CVE-2024-50194 to this issue. |
| |
| |
| Affected and fixed versions |
| =========================== |
| |
| Issue introduced in 4.10 with commit 9842ceae9fa8deae141533d52a6ead7666962c09 and fixed in 4.19.323 with commit b6a638cb600e13f94b5464724eaa6ab7f3349ca2 |
| Issue introduced in 4.10 with commit 9842ceae9fa8deae141533d52a6ead7666962c09 and fixed in 5.4.285 with commit e6ab336213918575124d6db43dc5d3554526242e |
| Issue introduced in 4.10 with commit 9842ceae9fa8deae141533d52a6ead7666962c09 and fixed in 5.10.229 with commit cf9ddf9ed94c15564a05bbf6e9f18dffa0c7df80 |
| Issue introduced in 4.10 with commit 9842ceae9fa8deae141533d52a6ead7666962c09 and fixed in 5.15.170 with commit cf60d19d40184e43d9a624e55a0da73be09e938d |
| Issue introduced in 4.10 with commit 9842ceae9fa8deae141533d52a6ead7666962c09 and fixed in 6.1.115 with commit 14841bb7a531b96e2dde37423a3b33e75147c60d |
| Issue introduced in 4.10 with commit 9842ceae9fa8deae141533d52a6ead7666962c09 and fixed in 6.6.58 with commit 8165bf83b8a64be801d59cd2532b0d1ffed74d00 |
| Issue introduced in 4.10 with commit 9842ceae9fa8deae141533d52a6ead7666962c09 and fixed in 6.11.5 with commit 3d2530c65be04e93720e30f191a7cf1a3aa8b51c |
| Issue introduced in 4.10 with commit 9842ceae9fa8deae141533d52a6ead7666962c09 and fixed in 6.12 with commit 13f8f1e05f1dc36dbba6cba0ae03354c0dafcde7 |
| |
| 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-50194 |
| 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: |
| arch/arm64/include/asm/uprobes.h |
| arch/arm64/kernel/probes/uprobes.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/b6a638cb600e13f94b5464724eaa6ab7f3349ca2 |
| https://git.kernel.org/stable/c/e6ab336213918575124d6db43dc5d3554526242e |
| https://git.kernel.org/stable/c/cf9ddf9ed94c15564a05bbf6e9f18dffa0c7df80 |
| https://git.kernel.org/stable/c/cf60d19d40184e43d9a624e55a0da73be09e938d |
| https://git.kernel.org/stable/c/14841bb7a531b96e2dde37423a3b33e75147c60d |
| https://git.kernel.org/stable/c/8165bf83b8a64be801d59cd2532b0d1ffed74d00 |
| https://git.kernel.org/stable/c/3d2530c65be04e93720e30f191a7cf1a3aa8b51c |
| https://git.kernel.org/stable/c/13f8f1e05f1dc36dbba6cba0ae03354c0dafcde7 |