(CVE-2025-23095) Samsung Exynos NPU Driver Double Free Leading to Privilege Escalation

CVE: CVE-2025-23095

Affected Versions: Samsung Galaxy S24+ (samsung/e2sxxx/e2s:14/UP1A.231005.007/S926BXXS3AXGD:user/release-keys); Samsung Exynos 1280, 2200, 1380, 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 1280, 2200, 1380, 1480, 2400
Tested Versions Samsung Galaxy S24+ (S926BXXS3AXGD)
CVE Identifier CVE-2025-23095
CVE Description A double free in the Samsung Exynos mobile processor NPU driver leads to privilege escalation
CWE Classification(s) CWE-415: Double 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

The double free exists in __prepare_IMB_info, which manages IMB (Inference Memory Buffer) allocation for an NPU session.

The function allocates IMB_info, assigns it to session->IMB_info, and then checks whether session->IMB_size exceeds the maximum permitted chunk size. If the size check fails, execution jumps to p_err, which frees IMB_info — but does not clear the session->IMB_info pointer:

int __prepare_IMB_info(struct npu_session *session, struct addr_info **IMB_av,
                       struct npu_memory_buffer *IMB_mem_buf)
{
    IMB_info = kcalloc(IMB_cnt, sizeof(struct addr_info), GFP_KERNEL);
    if (unlikely(!IMB_info)) {
        npu_err("IMB: IMB_info alloc is fail\n");
        ret = -ENOMEM;
        goto p_err;
    }

    session->IMB_info = IMB_info;
    ...
    if (session->IMB_size > (NPU_IMB_CHUNK_SIZE * NPU_IMB_CHUNK_MAX_NUM)) {
        npu_uerr("IMB_size(%zu) is larger than %u\n",
            session, session->IMB_size, NPU_IMB_CHUNK_SIZE * NPU_IMB_CHUNK_MAX_NUM);
        ret = -ENOMEM;
        goto p_err;
    }
    ...
p_err:
    if (likely(IMB_info))
        kfree(IMB_info);   /* freed here, but session->IMB_info still points to it */
}

When the session is subsequently torn down via _undo_s_graph_each_state, the stale session->IMB_info pointer is freed a second time:

imb_ion_unmap:
    addr_info = session->IMB_info;
    session->IMB_info = NULL;
    if (likely(addr_info))
        kfree(addr_info);   /* double free */

This double free of a kernel heap object is exploitable from the untrusted_app SELinux context to achieve local privilege escalation to root.

References

  • 1a13e0c1 — example of a similar fix addressing a dangling pointer not cleared on error path

Credit

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

Timeline