CVE-2026-87038

HIGH
Published Nov 4, 2026 Modified Nov 9, 2026 CWE-367

Description

The user-mode verification handler for the i3c_transfer() system call, z_vrfy_i3c_transfer() in drivers/i3c/i3c_handlers.c, validated the caller-supplied struct i3c_device_desc in place instead of snapshotting it. It confirmed only that the descriptor was readable by the calling thread (K_SYSCALL_MEMORY_READ()), read target->bus once to check it with K_SYSCALL_OBJ(), and then passed the caller's live pointer down. The implementation z_impl_i3c_transfer() re-reads target->bus from that user memory and dispatches through it as DEVICE_API_GET(i3c, target->bus)->i3c_xfers(...), so the bus that was validated is not necessarily the bus that is used. DEVICE_API_GET() performs no runtime type check outside CONFIG_DEVICE_API_ASSERT builds. On a build with CONFIG_USERSPACE and an I3C controller driver, a user thread that has been granted an I3C device object can exploit this with a second thread in the same memory domain: one thread calls i3c_transfer() while the other rewrites the bus field of the descriptor. The window between the check and the use spans the num_msgs validation, the message-array access check, a stack VLA allocation and a memcpy() of up to 32 struct i3c_msg, so the race is repeatable and can simply be retried until it lands. When the substitution succeeds, the kernel dereferences an attacker-chosen pointer as a struct device, loads a function pointer from the attacker-controlled api table and calls it in supervisor mode with attacker-influenced arguments. This yields kernel-mode code execution from an unprivileged user thread — a complete escape of the userspace memory-protection sandbox; lesser outcomes are an arbitrary two-level kernel read or a kernel fault. Builds without CONFIG_USERSPACE, or without an I3C driver, are unaffected. The fix copies the descriptor into a kernel-stack local with k_usermode_from_copy(), validates the bus in that copy, and dispatches on the copy, so the validated value is provably the value used.

Is your site exposed to CVE-2026-87038?

Run a free security scan — no signup, results in seconds.

CVSS v3.1 Score

7.0
HIGH
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H

EPSS — Exploit Prediction

0.0009
Probability of exploitation
0.00%
Percentile rank

EPSS estimates the probability that this vulnerability will be exploited in the wild within the next 30 days. A higher score means more likely to be exploited.

Weakness Type (CWE)

CWE-367 CWE-367

References

Frequently Asked Questions

What is CVE-2026-87038? +
The user-mode verification handler for the i3c_transfer() system call, z_vrfy_i3c_transfer() in drivers/i3c/i3c_handlers.c, validated the caller-supplied struct i3c_device_desc in place instead of snapshotting it. It confirmed only that the descriptor was readable by the calling thread (K_SYSCALL_MEMORY_READ()), read target->bus once to check it with K_SYSCALL_OBJ(), and then passed the caller's live pointer down. The implementation z_impl_i3c_transfer() re-reads target->bus from that user memory and dispatches through it as DEVICE_API_GET(i3c, target->bus)->i3c_xfers(...), so the bus that was validated is not necessarily the bus that is used. DEVICE_API_GET() performs no runtime type check outside CONFIG_DEVICE_API_ASSERT builds. On a build with CONFIG_USERSPACE and an I3C controller driver, a user thread that has been granted an I3C device object can exploit this with a second thread in the same memory domain: one thread calls i3c_transfer() while the other rewrites the bus field of the descriptor. The window between the check and the use spans the num_msgs validation, the message-array access check, a stack VLA allocation and a memcpy() of up to 32 struct i3c_msg, so the race is repeatable and can simply be retried until it lands. When the substitution succeeds, the kernel dereferences an attacker-chosen pointer as a struct device, loads a function pointer from the attacker-controlled api table and calls it in supervisor mode with attacker-influenced arguments. This yields kernel-mode code execution from an unprivileged user thread — a complete escape of the userspace memory-protection sandbox; lesser outcomes are an arbitrary two-level kernel read or a kernel fault. Builds without CONFIG_USERSPACE, or without an I3C driver, are unaffected. The fix copies the descriptor into a kernel-stack local with k_usermode_from_copy(), validates the bus in that copy, and dispatches on the copy, so the validated value is provably the value used. It has a CVSS v3.1 base score of 7.0 (HIGH).
How severe is CVE-2026-87038? +
CVE-2026-87038 has a CVSS v3.1 score of 7.0 out of 10, rated HIGH. This is a high-severity vulnerability that should be prioritized for patching. The EPSS score is 0.0009, placing it in the 0th percentile for exploitation probability.
How do I check if I'm vulnerable to CVE-2026-87038? +
You can use Secably's free Website Scanner to check your website for known vulnerabilities. For infrastructure scanning, use the Port Scanner to identify exposed services that may be affected. Check the vendor advisories linked above for specific patch and version information.

Related Vulnerabilities

Don't wait for an exploit

Scan your website for vulnerabilities like CVE-2026-87038 — free, no signup required.

Patch and protect

Block known exploits with a web application firewall while you patch, keep your own devices clean, or test the fix on a fresh server.

Compare VPS prices →

Affiliate links: we may earn a commission, your price stays the same.