Skip to content

Commit dfa74ec

Browse files
committed
[C++][IPC] Validate sparse tensor index sizes to prevent OOB access
1 parent a3d630f commit dfa74ec

2 files changed

Lines changed: 23 additions & 3 deletions

File tree

cpp/src/arrow/ipc/metadata_internal.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1523,6 +1523,10 @@ Status GetSparseCSFIndexMetadata(const flatbuf::SparseTensorIndexCSF* sparse_ind
15231523
RETURN_NOT_OK(IntFromFlatbuffer(sparse_index->indicesType(), indices_type));
15241524

15251525
const int ndim = static_cast<int>(sparse_index->axisOrder()->size());
1526+
if (static_cast<int>(sparse_index->indicesBuffers()->size()) != ndim ||
1527+
static_cast<int>(sparse_index->indptrBuffers()->size()) != ndim - 1) {
1528+
return Status::Invalid("Inconsistent CSF index buffer counts");
1529+
}
15261530
for (int i = 0; i < ndim; ++i) {
15271531
axis_order->push_back(sparse_index->axisOrder()->Get(i));
15281532
indices_size->push_back(sparse_index->indicesBuffers()->Get(i)->length());
@@ -1550,6 +1554,9 @@ Status GetSparseTensorMetadata(const Buffer& metadata, std::shared_ptr<DataType>
15501554
auto dim = sparse_tensor->shape()->Get(i);
15511555

15521556
if (shape) {
1557+
if (dim->size() < 0) {
1558+
return Status::Invalid("Invalid sparse tensor dimension size: ", dim->size());
1559+
}
15531560
shape->push_back(dim->size());
15541561
}
15551562

@@ -1560,6 +1567,10 @@ Status GetSparseTensorMetadata(const Buffer& metadata, std::shared_ptr<DataType>
15601567
}
15611568

15621569
if (non_zero_length) {
1570+
if (sparse_tensor->non_zero_length() < 0) {
1571+
return Status::Invalid("Invalid sparse tensor non-zero length: ",
1572+
sparse_tensor->non_zero_length());
1573+
}
15631574
*non_zero_length = sparse_tensor->non_zero_length();
15641575
}
15651576

cpp/src/arrow/ipc/reader.cc

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2332,9 +2332,6 @@ Result<std::shared_ptr<SparseIndex>> ReadSparseCSXIndex(
23322332
if (shape.size() != 2) {
23332333
return Status::Invalid("Invalid shape length for a sparse matrix");
23342334
}
2335-
if (non_zero_length < 0) {
2336-
return Status::Invalid("Invalid non-zero length for a sparse matrix");
2337-
}
23382335

23392336
auto* sparse_index = sparse_tensor->sparseIndex_as_SparseMatrixIndexCSX();
23402337

@@ -2404,8 +2401,16 @@ Result<std::shared_ptr<SparseIndex>> ReadSparseCSFIndex(
24042401
io::RandomAccessFile* file) {
24052402
auto* sparse_index = sparse_tensor->sparseIndex_as_SparseTensorIndexCSF();
24062403
const auto ndim = static_cast<int64_t>(shape.size());
2404+
if (ndim < 1) {
2405+
return Status::Invalid("Invalid number of dimensions for a CSF sparse tensor");
2406+
}
24072407
auto* indptr_buffers = sparse_index->indptrBuffers();
24082408
auto* indices_buffers = sparse_index->indicesBuffers();
2409+
if (static_cast<int64_t>(indptr_buffers->size()) != ndim - 1 ||
2410+
static_cast<int64_t>(indices_buffers->size()) != ndim) {
2411+
return Status::Invalid(
2412+
"Sparse CSF index buffer counts are inconsistent with the tensor shape");
2413+
}
24092414
std::vector<std::shared_ptr<Buffer>> indptr_data(ndim - 1);
24102415
std::vector<std::shared_ptr<Buffer>> indices_data(ndim);
24112416

@@ -2414,6 +2419,10 @@ Result<std::shared_ptr<SparseIndex>> ReadSparseCSFIndex(
24142419

24152420
RETURN_NOT_OK(internal::GetSparseCSFIndexMetadata(
24162421
sparse_index, &axis_order, &indices_size, &indptr_type, &indices_type));
2422+
if (static_cast<int64_t>(axis_order.size()) != ndim) {
2423+
return Status::Invalid(
2424+
"Sparse CSF axisOrder length is inconsistent with the tensor shape");
2425+
}
24172426
for (int i = 0; i < static_cast<int>(indptr_buffers->size()); ++i) {
24182427
ARROW_ASSIGN_OR_RAISE(indptr_data[i], file->ReadAt(indptr_buffers->Get(i)->offset(),
24192428
indptr_buffers->Get(i)->length(),

0 commit comments

Comments
 (0)