Skip to content

Fix unbound read in Azure::readBigAt - #119054

Merged
arsenmuk merged 8 commits into
masterfrom
arsenmuk/azure-fix-unbound-read
Sep 14, 2026
Merged

Fix unbound read in Azure::readBigAt#119054
arsenmuk merged 8 commits into
masterfrom
arsenmuk/azure-fix-unbound-read

Conversation

@arsenmuk

@arsenmuk arsenmuk commented Sep 9, 2026

Copy link
Copy Markdown
Member

Problem

The reported length of a response from blob storage was trusted when copying data, which could result in a heap buffer overflow.

Fix

The read is now limited by the local buffer capacity. Test coverage is added.

Changelog category (leave one):

  • Bug Fix (user-visible misbehavior in an official stable release)

Changelog entry (a user-readable short description of the changes that goes to CHANGELOG.md):

Fix a possible heap buffer overflow on malformed responses from blob storage.


Workflow [PR]
Sync PR [sync-upstream/pr/119054]

Version info

  • Merged into: 26.9.1.1439 (included in 26.9 and later)

@arsenmuk
arsenmuk marked this pull request as ready for review September 9, 2026 15:09
@clickhouse-gh

clickhouse-gh Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Workflow [PR], commit [a515da0]

Summary:


AI Review

Summary

This PR fixes ReadBufferFromAzureBlobStorage::readBigAt so it no longer trusts the response-reported body length when copying into caller memory, returns the accumulated byte count on short bodies, and makes lazy BlobClient creation safe for the documented supportsReadAt() / readBigAt() handshake. I did not find a remaining correctness or safety issue in the current patch, and the added regression tests cover the overflow and truncated-body cases the PR claims to fix.

Final Verdict

Status: ✅ Approve

LLVM Coverage Report

Measured on commit a515da0.

Metric Baseline Current Δ
Lines 89.00% 88.90% -0.10%
Functions 91.80% 91.80% +0.00%
Branches 81.30% 81.30% +0.00%

Changed lines: Changed C/C++ lines covered: 94/100 (94.00%) · Uncovered code

Full report · Diff report

@clickhouse-gh clickhouse-gh Bot added the pr-bugfix Pull request with bugfix, not backported by default label Sep 9, 2026
@scanhex12 scanhex12 self-assigned this Sep 9, 2026
@arsenmuk arsenmuk changed the title Fix unbound read Fix unbound read in Azure::readBigAt Sep 9, 2026
Comment thread src/Disks/IO/ReadBufferFromAzureBlobStorage.cpp
Comment thread src/Disks/tests/gtest_azure_read_buffer.cpp Outdated
…g a full read

`readBigAt` returned the requested size even when the response bodies kept
ending prematurely and the retry loop ran out of attempts, so callers such as
`Parquet::Prefetcher::readSync` could not detect the truncation. Return the
accumulated byte count, like the S3 and HTTP implementations.
@clickhouse-gh clickhouse-gh Bot added the comp-azure Azure Blob Storage integration (credentials, multipart, Azure-specific IO). label Sep 9, 2026
@clickhouse-gh

clickhouse-gh Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Build profile diff (arm_release)

Comparing a515da026 with master c5c3c4d5d (stripped binary size, per-symbol sizes and ThinLTO time; compile times per translation unit against the most recent warmup build that recompiled it).

✅ No significant changes.

Binary sizes

programs/clickhouse-stripped: smaller than the master baseline by the known offset between the two builds, so the difference is not shown. A delta that differs from the offset by more than 50% of it is shown, in either direction.

The official master build is compiled with -g and a pull request build is not, and XRay counts debug instructions towards its instrumentation threshold, so master instruments thousands of functions more and its binary is ~0.4% larger no matter what the pull request does.

Compile time of recompiled translation units

13 translation units recompiled, 44 s compile time in total, 13 of them have a recent master baseline.

Median compile-time ratio to the baselines is ×1.06 (machine-speed difference or a change affecting every TU); per-TU deltas below are relative to that ratio.
The matched translation units cost +2.7 s (+6%) in total before that adjustment.

Job report

… hit a null client

`readBigAt` dereferenced `blob_client` unconditionally, while the client was
only created lazily by `initialize` or `tryGetFileSize`, so a caller following
the documented `supportsReadAt` handshake could hit a null pointer. Route every
user through `getBlobClient`, which creates the client under `std::call_once`:
`readBigAt` is `const` and may be called from multiple threads in parallel, and
creating the client is cheap (it only composes the blob URL, no request is
made). Also make the regression test exercise the documented handshake instead
of forcing a `getFileSize` call.
Comment thread src/Disks/tests/gtest_azure_read_buffer.cpp
The existing test only served responses at least as long as requested, so it
exercised the overlong-body clamp but left the short-count return unproved: a
regression to returning the requested size after a truncated Azure response
would still have passed. Parameterize the mock transport by advertised vs.
served size and add a case whose body ends early, asserting `readBigAt` returns
the accumulated byte count and leaves the unread tail untouched.
Comment thread src/Disks/IO/ReadBufferFromAzureBlobStorage.cpp
@arsenmuk
arsenmuk added this pull request to the merge queue Sep 14, 2026
Merged via the queue into master with commit 0d04f2b Sep 14, 2026
344 of 345 checks passed
@arsenmuk
arsenmuk deleted the arsenmuk/azure-fix-unbound-read branch September 14, 2026 02:32
@robot-ch-test-poll robot-ch-test-poll added the pr-synced-to-cloud The PR is synced to the cloud repo label Sep 14, 2026
alexey-milovidov added a commit that referenced this pull request Sep 14, 2026
…-buffer-overflows

Master merged #119054, an independent fix of
the same `readBigAt` overflow in `ReadBufferFromAzureBlobStorage`. Resolution:

- `ReadBufferFromAzureBlobStorage.cpp`: take master's thread-safe lazy `getBlobClient`
  (created under `call_once`) everywhere, which supersedes this branch's call-local blob
  client in `readBigAt`; keep this branch's `checkReturnedRange` / `checkReturnedETag`,
  `copyFromAzureBodyStream`, the null body stream guard and the short-read warning; keep
  master's `chassert(bytes_copied <= n)`.
- `gtest_azure_read_buffer.cpp` (add/add): keep this branch's file and port master's two
  tests `AzureReadBigAt.DoesNotTrustResponseLength` and
  `AzureReadBigAt.ReturnsAccumulatedCountOnTruncatedResponse` onto its `makeFreshBuffer`
  harness.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp-azure Azure Blob Storage integration (credentials, multipart, Azure-specific IO). pr-bugfix Pull request with bugfix, not backported by default pr-synced-to-cloud The PR is synced to the cloud repo

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants