|WARNING| net/bnxt: fix potential OOB string writes in debug helpers

dpdklab at iol.unh.edu dpdklab at iol.unh.edu
Tue Oct 6 14:46:51 CEST 2026


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

_AI Code Review_

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

# DPDK Patch Review

## Summary
This patch adds bounds-checked string concatenation to debug dump helpers in the bnxt PMD to prevent out-of-bounds writes when building formatted output strings. The core fix is the addition of `tfc_str_append()` and its use throughout the debug code.

---

## Errors

### 1. Missing `__rte_internal` tag on exported function (Error)

**Issue:** `tfc_str_append()` is declared in `tfc_debug.h` (an installed header based on context) without the `__rte_internal` tag.

**Why it matters:** This function is internal to the driver and should not be part of the public API. Without `__rte_internal`, it becomes a public symbol that applications could attempt to use.

**Fix:** Add `__rte_internal` tag in the header:

```c
/* In tfc_debug.h */
__rte_internal
size_t tfc_str_append(char *buf, size_t size, const char *fmt, ...);
```

And add the corresponding `RTE_EXPORT_INTERNAL_SYMBOL` macro in the `.c` file on the line immediately before the function definition:

```c
/* In tfc_mpc_debug.c */
RTE_EXPORT_INTERNAL_SYMBOL(tfc_str_append)
size_t tfc_str_append(char *buf, size_t size, const char *fmt, ...)
{
    /* ... */
}
```

---

### 2. vsnprintf return value handling unsafe for signed overflow (Error)

**Issue:** In `tfc_str_append()`, `vsnprintf()` returns `int` which can be negative on encoding error. The code checks `n < 0` and returns 0, but then casts `n` directly to `size_t` at the end without verifying it's within `[0, INT_MAX]` range.

**Why it matters:** If `vsnprintf()` returns a very large positive value indicating the *would-be* output size (not the actual bytes written), the `(size_t)n >= size` check is correct, but the final `return (size_t)n;` could return a misleadingly large value. This is unlikely in practice since we already checked truncation, but the logic should be clearer.

**Current code:**
```c
int n;
/* ... */
n = vsnprintf(buf, size, fmt, ap);
/* ... */
if (n < 0)
    return 0;
if ((size_t)n >= size) {
    /* truncate marker */
    return size - 1;
}
return (size_t)n;  /* n is known to be in [0, size-1] here - actually OK */
```

**Analysis:** On second review, this is actually correct. After the checks, `n` is guaranteed to be in `[0, size-1]`, so the cast is safe. The `n < 0` check handles encoding errors, and the `n >= size` check handles truncation. The final return only executes when `0 <= n < size`, making the cast safe.

**Verdict:** No issue here after all. (This item is being removed per guidelines - if analysis concludes correctness, do not include it.)

---

### 3. Potential truncation of append operations undetected by callers (Warning)

**Issue:** `tfc_str_append()` returns the number of bytes appended, clamped to `size - 1` on truncation. Callers accumulate this into offset variables (`off1 += tfc_str_append(...)`), but never check whether truncation occurred.

**Why it matters:** Once truncation happens, subsequent appends continue writing to the same tail position (because `off1` stops advancing), silently overwriting the `<truncated>` marker. This defeats the purpose of the marker and produces confusing output.

**Example scenario:**
```c
off1 = tfc_str_append(line1, 256, "+-+--+-Epoch-+--+--+--+");  /* 23 bytes, off1 = 23 */
off1 += tfc_str_append(line1 + off1, 256 - off1, "...long string...");  /* Suppose this fills the buffer */
/* off1 is now 255 */
off1 += tfc_str_append(line1 + off1, 256 - off1, "more data");
/* This writes to line1[255], size 1, immediately truncates, overwrites marker */
```

**Fix:** After any append, check if we hit the buffer limit and stop appending:

```c
off1 = tfc_str_append(line1, TFC_STRING_LENGTH_256, "+-+--+-Epoch-+--+--+--+");
if (off1 >= TFC_STRING_LENGTH_256 - 1)
    goto truncated;
off1 += tfc_str_append(line1 + off1, TFC_STRING_LENGTH_256 - off1, "%s", tmp1);
if (off1 >= TFC_STRING_LENGTH_256 - 1)
    goto truncated;
/* ... */
truncated:
    /* Stop appending, output what we have */
```

Or more simply, don't append after truncation is detected. The current code doesn't check this.

**Severity:** Warning (code works for typical debug output sizes, but could produce confusing output if a field is unexpectedly large).

---

## Warnings

### 4. Inconsistent offset tracking initialization (Warning)

**Issue:** In `prof_tcam_show()` and `wc_tcam_show()`, offset variables are declared without initialization at the top of the function, then assigned via the first `tfc_str_append()` call. In `em_show()` and the decode functions, a `size_t off` variable is declared and assigned in one statement.

**Why it matters:** Consistency in variable initialization style within a file improves readability.

**Suggested fix:** Initialize offset variables to 0 at declaration for consistency:

```c
size_t offh = 0, off1 = 0, off2 = 0, off3 = 0, off4 = 0, off5 = 0;
```

This matches the pattern used elsewhere and makes it clear that subsequent assignments are accumulative.

---

### 5. Missing release notes update (Warning)

**Issue:** This patch fixes a potential out-of-bounds write (a security-relevant bug), but there is no mention of a corresponding release notes update in the commit message.

**Why it matters:** Significant bug fixes, especially those with security implications, should be documented in the release notes so users know which version contains the fix.

**Suggested action:** Add a release notes entry in the current release notes file under the "Fixed Issues" section for the bnxt PMD, describing the fix for potential buffer overflows in debug helpers.

---

## Informational

### 6. Consider using RTE_MIN for clamping logic (Info)

The clamping logic in `tfc_str_append()` is correct but could be slightly more idiomatic:

```c
if ((size_t)n >= size) {
    if (size > marklen)
        snprintf(buf + (size - 1 - marklen), marklen + 1, "%s", mark);
    return size - 1;
}
```

Could be written as:

```c
if ((size_t)n >= size) {
    size_t mark_offset = (size > marklen) ? (size - 1 - marklen) : 0;
    if (size > marklen)
        snprintf(buf + mark_offset, marklen + 1, "%s", mark);
    return size - 1;
}
```

But the current form is clear enough. This is a style preference, not a requirement.

---

### 7. Function comment formatting (Info)

The block comment for `tfc_str_append()` uses a non-standard format:

```c
/* Helper function to append a formatted string to a buffer of a given size.
 * Returns the number of chars appended (excluding the NUL terminator).
 * If size is exceeded, a "<truncated>" marker is appended at the tail
 * of the buffer.
 */
```

DPDK prefers the opening `/*` on its own line for multi-line comments:

```c
/*
 * Helper function to append a formatted string to a buffer of a given size.
 * Returns the number of chars appended (excluding the NUL terminator).
 * If size is exceeded, a "<truncated>" marker is appended at the tail
 * of the buffer.
 */
```

---

## Conclusion

The patch correctly addresses the out-of-bounds write vulnerability in the debug helpers by introducing bounds-checked string appends. The core fix is sound.

**Required changes:**
1. Add `__rte_internal` tag and export macro for `tfc_str_append()`
2. Document fix in release notes

**Recommended changes:**
3. Add truncation detection to stop appending after buffer is full (or document that subsequent appends will overwrite the marker)
4. Initialize offset variables consistently at declaration

**Style suggestions:**
5. Multi-line comment formatting for `tfc_str_append()`


More information about the test-report mailing list