---
id: "CVE-2026-98496"
kind: "vulnerability"
aliases: ["CVE-2026-98496"]
title: "Linux kernel: Airoha NPU driver can run freed memory on removal"
severity: "unknown"
cvss: null
epss: null
exploited: false
status: "open"
category: "runtime"
products: []
ecosystems: []
tags: ["airoha-soc", "embedded", "linux-kernel", "routers", "runtime"]
not_affected_if: ["driver-not-loaded", "no-airoha-hardware"]
published_at: "2026-10-18T16:17:00+00:00"
first_seen_at: "2026-10-23T21:57:15+00:00"
updated_at: "2026-10-25T05:25:38+00:00"
sources: [{"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-98496", "first_seen_at": "2026-10-23T21:57:15+00:00"}]
---

# Linux kernel: Airoha NPU driver can run freed memory on removal

In the Airoha NPU driver, a watchdog interrupt can queue work after the driver has cancelled it during removal, so the work runs on memory that was already freed. The sources do not state what an attacker can achieve beyond a use-after-free in kernel context.

_Summary, check and fix written by a model from the sources; labelled as such._

## How to check

- `uname -r` and compare against the kernel version that carries the fix, which the sources do not name
- `lsmod | grep airoha` to see whether the Airoha NPU driver is loaded at all
- unknown

## Fix

- Update the Linux kernel to a release that includes the upstream commit for this fix (version unknown from the sources)
- unknown

## Timeline

- 2026-10-23T21:57:15+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-98496

## From the sources

In the Linux kernel, the following vulnerability has been resolved:

net: airoha: npu: cancel wdt_work after releasing the WDT IRQ

airoha_npu_remove() calls cancel_work_sync() on each core's wdt_work,
but the watchdog IRQ that queues it is requested with devm_request_irq()
and is freed only after .remove() returns.  airoha_npu_wdt_handler() can
therefore schedule_work() again once the cancel has returned.  struct
airoha_npu, which contains the work, is devm_kzalloc()'d and is freed in
that same unwind, so the late work dereferences freed memory.

Register the work with devm_work_autocancel() before devm_request_irq()
and drop .remove().  Devres runs in reverse order, so the IRQ is freed
before cancel_work_sync(), including when probe fails.  A cancel left in
.remove() cannot get that order.  Initializing the work first also stops
a pending watchdog interrupt from queuing an uninitialized work item.
Probe currently calls INIT_WORK() only after devm_request_irq().

This issue was identified during our ongoing static-analysis research
while reviewing kernel code.

---

_Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai_
