(CVE-2025-23098) Samsung Exynos NPU Driver Use-After-Free in IMB Memory Buffer Leading to Privilege Escalation

CVE: CVE-2025-23098

Affected Versions: Samsung Galaxy S24+ (samsung/e2sxxx/e2s:14/UP1A.231005.007/S926BXXS3AXGD:user/release-keys); Samsung Exynos 980, 990, 1080, 2100, 1280, 2200, 1380

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 980, 990, 1080, 2100, 1280, 2200, 1380
Tested Versions Samsung Galaxy S24+ (S926BXXS3AXGD)
CVE Identifier CVE-2025-23098
CVE Description A use-after-free in the Samsung Exynos mobile processor NPU driver leads to privilege escalation
CWE Classification(s) CWE-416: Use After Free

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 is a privileged component that manages session state, memory allocation, and inference buffer management on behalf of userspace applications.

Technical Details

In __prepare_IMB_info, it will assign IMB_mem_buf to session->IMB_mem_buf. If session->IMB_size is quite big, it will goto p_err free the IMB_mem_buf but do not clean the pointer in session. But it only set IMB_mem_buf pointer to NULL, but do not set session->IMB_mem_buf to NULL.

int __config_session_info(struct npu_session *session)
{
    	IMB_mem_buf = kcalloc(1, sizeof(struct npu_memory_buffer), GFP_KERNEL);
        ...
        ret = __prepare_IMB_info(session, &IMB_av, IMB_mem_buf);
        ...
}
    
int __prepare_IMB_info(struct npu_session *session, struct addr_info **IMB_av, struct npu_memory_buffer *IMB_mem_buf)
{
    ...
	session->IMB_mem_buf = IMB_mem_buf;
	if (session->IMB_size > (NPU_IMB_CHUNK_SIZE * NPU_IMB_CHUNK_MAX_NUM)) {
		...
		goto p_err;
	}
p_err:
	if (likely(IMB_mem_buf)) {
		kfree(IMB_mem_buf); // [1]
		IMB_mem_buf = NULL;

Then it will be freed again at __release_imb_mem_buf:

static inline void __release_imb_mem_buf(struct npu_session *session)
{
	struct npu_memory_buffer *ion_mem_buf = session->IMB_mem_buf;
	if (likely(ion_mem_buf)) {
                ...
		session->IMB_mem_buf = NULL;
		kfree(ion_mem_buf);
	}
}

Credit

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

Timeline