(CVE-2025-23103) Samsung Exynos NPU Driver Out-of-Bounds Write via Unbounded Loop Counter

CVE: CVE-2025-23103

Affected Versions: Samsung Galaxy S24+ (samsung/e2sxxx/e2s:14/UP1A.231005.007/S926BXXS3AXGD:user/release-keys); Samsung Exynos 1480, 2400

CVSS3.1: 7.8 (High) — CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

Summary

Product Samsung Exynos NPU Driver
Vendor Samsung
Severity High — a local attacker within untrusted_app SELinux context may exploit this to achieve local privilege escalation
Affected Versions Samsung Galaxy S24+ (Android 14); Exynos 1480, 2400
Tested Versions Samsung Galaxy S24+ (S926BXXS3AXGD)
CVE Identifier CVE-2025-23103
CVE Description A missing length check in the Samsung Exynos NPU driver leads to out-of-bounds writes, exploitable for local privilege escalation
CWE Classification(s) CWE-787: Out-of-Bounds Write

CVSS3.1 Scoring System

Base Score: 7.8 (High) Vector String: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

Metric Value
Attack Vector (AV) Local
Attack Complexity (AC) Low
Privileges Required (PR) Low
User Interaction (UI) None
Scope (S) Unchanged
Confidentiality (C) High
Integrity (I) High
Availability (A) High

Product Background

The Samsung Galaxy S24+ features a Neural Processing Unit (NPU) integrated into either the Snapdragon 8 Gen 3 or Exynos 2400 chipset depending on the market. The NPU accelerates on-device AI workloads including camera processing, real-time translation, and generative photo editing. The NPU kernel driver manages session state, memory allocation, and queue management on behalf of userspace applications.

Technical Details

In npu_queue_update it uses user provided count to process a loop, and didn’t check it larger than the actual queue_list->count

static int npu_queue_update(struct npu_queue_list *queue_list, struct vs4l_container_list *c)
{
	...
	for (i = 0; i < c->count; ++i) { // [1]
		container = &c->containers[i];
		q_container = &queue_list->containers[i]; // [2]
		q_container->count = container->count;

It takes q_container that can comes from out-of-bounds, and even it assign q_container->count without any check. Then OOB/ARB write could happen here:

		switch (container->memory) {
		case VS4L_MEMORY_DMABUF:
			for (j = 0; j < container->count; ++j) {
				buffer = &container->buffers[j];
				q_buffer = &q_container->buffers[j];

				if (q_buffer->roi.offset != buffer->roi.offset)
					q_buffer->roi.offset = buffer->roi.offset; // [3]
			}
			break;

Credit

Billy Jheng Bing-Jhong, Muhammad Alifa Ramdhan and Pan Zhenpeng of STAR Labs SG Pte. Ltd.

Timeline