Skip to content

Commit cedfe4c

Browse files
authored
Fix heap-buffer-overflow in constant_pad_nd (pytorch#18018)
Summary: Fix write-heap-buffer-overflow in set_all_to_value triggered via apply_padding_to_dim, reported by fuzzer (T258811544). Root causes: 1. Negative padding values silently cast to huge size_t, causing massive out-of-bounds writes. 2. When out_data advances past out_data_end, the remaining computation (out_data_end - out_data) wraps around to a huge size_t, causing bounds checks to incorrectly pass. 3. No error propagation after recursive apply_padding_to_dim calls, allowing the loop to continue writing after a child call has failed. Fixes: - Validate all padding values are non-negative in check_constant_pad_args. - Read padding as int64_t and explicitly check >= 0 before casting to size_t. - Guard remaining computation with out_data <= out_data_end check at all three bounds-check sites to prevent size_t wraparound. - Check ctx.failure_state() after recursive calls and bail out early. - Remove dead pad_i >= 0 check (always true for size_t). Differential Revision: D95762335
1 parent bad1aec commit cedfe4c

2 files changed

Lines changed: 41 additions & 4 deletions

File tree

kernels/portable/cpu/op_constant_pad_nd.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,17 @@ void apply_padding_to_dim(
5151

5252
size_t pad_before = 0;
5353
size_t pad_after = 0;
54-
if (pad_i >= 0 && pad_i < pad.size() / 2) {
55-
pad_before = pad[2 * pad_i];
56-
pad_after = pad[2 * pad_i + 1];
54+
if (pad_i < pad.size() / 2) {
55+
int64_t pb = pad[2 * pad_i];
56+
int64_t pa = pad[2 * pad_i + 1];
57+
ET_KERNEL_CHECK_MSG(
58+
ctx,
59+
pb >= 0 && pa >= 0,
60+
InvalidArgument,
61+
/* void */,
62+
"Padding values must be non-negative.");
63+
pad_before = static_cast<size_t>(pb);
64+
pad_after = static_cast<size_t>(pa);
5765
}
5866

5967
size_t out_step_len = out_strides[dim];
@@ -62,6 +70,12 @@ void apply_padding_to_dim(
6270
// Do not copy padding beyond the out tensor bounds.
6371
// Use division to avoid potential overflow in multiplication.
6472
if (pad_before > 0) {
73+
ET_KERNEL_CHECK_MSG(
74+
ctx,
75+
out_data <= out_data_end,
76+
InvalidArgument,
77+
/* void */,
78+
"Out data pointer exceeds buffer bounds.");
6579
size_t remaining = out_data_end - out_data;
6680
ET_KERNEL_CHECK_MSG(
6781
ctx,
@@ -92,7 +106,12 @@ void apply_padding_to_dim(
92106
/* void */,
93107
"Out tensor overlaps with the input tensor. This is not supported.");
94108
// Bounds check before memcpy
95-
// Use overflow-safe check for remaining >= copy_len
109+
ET_KERNEL_CHECK_MSG(
110+
ctx,
111+
out_data <= out_data_end,
112+
InvalidArgument,
113+
/* void */,
114+
"Out data pointer exceeds buffer bounds.");
96115
size_t remaining = out_data_end - out_data;
97116
ET_KERNEL_CHECK_MSG(
98117
ctx,
@@ -123,6 +142,10 @@ void apply_padding_to_dim(
123142
last_padded_dim,
124143
dim + 1);
125144

145+
if (ctx.failure_state() != Error::Ok) {
146+
return;
147+
}
148+
126149
out_data += out_step_len;
127150
self_data += in_step_len;
128151
}
@@ -131,6 +154,12 @@ void apply_padding_to_dim(
131154
// Do not copy padding beyond the out tensor bounds.
132155
// Use division to avoid potential overflow in multiplication.
133156
if (pad_after > 0) {
157+
ET_KERNEL_CHECK_MSG(
158+
ctx,
159+
out_data <= out_data_end,
160+
InvalidArgument,
161+
/* void */,
162+
"Out data pointer exceeds buffer bounds.");
134163
size_t remaining = out_data_end - out_data;
135164
ET_KERNEL_CHECK_MSG(
136165
ctx,

kernels/portable/cpu/util/kernel_ops_util.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,14 @@ bool check_constant_pad_args(
564564
pad.size() / 2,
565565
in.dim());
566566

567+
for (size_t i = 0; i < pad.size(); ++i) {
568+
ET_CHECK_OR_RETURN_FALSE(
569+
pad[i] >= 0,
570+
"Padding values must be non-negative, but got pad[%zu] = %" PRId64,
571+
i,
572+
pad[i]);
573+
}
574+
567575
return true;
568576
}
569577

0 commit comments

Comments
 (0)