---
id: "CVE-2026-99184"
kind: "vulnerability"
aliases: ["CVE-2026-99184"]
title: "Linux kernel: Rockchip NPU driver overruns core array on unbind and rebind"
severity: "unknown"
cvss: null
epss: null
exploited: false
status: "open"
category: "infrastructure"
products: []
ecosystems: []
tags: ["arm", "embedded", "infrastructure", "linux-kernel", "rk3588", "rockchip"]
not_affected_if: ["no-core-unbind", "no-rockchip-npu"]
published_at: "2026-10-28T11:17:39+00:00"
first_seen_at: "2026-10-28T11:32:37+00:00"
updated_at: "2026-10-28T11:35:20+00:00"
sources: [{"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-99184", "first_seen_at": "2026-10-28T11:32:37+00:00"}]
---

# Linux kernel: Rockchip NPU driver overruns core array on unbind and rebind

The Linux kernel accel/rocket driver for Rockchip NPUs loses track of the last core when cores are unbound, so a rebind writes past the end of the rdev->cores array. The sources describe a silent out-of-bounds write and a UBSAN-reported invalid bool load, with no confirmed attacker capability.

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

## How to check

- `uname -r` to see the running kernel version
- Check whether the `rocket` module is loaded with `lsmod | grep rocket`
- Check for Rockchip NPU devices bound to the driver under `/sys/bus/platform/drivers/rocket/`

## Fix

- Update the Linux kernel to a release that includes the upstream commit titled 'accel/rocket: search every core slot when a core is removed'
- Until patched, avoid unbinding individual NPU cores on affected systems (unknown exact fixed version)

## Timeline

- 2026-10-28T11:32:37+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-99184

## From the sources

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

accel/rocket: search every core slot when a core is removed

rocket_remove() decrements rdev->num_cores for each core it removes,
while find_core_for_dev() searches slots 0 to num_cores - 1. Unbinding
the cores in the order they were bound therefore loses the last one: by
the time it is removed the search range has already shrunk past its
slot, so find_core_for_dev() returns -1 and rocket_remove() gives up
without doing anything.

num_cores never reaches zero, rocket_device_fini() never runs, and the
file-scoped rdev keeps pointing at a device that is going away. Binding
the cores again starts from that stale count, because rocket_probe()
takes rdev->num_cores as the slot to fill. On an RK3588, which describes
three cores, the second round lands on slots 1, 2 and 3 while rdev->cores
was allocated with room for three:

  rocket fdab0000.npu: Rockchip NPU core 1 version: 1179210309
  rocket fdac0000.npu: Rockchip NPU core 2 version: 1179210309
  rocket fdad0000.npu: Rockchip NPU core 3 version: 1179210309

The write to rdev->cores[3] is past the end of the array.

Nothing in tree reads the core array often enough to notice, so the
overrun is silent today. It turned up while testing a devfreq series on
top of this, where a worker walks every core a few times a second, and
UBSAN caught the first bool it read out of the overrun entry:

  UBSAN: invalid-load in drivers/accel/rocket/rocket_devfreq.c:47:10
  load of value 5 is not a valid value for type '_Bool'
  Workqueue: devfreq_wq devfreq_monitor

Record how many slots were allocated and search all of them. Every core
is then found on removal, num_cores reaches zero, the device is torn down
and a later bind starts from a clean rdev.

This does not make unbinding a single core out of several work. probe
still takes num_cores as the slot to fill, so rebinding one core while
its siblings stay bound would write over a slot that is already in use,
and rocket_open() still reaches for cores[0] whether or not anything is
there. Both of those want more thought than a fix should carry.

Found by unbinding and rebinding all three cores on an Orange Pi 5 Plus.
With this applied, 25 unbind/rebind rounds and 5 module unload/reload
rounds run clean there: the cores land in slots 0, 1 and 2 every time,
whichever order they are bound in, and the shared supply goes back to a
single user after each round.

---

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