|WARNING| [2/2] net/bnxt: replace VLA with heap allocation

dpdklab at iol.unh.edu dpdklab at iol.unh.edu
Mon Oct 5 18:32:04 CEST 2026


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

_AI Code Review_

=== Patch Review: series.patch (via Claude) ===
Review date: 2026-10-05

# DPDK Patch Review

## Patch 1/2: net/bnxt: cap memcpy at field size

### Errors

**Buffer overflow via memcpy in ulp_rte_parser_fld_copy (Error)**

The fix attempts to prevent buffer overflow by clamping the size, but **it does not actually prevent the overflow** in the second memcpy at line 75.

```c
if (unlikely(size > RTE_PARSER_FLOW_HDR_FIELD_SIZE)) {
    BNXT_DRV_DBG(ERR, "Field size %u exceeds max of %u, clamping",
                 size, RTE_PARSER_FLOW_HDR_FIELD_SIZE);
    size = RTE_PARSER_FLOW_HDR_FIELD_SIZE;
}
field->size = size;
memcpy(field->spec, buffer, field->size);  // OK - uses clamped size
field++;
memcpy(field->spec, buffer, size);         // BUG - uses original unclamped 'size' parameter
```

At line 75, the code does `memcpy(field->spec, buffer, size)`, but if the original caller-supplied `size` exceeds `RTE_PARSER_FLOW_HDR_FIELD_SIZE`, this `size` variable still holds the unclamped value. The clamping only updates the local variable used in the first memcpy; the parameter value is unchanged, so the second memcpy still overflows.

**Fix:** Update `size` before the second memcpy, or use `field->size` consistently:

```c
if (unlikely(size > RTE_PARSER_FLOW_HDR_FIELD_SIZE)) {
    BNXT_DRV_DBG(ERR, "Field size %u exceeds max of %u, clamping",
                 size, RTE_PARSER_FLOW_HDR_FIELD_SIZE);
    size = RTE_PARSER_FLOW_HDR_FIELD_SIZE;  // This updates the parameter
}
field->size = size;
memcpy(field->spec, buffer, field->size);
field++;
memcpy(field->spec, buffer, field->size);  // Use field->size, not size
```

Or simply ensure `size` is modified before both memcpy calls.

---

**Missing return value check in ulp_rte_parser_fld_copy**

The function has no return type and cannot report the clamping error to the caller. When the size exceeds the maximum, the function logs an error and clamps the copy, but the caller has no way to know that the requested operation was not fully completed. This could lead to silent data truncation bugs where the flow rule is partially programmed.

**Suggested fix:** Change the function to return an error code when clamping occurs:

```c
static int32_t
ulp_rte_parser_fld_copy(struct ulp_rte_hdr_field *field,
                        const void *buffer,
                        uint32_t size)
{
    if (unlikely(size > RTE_PARSER_FLOW_HDR_FIELD_SIZE)) {
        BNXT_DRV_DBG(ERR, "Field size %u exceeds max of %u",
                     size, RTE_PARSER_FLOW_HDR_FIELD_SIZE);
        return -EINVAL;
    }
    field->size = size;
    memcpy(field->spec, buffer, field->size);
    field++;
    memcpy(field->spec, buffer, field->size);
    return 0;
}
```

Then verify all call sites propagate the error.

---

## Patch 2/2: net/bnxt: replace VLA with heap allocation

### Errors

**Resource leak on second error path**

The function allocates `data` with `rte_zmalloc()` at line 409, but the error check at line 401 (before the allocation) returns `-EINVAL` without freeing anything. However, there is a second error check that could be reached after allocation:

Actually, on closer inspection of the code flow, the error checks at lines 399 and 406 both occur **before** the `rte_zmalloc()` call at line 409, so they cannot leak the allocation. The allocation happens after all error checks that lead to early returns, and the only code path after allocation is the loop and the free. **No resource leak exists here.**

(Self-correction: removing this item per guidelines.)

---

### Warnings

**rte_zmalloc used for temporary swap buffer (Warning)**

This is control-path code (flow rule installation), so using standard `malloc()` instead of `rte_zmalloc()` would be more appropriate. `rte_zmalloc()` allocates from hugepage memory, which is a limited resource. The swap buffer is a temporary allocation that does not need to be in hugepages, DMA-accessible, or shared with secondary processes.

**Suggested fix:**

```c
data = malloc(block_sz);
if (unlikely(!data)) {
    BNXT_DRV_DBG(ERR, "Failed to allocate swap buffer");
    return -ENOMEM;
}
// ...
free(data);
```

---

**Zero-initialization unnecessary (Info)**

`rte_zmalloc()` zero-initializes the memory, but the buffer is immediately overwritten by `memcpy()` before being read, so the zeroing is wasted work. If switching to `malloc()` per the previous suggestion, this is already addressed. If keeping `rte_zmalloc()`, use `rte_malloc()` instead (non-zeroing variant).

---

## Summary

**Patch 1/2:** Contains a critical buffer overflow bug where the second memcpy still uses the unclamped size parameter. The function should also return an error code rather than silently clamping.

**Patch 2/2:** Correctly avoids VLA and frees the allocation, but should use `malloc()` instead of `rte_zmalloc()` for this temporary control-path buffer.


More information about the test-report mailing list