Skip to content

Fix out-of-bounds read in ConvTransposeWithDynamicPads - #32679

Merged
Akshay Sonawane (apsonawane) merged 3 commits into
microsoft:mainfrom
bbernhar:fix_134
Sep 22, 2026
Merged

Akshay Sonawane (apsonawane) merged 3 commits into
microsoft:mainfrom
bbernhar:fix_134

Conversation

@bbernhar

@bbernhar Bryan B (bbernhar) commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

Description

Add an explicit rank-consistency check in convTransposeWithDynamicPadsShapeInference() so that a derived kernel_shape (built from the weight tensor's rank when the kernel_shape attribute is absent) must have the same length as n_input_dims (derived from the input tensor's rank) before it is used, exactly like the existing check on the explicit-attribute path.

Motivation and Context

n_input_dims is computed from input X's rank. When kernel_shape is not given as an attribute, it is instead derived from weight W's rank. If W's rank disagrees with X's rank, the resulting kernel_shape (and effective_kernel_shape, sized identically) is shorter or longer than n_input_dims. Both directions are unsafe:

  • Shorter (e.g. X rank 5, W rank 3): the output-shape loop iterates n_input_dims times over effective_kernel_shape/pads, reading past the end of the shorter vector.
  • Longer (e.g. X rank 3, W rank 5): the dilation loop iterates kernel_shape.size() times over dilations, which is always sized to n_input_dims, reading past the end of dilations.

This runs during Graph::Resolve() (model load), before any kernel Compute() validation is ever reached.

Testing

Added ConvTransposeWithDynamicPads_MismatchedInputWeightRank (X rank 5, W rank 3, no kernel_shape attribute), asserting the model now fails cleanly at the existing kernel-level rank check ("X num_dims does not match W num_dims.") instead of hitting the shape-inference OOB read during load.

When 'kernel_shape' is not provided as an attribute, it is derived from
the weight (W) tensor's rank but indexed using n_input_dims, which is
derived from the input (X) tensor's rank. A W rank greater than X rank
overruns `dilations` in the dilation-scaling loop; a W rank less than
X rank leaves `effective_kernel_shape` too short for the output-shape
loop. Both occur in convTransposeWithDynamicPadsShapeInference() during
Graph::Resolve(), before the model ever runs.

Guard the derived kernel_shape against n_input_dims before it is used,
matching the check already applied when 'kernel_shape' is supplied as
an explicit attribute.
Copilot AI balanced review requested due to automatic review settings September 17, 2026 16:26
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The regression test misses the vulnerable inference path and may fail on DML builds.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Prevents out-of-bounds reads during dynamic ConvTranspose shape inference when input and weight ranks differ.

Changes:

  • Adds derived kernel-rank validation.
  • Adds a mismatched-rank regression test.
File summaries
File Description
onnxruntime/core/graph/contrib_ops/contrib_defs.cc Guards vector indexing against rank mismatch.
onnxruntime/test/contrib_ops/conv_transpose_with_dynamic_pads_test.cc Adds malformed-rank coverage.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 2
  • Review effort level: Balanced (auto)

Note

Copilot is running an experiment and ran this review at Balanced.


💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The guard prevents both unsafe indexing paths and the regression tests cover each rank mismatch direction.

Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced (auto)

Note

Copilot is running an experiment and ran this review at Balanced.

@bbernhar

Copy link
Copy Markdown
Contributor Author

Akshay Sonawane (@apsonawane) merged main to address unrelated build failure

@apsonawane
Akshay Sonawane (apsonawane) merged commit 2ecddca into microsoft:main Sep 22, 2026
95 of 96 checks passed
Tianlei Wu (tianleiwu) added a commit that referenced this pull request Sep 29, 2026
This cherry-picks the following commits for the release:

* #32610
* #32633
* #32641
* #32611
* #32609
* #32607
* #32679
* #32681
* #32666

CI fixes:

* #32491 (installs `uuid-dev` for the Linux minimal-build CoreML job;
that check also fails on the `rel-1.28.3` base)
* Raise the Android minimal baseline binary-size threshold from
1,440,768 to 1,443,840 bytes (release branch only). The checks added by
these fixes grow the minimal build from 1,440,538 to 1,443,098 bytes
(+2,560).

All picks except #32607 applied cleanly with `git cherry-pick -x`, in
the order they merged into main (#32666 was added afterward).

#32607 required a manual backport because `bert_defs.cc` has diverged on
main since 1.28 branched:
- `GroupQueryAttention` / `SparseAttention`: backported as-is
(`total_sequence_length_index` of 6 / 7, plus the single-element check).
The GQA call site in 1.28 has no `sliding_window_cache`, so it only gets
the new argument.
- `CausalConvWithState`: the 1.28 schema predates `channels_last`,
`state_window`, and `dilation`. Only the `ndim` in [1, 3] check and the
`weight`/`input` rank == `ndim + 2` checks are backported. These match
what the 1.28 CPU kernel already enforces.
`ChannelsLastInputRankBelowThreeIsRejected` is dropped.
- `GatedDeltaNet`: this op does not exist on 1.28.3, so its hunk and
test are dropped.

Validation (Windows x64, CPU EP, RelWithDebInfo):
- All 14 regression tests added by these PRs pass.
- `onnxruntime_test_all`: 1848 tests (including #32666's
`PluginCopiesForwardStreams`), 0 failures.
- `onnxruntime_provider_test`: 5370 tests, 0 failures.

---------

Co-authored-by: Wei Wang <wei4.wang@intel.com>
Co-authored-by: shiyi <shiyi.zou@intel.com>
Co-authored-by: Bin Miao <bin.miao@intel.com>
Co-authored-by: Bryan B <bryan.bernhart@intel.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: tianleiwu <30328909+tianleiwu@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Xiaofei Han <xiaofeihan@microsoft.com>
This was referenced Nov 2, 2026
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.

3 participants