Add validation of position_ids in RotaryEmbedding operators
Merged
TI
6mo ago+427+427+012345678901234567890123456789-23-23-01234567890123456789
Description
Fix out-of-bounds read in the RotaryEmbedding operator when user-provided position_ids values exceed the cos/sin cache bounds (max_sequence_length).
Problem
When position_ids contains values that are negative or >= max_sequence_length, the kernel computes cache_offset = position_id * half_rotary_embedding_dim and reads out-of-bounds from cos_cache / sin_cache. This can cause undefined behavior (incorrect results, crashes, or memory corruption).
Fix
CPU (rotary_embedding.cc):
- Added upfront validation of all
position_idsvalues before the parallel computation loop. Returns anINVALID_ARGUMENTerror if any value is out of range[0, max_sequence_length). - Validation is only applied when
position_ids_format != 0(i.e., when position_ids are explicitly provided). Whenposition_idsis not provided (format 0), the cache is shaped(B, S, H/2)and the indexb * S + sis always in-bounds by construction.
CUDA (rotary_embedding_impl.cu):
- Plumbed the previously-unused
max_sequence_lengthparameter through to the kernel. - Added a bounds check inside the
position_ids_format != 0branch. Out-of-bounds position IDs cause the kernel to pass through the input unchanged (errors cannot be propagated from GPU kernels). - The bounds check is scoped to the
position_ids_format != 0branch only. When format is 0 (no position_ids), the cache is(B*S, H/2)andb_s_index = b * S + sis deterministically valid — applying the check unconditionally would incorrectly reject all batches beyond the first sincemax_sequence_length == sequence_lengthin that case.
Tests
Added three CPU test cases for the ONNX domain RotaryEmbedding op:
RotaryEmbedding_PositionIds_ExceedsMaxSeqLen— position_id far exceeding cache sizeRotaryEmbedding_PositionIds_Negative— negative position_idRotaryEmbedding_PositionIds_OOB_InBatch— OOB position_id in a multi-batch, multi-sequence scenario
Motivation and Context
Security hardening — prevent out-of-bounds memory access from untrusted model inputs.