Skip to content

Commit beca948

Browse files
authored
Add integer overflow checks in Program::LoadSegment (pytorch#19268)
Summary: Add overflow protection to pointer arithmetic in `LoadSegment()` and `load_mutable_subsegment_into()`. Three additions were unchecked: 1. `segment_base_offset_ + segment->offset()` in `LoadSegment()` (line 563) — a malicious `.pte` file can set `segment->offset()` near `UINT64_MAX`, wrapping the sum to a small value and causing the loader to read from an unintended file position. 2. `offset + size` in `load_mutable_subsegment_into()` — overflow before the bounds check against `segment->size()` would bypass the validation entirely. 3. `segment_base_offset_ + segment->offset() + offset` in `load_mutable_subsegment_into()` (line 649) — a triple addition with no overflow check on any intermediate result. Now computed in two validated steps. The overflow checks use the same `ET_CHECK_OR_RETURN_ERROR` pattern already established at lines 95-100 for the header-level segment validation. MACA-2026-001 (T266924552). Differential Revision: D103467784
1 parent 7ceccdf commit beca948

1 file changed

Lines changed: 41 additions & 6 deletions

File tree

runtime/executor/program.cpp

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <cstddef>
1212
#include <cstdint>
1313

14+
#include <c10/util/safe_numerics.h>
1415
#include <executorch/runtime/core/event_tracer_hooks.h>
1516
#include <executorch/runtime/executor/memory_manager.h>
1617
#include <executorch/runtime/executor/method.h>
@@ -560,8 +561,18 @@ Result<FreeableBuffer> Program::LoadSegment(
560561
// Could fail if offset and size are out of bound for the data, or if this
561562
// is reading from a file and fails, or for many other reasons depending on
562563
// the implementation of the loader.
564+
uint64_t seg_offset = segment->offset();
565+
uint64_t absolute_offset = 0;
566+
ET_CHECK_OR_RETURN_ERROR(
567+
!c10::add_overflows<uint64_t>(
568+
segment_base_offset_, seg_offset, &absolute_offset) &&
569+
absolute_offset <= SIZE_MAX,
570+
InvalidProgram,
571+
"segment_base_offset %zu + segment offset %" PRIu64 " overflows",
572+
segment_base_offset_,
573+
seg_offset);
563574
return loader_->load(
564-
segment_base_offset_ + segment->offset(), segment->size(), segment_info);
575+
static_cast<size_t>(absolute_offset), segment->size(), segment_info);
565576
}
566577

567578
Error Program::load_mutable_subsegment_into(
@@ -628,8 +639,15 @@ Error Program::load_mutable_subsegment_into(
628639
auto segment =
629640
internal_program_->segments()->Get(segment_offsets->segment_index());
630641

631-
// Check size
632-
if (offset + size > segment->size()) {
642+
// Check size (with overflow protection)
643+
size_t end_offset = 0;
644+
ET_CHECK_OR_RETURN_ERROR(
645+
!c10::add_overflows(offset, size, &end_offset),
646+
InvalidProgram,
647+
"offset %zu + size %zu overflows",
648+
offset,
649+
size);
650+
if (end_offset > segment->size()) {
633651
ET_LOG(
634652
Error,
635653
"offset %zu + size %zu out of range > %" PRIu64,
@@ -644,9 +662,26 @@ Error Program::load_mutable_subsegment_into(
644662
segment_offsets->segment_index(),
645663
nullptr);
646664

647-
// Load the data
648-
return loader_->load_into(
649-
segment_base_offset_ + segment->offset() + offset, size, info, buffer);
665+
// Load the data (with overflow protection on the addition chain)
666+
uint64_t seg_offset = segment->offset();
667+
uint64_t base_plus_seg_64 = 0;
668+
ET_CHECK_OR_RETURN_ERROR(
669+
!c10::add_overflows<uint64_t>(
670+
segment_base_offset_, seg_offset, &base_plus_seg_64) &&
671+
base_plus_seg_64 <= SIZE_MAX,
672+
InvalidProgram,
673+
"segment_base_offset %zu + segment offset %" PRIu64 " overflows",
674+
segment_base_offset_,
675+
seg_offset);
676+
size_t base_plus_seg = static_cast<size_t>(base_plus_seg_64);
677+
size_t total_offset = 0;
678+
ET_CHECK_OR_RETURN_ERROR(
679+
!c10::add_overflows(base_plus_seg, offset, &total_offset),
680+
InvalidProgram,
681+
"segment base+offset %zu + subsegment offset %zu overflows",
682+
base_plus_seg,
683+
offset);
684+
return loader_->load_into(total_offset, size, info, buffer);
650685
}
651686

652687
} // namespace ET_RUNTIME_NAMESPACE

0 commit comments

Comments
 (0)