|WARNING| [v2,2/2] net/tap: fix use after free on interrupt handle
dpdklab at iol.unh.edu
dpdklab at iol.unh.edu
Fri Nov 6 10:30:14 CET 2026
Test-Label: ai-code-review
Test-Status: WARNING
https://dpdk.org/patch/172692
_AI Code Review_
=== Patch Review: series.patch (via Claude) ===
Review date: 2026-11-06
# DPDK Patch Review
## PATCH 1/2: net/tap: fix FD leak on netns change
### ERRORS
**Error 1: Resource leak on tap_dev_ns_switch() failure path**
In `tap_netns_change()`, when `tap_dev_ns_switch()` fails after setting `pmd->if_index = 0`, the function returns 0 without restoring the if_index or cleaning up any state. The netlink socket `new_nlsk_fd` is opened after the namespace switch, so on failure it is never opened, but the error path does not communicate this failure condition properly.
Additionally, the early return at line 1857 (`return 0;`) when `tap_dev_ns_switch()` fails means that the driver state is left inconsistent: `pmd->if_index` has been cleared but the namespace switch failed, so the interface is still in the original namespace.
**Suggested fix:**
```c
if (tap_dev_ns_switch(pmd, &orig_netns_fd) < 0) {
/* Failed to switch namespace, restore if_index */
pmd->if_index = if_nametoindex(pmd->name);
return -1; /* Signal failure instead of returning 0 */
}
```
**Error 2: Potential use-after-free in tap_lsc_register_alarm()**
The alarm callback `tap_lsc_register_alarm()` is scheduled with `dev` as the argument, but there is no guarantee that `dev` remains valid when the alarm fires. If the device is closed between scheduling the alarm and the alarm firing, the callback will access freed memory.
The alarm is cancelled in `tap_lsc_intr_handle_set()` during teardown, but the race window exists between `tap_netns_change()` scheduling the alarm and `tap_dev_close()` being called.
**Suggested fix:**
Ensure `tap_dev_close()` cancels any pending alarms before proceeding with teardown:
```c
int
tap_dev_close(struct rte_eth_dev *dev)
{
/* ... existing code ... */
rte_eal_alarm_cancel(tap_lsc_register_alarm, dev);
tap_intr_handle_set(dev, 0);
/* ... rest of close ... */
}
```
### WARNINGS
**Warning 1: Missing error check on rte_eal_alarm_set()**
Line 1891: The return value of `rte_eal_alarm_set()` is checked and logged on failure, but execution continues. If alarm scheduling fails, the LSC interrupt will never be re-registered, leaving the device without link state change notifications. This should be treated more seriously.
**Suggested fix:**
Consider falling back to immediate re-registration if alarm scheduling fails:
```c
if (rte_eal_alarm_set(1, tap_lsc_register_alarm, dev) < 0) {
TAP_LOG(WARNING, "%s: failed to schedule LSC re-registration, "
"attempting immediate re-registration", pmd->name);
tap_lsc_register_alarm(dev);
}
```
**Warning 2: Double alarm cancellation in tap_lsc_intr_handle_set()**
Lines 1970 and 1988: `rte_eal_alarm_cancel(tap_lsc_register_alarm, dev)` is called twice in the same function. The second call (line 1988) is redundant because:
1. The first call (line 1970) already cancels any pending alarms
2. The code between them does not schedule new alarms
3. The second call happens after the callback has been unregistered and the fd closed
The second cancellation is harmless but unnecessary.
**Suggested fix:**
Remove the redundant second `rte_eal_alarm_cancel()` call at line 1988.
**Warning 3: Incomplete error handling in tap_dev_ns_switch()**
The function `tap_dev_ns_switch()` returns -1 on multiple error paths but does not consistently clean up all resources. Specifically:
- Line 1810: If `open("/proc/self/ns/net")` fails, `netns_fd` is closed but the error is logged and function returns -1
- Line 1828: If `setns(netns_fd)` fails, both `netns_fd` and `*orig_netns_fd` are closed
This is actually correct behavior, but the asymmetry could be confusing to future maintainers.
**Suggested fix:**
Add a comment explaining the cleanup strategy:
```c
/* On failure, clean up all opened fds before returning */
if (setns(netns_fd, CLONE_NEWNET) < 0) {
TAP_LOG(ERR, "%s: failed to enter new netns: %s",
pmd->name, strerror(errno));
close(netns_fd);
close(*orig_netns_fd); /* Cleanup fd opened earlier */
return -1;
}
```
---
## PATCH 2/2: net/tap: fix use after free on interrupt handle
### Clean
This patch correctly adds the missing `tap_intr_handle_set(dev, 0)` call during `tap_dev_close()` to unregister interrupt callbacks before the device is freed. The placement before the persist check and link down operation is appropriate.
The fix addresses the use-after-free issue introduced by commit c663018eb7f3 where interrupt handles are no longer duplicated.
---
## SUMMARY
Patch 1/2 introduces correctness bugs that must be fixed:
- Resource leak and inconsistent state on namespace switch failure
- Potential use-after-free race with alarm callback and device close
Patch 2/2 is correct as written.
Review-Result: ERROR
More information about the test-report
mailing list