Skip to content

BUG: Buffer overflow in npy__cpu_validate_baseline when CPU lacks baseline features #30477

@stratakis

Description

@stratakis

Describe the issue:

Our downstream Coverity scanner identified a stack buffer overflow in npy__cpu_validate_baseline() in npy_cpu_features.c. The buffer is undersized because the copying logic uses more bytes per feature than the original string.

Coverity snippet:

Defect type: OVERRUN

  1. numpy-2.3.4/numpy/_core/src/common/npy_cpu_features.c:221:5: alias: Assigning: "fptr" = "&baseline_failure[0]". "fptr" now points to byte 0 of "baseline_failure" (which consists of 59 bytes).
  2. numpy-2.3.4/numpy/_core/src/common/npy_cpu_features.c:229:5: ptr_incr: Incrementing "fptr" by 5. "fptr" now points to byte 5 of "baseline_failure" (which consists of 59 bytes).
  3. numpy-2.3.4/numpy/_core/src/common/npy_cpu_features.c:229:5: ptr_incr: Incrementing "fptr" by 6. "fptr" now points to byte 11 of "baseline_failure" (which consists of 59 bytes).
  4. numpy-2.3.4/numpy/_core/src/common/npy_cpu_features.c:229:5: ptr_incr: Incrementing "fptr" by 6. "fptr" now points to byte 17 of "baseline_failure" (which consists of 59 bytes).
  5. numpy-2.3.4/numpy/_core/src/common/npy_cpu_features.c:229:5: ptr_incr: Incrementing "fptr" by 7. "fptr" now points to byte 24 of "baseline_failure" (which consists of 59 bytes).
  6. numpy-2.3.4/numpy/_core/src/common/npy_cpu_features.c:229:5: ptr_incr: Incrementing "fptr" by 7. "fptr" now points to byte 31 of "baseline_failure" (which consists of 59 bytes).
  7. numpy-2.3.4/numpy/_core/src/common/npy_cpu_features.c:229:5: ptr_incr: Incrementing "fptr" by 8. "fptr" now points to byte 39 of "baseline_failure" (which consists of 59 bytes).
  8. numpy-2.3.4/numpy/_core/src/common/npy_cpu_features.c:229:5: ptr_incr: Incrementing "fptr" by 7. "fptr" now points to byte 46 of "baseline_failure" (which consists of 59 bytes).
  9. numpy-2.3.4/numpy/_core/src/common/npy_cpu_features.c:229:5: ptr_incr: Incrementing "fptr" by 5. "fptr" now points to byte 51 of "baseline_failure" (which consists of 59 bytes).
  10. numpy-2.3.4/numpy/_core/src/common/npy_cpu_features.c:229:5: ptr_incr: Incrementing "fptr" by 6. "fptr" now points to byte 57 of "baseline_failure" (which consists of 59 bytes).
  11. numpy-2.3.4/numpy/_core/src/common/npy_cpu_features.c:229:5: overrun-buffer-arg: Overrunning buffer pointed to by "fptr" of 59 bytes by passing it to a function which accesses it at byte offset 61 using argument "5UL". [Note: The source code implementation of the function has been overridden by a builtin model.]
    227| fptr[size] = ' '; fptr += size + 1;
    228| }
    229|-> NPY_WITH_CPU_BASELINE_CALL(NPY__CPU_VALIDATE_CB, DUMMY) // extra arg for msvc
    230| *fptr = '\0';
    231|

This is practically quite hard to trigger. It happens when the CPU misses multiple the baseline features, such as on an old CPU or some restricted VM environment.

The npy__cpu_validate_baseline() function will build an error message listing CPU features that the machine doesn't support. It allocates a buffer based on the size of the original feature string.

For example, sizeof("SSE") is 4 (with the null terminator), so the code writes 5 bytes ("SSE\0 "). But in the original baseline string, "SSE " only occupies 4 bytes.

This means each missing feature uses 1 extra byte compared to the buffer allocation. When enough features are missing, the buffer overflows. A solution here would be to not copy the NULL terminator.

Reproduce the code example:

See description

Error message:

Python and NumPy Versions:

Python 3.14, numpy 2.3.4

Runtime Environment:

No response

Context for the issue:

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions