sumdb/tlog: fix TileHashReader authentication bypass
TileHashReader's ReadHashes operates in five stages:
1. it collects the tiles needed to compute the tree hash (stx);
2. it collects the tiles needed to compute the requested indexes;
3. if fetches all the tiles from the TileReader;
4. it authenticates the stx tiles against the tree hash;
5. it authenticates the remaining tiles against their parents.
At the collection stage, it deduplicates. So for example if h = 2,
N = 15, and indexes = [(0, 01)]
s3
┌───────┴───────┐
∘ ∘ s2 <- 1/000.p/3
┌───┴───┐ ┌───┴───┐ ┌───┴───┐
∘ ∘ ∘ ∘ ∘ ∘ s1 s0
┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ ┌─┴─┐ |
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14
└── 0/000 ───┘ └── 0/001 ───┘ └── 0/002 ───┘ └ 0/003.p/3 ┘
then there are four hashes needed to compute the tree hash
(s3, s2, s1, s0) which sit in two tiles (1/000.p/3 and 0/003.p/3).
Step 4 authenticates those two tiles against the tree hash. Then step 5
should have authenticated tiles[2:] (the remaining tiles) against their
parents. Instead, it was authenticating tiles[len(stx):], so tiles[4:].
That means that tiles[2:4] were never authenticated, but were still
(correctly) used to find hashes for indexes. Those hashes were returned
completely attacker-controlled. The tiles were also passed
attacker-controlled to SaveTiles, breaking its security contract.
Ooof.
Add a comprehensive test that iterates over all tree sizes in [1, 100]
and tries to tamper with every index.
Fixes CVE-2026-56865
Fixes #80744
Change-Id: I4948dfe06e5c8ba068f7f7edfc215c086a6a6964
Reviewed-on: https://go-review.googlesource.com/c/mod/+/814960
Auto-Submit: Gopher Robot <gobot@golang.org>
Reviewed-by: Neal Patel <nealpatel@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This repository holds packages for writing tools that work directly with Go module mechanics. That is, it is for direct manipulation of Go modules themselves.
It is NOT about supporting general development tools that need to do things like load packages in module mode. That use case, where modules are incidental rather than the focus, should remain in x/tools, specifically x/tools/go/packages.
The specific case of loading packages should still be done by invoking the go command, which remains the single point of truth for package loading algorithms.