Querier: fix panic on invalid UTF-8 in active request tracker - #7743
Open
pujitha24 wants to merge 1 commit into
Open
Querier: fix panic on invalid UTF-8 in active request tracker#7743pujitha24 wants to merge 1 commit into
pujitha24 wants to merge 1 commit into
Conversation
Motivation:
trimStringByBytes in the active request tracker scans backwards from
a byte offset for a UTF-8 rune-start byte, with no lower bound. If a
truncated value consists entirely of UTF-8 continuation bytes
(0x80-0xBF), no byte in the string is ever a rune start, so the loop
decrements past 0 and the subsequent slice index panics with "index
out of range [-1]".
The active request tracker is enabled by default
(-querier.active-query-tracker-dir) and wraps the Prometheus API
router, including /api/v1/series, /api/v1/labels and
/api/v1/label/{name}/values. A tenant-supplied match[] or query value
long enough to be truncated (over maxEntrySize) and made of invalid
UTF-8 continuation bytes reaches trimStringByBytes byte-for-byte, so
this is reachable from request input without special privileges. This
is the same underflow class as cortexproject#7640, which added a bound in
trimForJsonMarshalRecursive but did not touch the scan inside
trimStringByBytes; its regression tests only use valid multi-byte
UTF-8, which always terminates the backwards scan before reaching
index 0.
This change only fixes the panic in trimStringByBytes. It does not add
a recover() to the querier worker goroutine that runs request handling
(pkg/querier/worker/scheduler_processor.go) — that was suggested in
the issue as a separate, additional hardening measure and is out of
scope for this fix.
Approach:
Bound the backwards scan with size > 0 so it stops at index 0 instead
of underflowing. For any valid UTF-8 input, byte 0 is always a rune
start, so this does not change behavior for legitimate input; it only
changes the degenerate all-continuation-byte case, which now correctly
trims to an empty string instead of panicking.
Validation:
- go build ./...
- go test ./pkg/util/request_tracker/... (all pass, including the new
TestTrimForJsonMarshalInvalidUTF8 regression test)
- Confirmed TestTrimForJsonMarshalInvalidUTF8 reproduces the exact
panic ("index out of range [-1]" at request_extractor.go:86) against
the pre-fix code by temporarily reverting the one-line fix and
re-running the test, then restored the fix and re-ran to confirm it
passes.
Fixes cortexproject#7729
Signed-off-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation:
trimStringByBytes in the active request tracker scans backwards from
a byte offset for a UTF-8 rune-start byte, with no lower bound. If a
truncated value consists entirely of UTF-8 continuation bytes
(0x80-0xBF), no byte in the string is ever a rune start, so the loop
decrements past 0 and the subsequent slice index panics with "index
out of range [-1]".
The active request tracker is enabled by default
(-querier.active-query-tracker-dir) and wraps the Prometheus API
router, including /api/v1/series, /api/v1/labels and
/api/v1/label/{name}/values. A tenant-supplied match[] or query value
long enough to be truncated (over maxEntrySize) and made of invalid
UTF-8 continuation bytes reaches trimStringByBytes byte-for-byte, so
this is reachable from request input without special privileges. This
is the same underflow class as #7640, which added a bound in
trimForJsonMarshalRecursive but did not touch the scan inside
trimStringByBytes; its regression tests only use valid multi-byte
UTF-8, which always terminates the backwards scan before reaching
index 0.
This change only fixes the panic in trimStringByBytes. It does not add
a recover() to the querier worker goroutine that runs request handling
(pkg/querier/worker/scheduler_processor.go) — that was suggested in
the issue as a separate, additional hardening measure and is out of
scope for this fix.
Approach:
Bound the backwards scan with size > 0 so it stops at index 0 instead
of underflowing. For any valid UTF-8 input, byte 0 is always a rune
start, so this does not change behavior for legitimate input; it only
changes the degenerate all-continuation-byte case, which now correctly
trims to an empty string instead of panicking.
Validation:
TestTrimForJsonMarshalInvalidUTF8 regression test)
panic ("index out of range [-1]" at request_extractor.go:86) against
the pre-fix code by temporarily reverting the one-line fix and
re-running the test, then restored the fix and re-ran to confirm it
passes.
Fixes #7729
Signed-off-by: Pujitha Paladugu 10557236+pujitha24@users.noreply.github.com
AI assistance: this change was drafted with Claude Code.