{"id":"CVE-2026-90833","aliases":["EUVD-2026-123038"],"status":"published","title":"Signed offset bypasses bounds check in simulated EEPROM driver, allowing out-of-bounds kernel memory read and write from user mode","description":"The simulated EEPROM driver validated access ranges in eeprom_range_is_valid() (drivers/eeprom/eeprom_simulator.c) with a single test, (offset + len) \u003c= config-\u003esize. Because offset is a signed off_t and len an unsigned size_t of the same rank, the addition is evaluated in unsigned arithmetic: a negative offset combined with a compensating len wraps the sum back into the accepted range. eeprom_sim_read() and eeprom_sim_write() then memcpy() through the EEPROM(addr) macro, which is plain pointer arithmetic on the driver's static mock_eeprom array, so the copy addresses memory located before that array.\n\neeprom_read() and eeprom_write() are __syscall entry points, and their verification handlers in drivers/eeprom/eeprom_handlers.c check only the device object and the caller's own data buffer (K_SYSCALL_MEMORY_READ/K_SYSCALL_MEMORY_WRITE) — the offset argument is passed to the driver unvalidated. With CONFIG_USERSPACE=y, a CONFIG_EEPROM_SIMULATOR device instance, and the device object granted to a user thread (the usage the in-tree tests/drivers/eeprom/api suite exercises from ZTEST_USER threads), an unprivileged thread could supply a negative offset and have the kernel perform the copy on its behalf.\n\nThe result is an out-of-bounds read of kernel .bss returned into the caller's buffer and, via the write path, an out-of-bounds write of caller-supplied bytes over kernel memory preceding mock_eeprom. Both the start address and the length of the affected span are attacker-selected, so the primitive is sufficient to corrupt adjacent kernel state and escape the user-mode sandbox. Exposure is limited to builds that instantiate the simulated EEPROM (status = \"okay\" by default on qemu_x86 and native_sim, otherwise added by a devicetree overlay) together with userspace isolation.\n\nThe fix rejects negative offsets and performs the remaining bound check without overflow.","severity":{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","level":"high","assessor":"cna","from":"cve"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":false},"cwes":["CWE-787"],"published":"2026-11-10T22:07:42Z","modified":"2026-11-10T22:07:42Z","products":[{"vendor":"zephyrproject","product":"zephyr"},{"vendor":"zephyrproject-rtos","product":"zephyr"}],"references":[{"url":"https://github.com/zephyrproject-rtos/zephyr/commit/ce2ec9b3a34d71f52f5d1d7491b91393e334713e","tags":["patch"]},{"url":"https://github.com/zephyrproject-rtos/zephyr/security/advisories/GHSA-vf6j-hcx8-44vh"}],"sources":{"cve":[{"id":"CVE-2026-90833","title":"Signed offset bypasses bounds check in simulated EEPROM driver, allowing out-of-bounds kernel memory read and write from user mode","description":"The simulated EEPROM driver validated access ranges in eeprom_range_is_valid() (drivers/eeprom/eeprom_simulator.c) with a single test, (offset + len) \u003c= config-\u003esize. Because offset is a signed off_t and len an unsigned size_t of the same rank, the addition is evaluated in unsigned arithmetic: a negative offset combined with a compensating len wraps the sum back into the accepted range. eeprom_sim_read() and eeprom_sim_write() then memcpy() through the EEPROM(addr) macro, which is plain pointer arithmetic on the driver's static mock_eeprom array, so the copy addresses memory located before that array.\n\neeprom_read() and eeprom_write() are __syscall entry points, and their verification handlers in drivers/eeprom/eeprom_handlers.c check only the device object and the caller's own data buffer (K_SYSCALL_MEMORY_READ/K_SYSCALL_MEMORY_WRITE) — the offset argument is passed to the driver unvalidated. With CONFIG_USERSPACE=y, a CONFIG_EEPROM_SIMULATOR device instance, and the device object granted to a user thread (the usage the in-tree tests/drivers/eeprom/api suite exercises from ZTEST_USER threads), an unprivileged thread could supply a negative offset and have the kernel perform the copy on its behalf.\n\nThe result is an out-of-bounds read of kernel .bss returned into the caller's buffer and, via the write path, an out-of-bounds write of caller-supplied bytes over kernel memory preceding mock_eeprom. Both the start address and the length of the affected span are attacker-selected, so the primitive is sufficient to corrupt adjacent kernel state and escape the user-mode sandbox. Exposure is limited to builds that instantiate the simulated EEPROM (status = \"okay\" by default on qemu_x86 and native_sim, otherwise added by a devicetree overlay) together with userspace isolation.\n\nThe fix rejects negative offsets and performs the remaining bound check without overflow.","status":"published","published":"2026-11-10T22:07:42.603Z","modified":"2026-11-10T22:07:42.603Z","cvss":[{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","level":"high","assessor":"cna"}],"cwes":["CWE-787"],"updated_at":"2026-11-10T23:49:31.970756Z"}],"euvd":[{"id":"EUVD-2026-123038","description":"The simulated EEPROM driver validated access ranges in eeprom_range_is_valid() (drivers/eeprom/eeprom_simulator.c) with a single test, (offset + len) \u003c= config-\u003esize. Because offset is a signed off_t and len an unsigned size_t of the same rank, the addition is evaluated in unsigned arithmetic: a negative offset combined with a compensating len wraps the sum back into the accepted range. eeprom_sim_read() and eeprom_sim_write() then memcpy() through the EEPROM(addr) macro, which is plain pointer arithmetic on the driver's static mock_eeprom array, so the copy addresses memory located before that array.\n\neeprom_read() and eeprom_write() are __syscall entry points, and their verification handlers in drivers/eeprom/eeprom_handlers.c check only the device object and the caller's own data buffer (K_SYSCALL_MEMORY_READ/K_SYSCALL_MEMORY_WRITE) — the offset argument is passed to the driver unvalidated. With CONFIG_USERSPACE=y, a CONFIG_EEPROM_SIMULATOR device instance, and the device object granted to a user thread (the usage the in-tree tests/drivers/eeprom/api suite exercises from ZTEST_USER threads), an unprivileged thread could supply a negative offset and have the kernel perform the copy on its behalf.\n\nThe result is an out-of-bounds read of kernel .bss returned into the caller's buffer and, via the write path, an out-of-bounds write of caller-supplied bytes over kernel memory preceding mock_eeprom. Both the start address and the length of the affected span are attacker-selected, so the primitive is sufficient to corrupt adjacent kernel state and escape the user-mode sandbox. Exposure is limited to builds that instantiate the simulated EEPROM (status = \"okay\" by default on qemu_x86 and native_sim, otherwise added by a devicetree overlay) together with userspace isolation.\n\nThe fix rejects negative offsets and performs the remaining bound check without overflow.","status":"published","published":"2026-11-10T22:07:42Z","modified":"2026-11-10T22:07:42Z","cvss":[{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","level":"high"}],"updated_at":"2026-11-10T23:24:16.163953Z"}],"nvd":[{"id":"CVE-2026-90833","description":"The simulated EEPROM driver validated access ranges in eeprom_range_is_valid() (drivers/eeprom/eeprom_simulator.c) with a single test, (offset + len) \u003c= config-\u003esize. Because offset is a signed off_t and len an unsigned size_t of the same rank, the addition is evaluated in unsigned arithmetic: a negative offset combined with a compensating len wraps the sum back into the accepted range. eeprom_sim_read() and eeprom_sim_write() then memcpy() through the EEPROM(addr) macro, which is plain pointer arithmetic on the driver's static mock_eeprom array, so the copy addresses memory located before that array.\n\neeprom_read() and eeprom_write() are __syscall entry points, and their verification handlers in drivers/eeprom/eeprom_handlers.c check only the device object and the caller's own data buffer (K_SYSCALL_MEMORY_READ/K_SYSCALL_MEMORY_WRITE) — the offset argument is passed to the driver unvalidated. With CONFIG_USERSPACE=y, a CONFIG_EEPROM_SIMULATOR device instance, and the device object granted to a user thread (the usage the in-tree tests/drivers/eeprom/api suite exercises from ZTEST_USER threads), an unprivileged thread could supply a negative offset and have the kernel perform the copy on its behalf.\n\nThe result is an out-of-bounds read of kernel .bss returned into the caller's buffer and, via the write path, an out-of-bounds write of caller-supplied bytes over kernel memory preceding mock_eeprom. Both the start address and the length of the affected span are attacker-selected, so the primitive is sufficient to corrupt adjacent kernel state and escape the user-mode sandbox. Exposure is limited to builds that instantiate the simulated EEPROM (status = \"okay\" by default on qemu_x86 and native_sim, otherwise added by a devicetree overlay) together with userspace isolation.\n\nThe fix rejects negative offsets and performs the remaining bound check without overflow.","status":"published","published":"2026-11-10T22:21:14.32Z","modified":"2026-11-10T22:21:14.427Z","cvss":[{"version":"3.1","score":7.8,"vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","level":"high","assessor":"secondary"}],"cwes":["CWE-787"],"updated_at":"2026-11-11T00:21:54.825455Z"}]}}
