Skip to content

Fix LinearRegressor heap-buffer-overflow from undersized coefficients#27964

Open
bmehta001 wants to merge 2 commits into
mainfrom
fix/linearregressor-heap-oob-read
Open

Fix LinearRegressor heap-buffer-overflow from undersized coefficients#27964
bmehta001 wants to merge 2 commits into
mainfrom
fix/linearregressor-heap-oob-read

Conversation

@bmehta001
Copy link
Copy Markdown
Contributor

@bmehta001 bmehta001 commented Apr 3, 2026

Description

Fix a heap-buffer-overflow (out-of-bounds read) in LinearRegressor triggered when the coefficients attribute is smaller than num_targets * num_features.

Root Cause

LinearRegressor treats the coefficients attribute as a [num_targets, num_features] matrix and passes it directly to MLAS SGEMM via Gemm<T>::ComputeGemm. However, num_features is derived from the input tensor shape at runtime, and there was no validation that coefficients.size() == num_targets * num_features. A malformed model could provide fewer coefficients than expected, causing MlasSgemmTransposePackB to read past the buffer boundary.

Fix

Added a size check in Compute() after num_features is derived but before the GEMM dispatch:

  • Uses SafeInt for overflow-safe multiplication
  • Also validates num_targets is non-negative
  • Returns INVALID_ARGUMENT status with a clear error message on mismatch

Testing

  • CoefficientsSizeMismatch: verifies undersized coefficients are rejected with a clear error

Motivation and Context

Security fix — prevents out-of-bounds heap reads when processing untrusted ONNX models with malformed LinearRegressor attributes on the CPUExecutionProvider.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens several operators against invalid shapes/attributes that could lead to out-of-bounds reads (notably LinearRegressor), and adds additional runtime validation in CPU/CUDA/WebGPU and JS implementations.

Changes:

  • Add runtime validation for LinearRegressor that coefficients matches targets * num_features, plus a regression test for the mismatch case.
  • Add additional validation in Slice/Pad (negative output dims, axis range) and Split (non-negative split sizes) across multiple execution providers/backends.
  • Fix JS normalizeAxis() logic and add extra shape validation in JS pad/slice utilities.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
onnxruntime/core/providers/cpu/ml/linearregressor.cc Reject mismatched coefficients size to prevent GEMM backend OOB reads.
onnxruntime/test/providers/cpu/ml/linearregressor_test.cc Add regression test covering invalid coefficients size.
onnxruntime/core/providers/webgpu/tensor/slice.cc Add axis range checking and output-dimension validation in WebGPU Slice.
onnxruntime/core/providers/webgpu/tensor/pad.cc Add output-dimension negative check in WebGPU Pad.
onnxruntime/core/providers/cuda/tensor/split.cc Reject negative values in runtime split input.
onnxruntime/core/providers/cuda/tensor/pad.cc Add output-dimension negative check in CUDA Pad.
onnxruntime/core/providers/cpu/tensor/split.h Reject negative values in runtime split input (CPU).
onnxruntime/core/providers/cpu/tensor/pad.cc Add output-dimension negative checks in CPU Pad (reshaped + final dims).
js/web/lib/wasm/jsep/webgpu/ops/slice.ts Add JS WebGPU slice output-dimension validation.
js/web/lib/wasm/jsep/util.ts Fix axis normalization condition; add negative-dimension check in pad shape.
js/web/lib/onnxjs/util.ts Fix axis normalization condition; add negative-dimension check in pad shape.
js/web/lib/onnxjs/backends/webgl/ops/slice.ts Add JS WebGL slice output-dimension validation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread js/web/lib/wasm/jsep/webgpu/ops/slice.ts Outdated
Comment thread js/web/lib/onnxjs/backends/webgl/ops/slice.ts Outdated
Comment thread onnxruntime/core/providers/cpu/ml/linearregressor.cc
Comment thread onnxruntime/core/providers/cpu/tensor/split.h Outdated
Comment thread onnxruntime/core/providers/webgpu/tensor/slice.cc Outdated
Comment thread onnxruntime/core/providers/webgpu/tensor/slice.cc Outdated
Comment thread onnxruntime/core/providers/cpu/tensor/pad.cc Outdated
Comment thread onnxruntime/core/providers/cuda/tensor/pad.cc Outdated
Comment thread onnxruntime/core/providers/webgpu/tensor/pad.cc Outdated
@bmehta001 bmehta001 force-pushed the fix/linearregressor-heap-oob-read branch from ac9a4f8 to 913cbb9 Compare April 4, 2026 05:54
LinearRegressor treats the coefficients attribute as a [num_targets,
num_features] matrix and passes it directly to MLAS SGEMM. However,
num_features is derived from the input tensor at runtime, and no
validation ensured coefficients.size() == num_targets * num_features.
A malformed model could provide fewer coefficients than expected,
causing MlasSgemmTransposePackB to read past the buffer boundary.

Add a size check after num_features is computed but before the GEMM
dispatch to reject mismatched coefficients with a clear error message.

Files changed:
- onnxruntime/core/providers/cpu/ml/linearregressor.cc
- onnxruntime/test/providers/cpu/ml/linearregressor_test.cc

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@bmehta001 bmehta001 force-pushed the fix/linearregressor-heap-oob-read branch from 913cbb9 to 6191529 Compare April 4, 2026 06:45
@bmehta001 bmehta001 self-assigned this Apr 4, 2026
@bmehta001 bmehta001 changed the title Fix linearregressor heap oob read Fix LinearRegressor heap-buffer-overflow from undersized coefficients Apr 4, 2026
@bmehta001 bmehta001 requested a review from Copilot April 5, 2026 17:42
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread onnxruntime/core/providers/cpu/ml/linearregressor.cc Outdated
@bmehta001 bmehta001 force-pushed the fix/linearregressor-heap-oob-read branch from 6191529 to 33b8291 Compare April 5, 2026 18:34
@bmehta001 bmehta001 requested a review from Copilot April 6, 2026 05:52
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +97 to +106
size_t expected_coefficients_size = 0;
ORT_TRY {
expected_coefficients_size = SafeInt<size_t>(num_targets_) * static_cast<size_t>(num_features);
}
ORT_CATCH(...) {
return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT,
"LinearRegressor: coefficients attribute size (", coefficients_.size(),
") does not match targets (", num_targets_,
") * input features (", num_features, ")");
}
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In ORT_NO_EXCEPTIONS builds, ORT_TRY/ORT_CATCH are compiled to if(true)/else if(false), and SafeInt overflow calls ORT_THROW which aborts. That means the overflow path here will terminate the process instead of returning INVALID_ARGUMENT, which is undesirable for malformed/untrusted models. Consider using a non-throwing overflow check (e.g., IAllocator::CalcMemSizeForArray(static_cast<size_t>(num_targets_), static_cast<size_t>(num_features), &expected_coefficients_size) with size=1) or an explicit num_targets_ > 0 && num_features <= max/num_targets_ style check to keep behavior consistent across exception/no-exception builds.

Copilot uses AI. Check for mistakes.
Address review feedback: ORT_TRY/ORT_CATCH is a no-op in
ORT_NO_EXCEPTIONS builds, so SafeInt overflow would abort the process.
Replace with an explicit non-throwing overflow check using
std::numeric_limits that works consistently across all build configs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@bmehta001 bmehta001 force-pushed the fix/linearregressor-heap-oob-read branch from 33b8291 to 494c070 Compare April 6, 2026 16:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants