|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