天下漏洞,尽知其名
HIGH

CVE-2026-18414 Zephyr ADC MAX32 缓冲区溢出漏洞

影响越界写入,可能造成内存破坏或权限提升

AI 研判

Zephyr 的 ADI MAX32 ADC 驱动未遵守 ADC API 约定,在 start_read() 中把字节数 buffer_size 与采样数直接比较,忽略了每个采样占 2 字节,导致缓冲区不足时仍通过校验。随后 Wrap_MXC_ADC_GetData() 按 uint16_t 写入,造成越界写。

影响范围

Zephyr ADI MAX32 ADC 驱动

使用 Zephyr RTOS 且启用 ADI MAX32 ADC 驱动(drivers/adc/adc_max32.c)的版本;具体受影响版本范围暂无公开信息。

漏洞详情

漏洞类型为缓冲区越界写入(CWE-787)。成因是驱动校验时混淆了字节数与采样数,未乘以 sizeof(uint16_t)。同步读取经 adc_max32_start_channel()、异步读取经 adc_max32_isr() 写入,均可能越过缓冲区末尾。

利用条件与风险

需要本地或具备相应权限的调用者构造缓冲区过小的 ADC 采样序列;在启用 CONFIG_USERSPACE 时可通过系统调用触发,实战中可导致内存破坏甚至权限提升。

修复建议

官方修复方案暂无公开信息;临时缓解可避免使用过小的 ADC 缓冲区,或在受影响驱动中修正 buffer_size 校验逻辑。

原始情报

The ADC API requires each driver to reject a sampling sequence whose destination buffer is too small: the buffer_size field of struct adc_sequence in include/zephyr/drivers/adc.h documents that “the driver must ensure that samples are not written beyond the limit and it must return an error if the buffer turns out to be not large enough”. The ADI MAX32 driver did not honour that contract. start_read() in drivers/adc/adc_max32.c compared buffer_size, a byte count, against a sample count ((1 + extra_samplings) channels), ignoring sizeof(uint16_t), so it accepted a buffer half the required size. The samples are then stored through the uint16_t data->buffer by Wrap_MXC_ADC_GetData(), which writes two bytes per sample and advances the pointer by one uint16_t: in adc_max32_start_channel() for synchronous reads, and in adc_max32_isr() for asynchronous ones. A sequence selecting two channels with a two-byte buffer, for example, passes the check and has its second sample written past the end of the buffer.

On a build with CONFIG_USERSPACE, adc_read() and adc_read_async() are system calls. The handler in drivers/adc/adc_handlers.c copies the sequence in from user memory, verifies only that [buffer, buffer + buffer_size) is writable by the calling thread, and rejects a user-supplied options->callback; it deliberately leaves the size arithmetic to the driver. A user-mode thread that has been granted access to a MAX32 ADC device object therefore fully controls channels, buffer, buffer_size and options->extra_samplings, and can make the driver write twice as many bytes as its buffer holds. Because the check scales with extra_samplings, the overrun equals the length of the buffer itself, up to channels * 65536 bytes past its end, since the sample pointer is only rewound on a repeat sampling, never on the extra samplings of a sequence.

The resulting stores are performed by the driver in kernel mode (in the system call itself, the ADC context timer, or the ADC interrupt handler for asynchronous reads), where the MPU does not restrict the thread’s memory domain, so the write walks linearly out of the user partition and into adjacent memory such as other partitions, kernel data or thread stacks. The impact is kernel-memory corruption of attacker-chosen length at an attacker-chosen offset, a plausible privilege-escalation and denial-of-service primitive from an unprivileged user-mode thread. Builds without CONFIG_USERSPACE are affected only as a caller-side robustness defect, since the application itself supplies the buffer.

The fix replaces that check in start_read() with a call to the new shared helper adc_sequence_validate_buffer() in drivers/adc/adc_common.c, passing sizeof(uint16_t) as the sample size. The helper computes active_channels sizeof(uint16_t) (1 + extra_samplings) and returns -ENOMEM before any sampling is started.