---
id: CVE-2026-87039
title: >-
  I2S configure syscall handler passes an unvalidated user-supplied kernel
  object pointer to drivers
summary: >-
  The user-mode syscall verifier z_vrfy_i2s_configure() in
  drivers/i2s/i2s_handlers.c copies the caller's struct i2s_config in from user
  memory and then, when cfg->frame_clk_freq is 0 (the API's "unconfigure the
  stream" request), jumps str…
severity: high
cvss: 7.8
cvssVector: 'CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:H'
cvssSource: cna
cwe:
  - CWE-787
vendor: zephyrproject
product: zephyr
affected:
  - zephyr >= 4.4.0 < 4.5.0
published: '2026-11-04'
updated: '2026-11-04'
sourceUpdated: '2026-11-04T06:09:04.926Z'
source: CVEORG
sourceUrl: 'https://www.cve.org/CVERecord?id=CVE-2026-87039'
references:
  - url: >-
      https://github.com/zephyrproject-rtos/zephyr/commit/e9898c4d22f69575d9b5f297b3df130ceaff1b8f
    label: Fix commit
  - url: >-
      https://github.com/zephyrproject-rtos/zephyr/security/advisories/GHSA-g43m-x6vj-5cg2
    label: GHSA-g43m-x6vj-5cg2
tags:
  - cve.org
epss: 0.00101
epssPercentile: 0.00905
ingestedAt: '2026-11-05T20:33:06.717Z'
---

## Overview

The user-mode syscall verifier z_vrfy_i2s_configure() in drivers/i2s/i2s_handlers.c copies the caller's struct i2s_config in from user memory and then, when cfg->frame_clk_freq is 0 (the API's "unconfigure the stream" request), jumps straight to z_impl_i2s_configure() without performing the K_SYSCALL_OBJ(config.mem_slab, K_OBJ_MEM_SLAB) ownership/type check or the block_size sanity check. The mem_slab field is a struct k_mem_slab *, so on that path a completely unvalidated, user-chosen pointer reaches driver code that is entitled to trust it as a real kernel object.

Any thread running under CONFIG_USERSPACE that has access to an I2S device object can trigger this with a single i2s_configure() call. Most in-tree drivers special-case frame_clk_freq == 0 and never store the caller's structure, but drivers/i2s/i2s_litex.c does not: i2s_litex_configure() only logs a warning for a mismatched frame clock, then memcpy()s the caller's config into stream->cfg and marks the stream I2S_STATE_READY. A subsequent i2s_trigger() with I2S_TRIGGER_START enables the FIFO interrupt, and the interrupt handlers i2s_litex_isr_rx() / i2s_litex_isr_tx() then call k_mem_slab_alloc() and k_mem_slab_free() on the attacker-supplied pointer in supervisor context.

The result is an arbitrary-pointer read/write primitive executed by the kernel on behalf of an unprivileged thread — k_mem_slab_alloc() takes a spinlock at slab->lock and reads and writes slab->free_list and the link word inside the returned "block" — which defeats the CONFIG_USERSPACE isolation boundary entirely. The same missing validation is a hazard for out-of-tree I2S drivers that retain the configuration on the unconfigure path. Builds without CONFIG_USERSPACE are unaffected, since the verifier is not used.

The fix zeroes config.mem_slab and config.block_size on the unconfigure path so the driver can never receive an unvalidated pointer, while still allowing a stream to be unconfigured by a caller that does not own a memory slab, as the API documents.

## Affected

- `zephyr >= 4.4.0 < 4.5.0`

## Remediation

Refer to the linked advisories for vendor-supplied fixes and affected version ranges.
