|WARNING| [2/2] net/tap: fix use after free on interrupt handle

dpdklab at iol.unh.edu dpdklab at iol.unh.edu
Wed Nov 4 00:14:38 CET 2026


Test-Label: ai-code-review
Test-Status: WARNING
https://dpdk.org/patch/172605

_AI Code Review_

=== Patch Review: series.patch (via Claude) ===
Review date: 2026-11-03

# DPDK Patch Review

## PATCH 1/2: net/tap: fix FD leak on netns change

### Errors

None.

### Warnings

**1. Missing error handling in tap_lsc_register_alarm**
```c
if (tap_lsc_intr_handle_set(dev, 1) < 0)
    TAP_LOG(ERR, "%s: failed to register LSC interrupt", pmd->name);
```
The alarm callback logs failure but does not propagate the error or take corrective action.
If LSC registration fails after a namespace change, the device is left without link state change interrupts.
At minimum, the failure should set a flag or attempt fallback behavior.

**2. Inconsistent error logging severity**
In `tap_netns_change()`, the original code logged LSC registration failure as WARNING:
```c
TAP_LOG(WARNING, "%s: failed to recreate LSC interrupt socket", pmd->name);
```
The new code in `tap_lsc_register_alarm()` logs it as ERR.
Either severity is defensible, but the change should be intentional.

**3. Potential race between alarm and device close**
`tap_lsc_register_alarm()` is scheduled via `rte_eal_alarm_set(1, ...)` and can execute asynchronously.
If the device is closed before the alarm fires, the alarm will dereference freed memory (`dev->data->dev_private`).
The added `rte_eal_alarm_cancel()` in the `clean:` label of `tap_lsc_intr_handle_set()` partially addresses this by canceling pending alarms before unregister.
However, `tap_dev_close()` (added in patch 2/2) calls `tap_intr_handle_set(dev, 0)`, which calls `tap_lsc_intr_handle_set(dev, 0)`, and that will cancel the alarm.
This appears correct but should be verified: the alarm callback must not run after `tap_dev_close()` starts tearing down the device.

### Info

**Resource ownership clarification**
The fix correctly defers LSC teardown and re-registration to an alarm callback, avoiding the fd leak caused by calling `tap_lsc_intr_handle_set(dev, 1)` without first tearing down the old handle.
The namespace switch/restore helpers are a good refactoring.

---

## PATCH 2/2: net/tap: fix use after free on interrupt handle

### Errors

**1. Missing cleanup of LSC interrupt handle**
```c
tap_dev_close(struct rte_eth_dev *dev)
{
    ...
    tap_intr_handle_set(dev, 0);
```
`tap_intr_handle_set(dev, 0)` tears down the *Rx/Tx* interrupt handle (`tap_rx_intr_vec_set(dev, 0)`).
It does **not** tear down the *LSC* interrupt handle, which is managed separately by `tap_lsc_intr_handle_set()`.
The LSC handle (created in `tap_dev_start()` via `tap_lsc_intr_handle_set(dev, 1)`) is never freed, causing:
- The netlink socket fd to leak
- The interrupt callback to remain registered, leading to use-after-free when the callback fires after `pmd` is freed

**Fix:** Add `tap_lsc_intr_handle_set(dev, 0)` to `tap_dev_close()` before `tap_intr_handle_set(dev, 0)`.

**2. Incorrect fd validity check**
```c
if (rte_intr_fd_get(pmd->intr_handle) < 0)
    return 0;
```
This check is performed **after** `rte_eal_alarm_cancel()` in the `clean:` label but **before** the unregister loop.
If `rte_intr_fd_get()` returns `-1`, the function returns 0 without unregistering the callback.
The callback remains registered, holding a reference to `dev`, which will be freed on device close.
When the callback fires later, it will access freed memory.

The fd check should come **before** `rte_eal_alarm_cancel()` or should not short-circuit the unregister loop.
The unregister loop itself handles the case where the callback is not registered (returns `-EAGAIN`).

### Warnings

None.

### Info

The commit message correctly identifies the root cause:
the driver did not unregister interrupt callbacks on close, which became a use-after-free when the interrupt thread stopped duplicating handles.

---

## FINAL CHECK

### Pass 1: Correctness bugs included
- Patch 2/2: Missing LSC interrupt handle cleanup in `tap_dev_close()` (Error)
- Patch 2/2: Early return skips callback unregister when fd is invalid (Error)

### Pass 2: Style/process false positives removed
No style items flagged as errors/warnings.

### Pass 3: Evidence verification
All findings quote specific lines from the patch.

---

Review-Result: ERROR


More information about the test-report mailing list