airborne12 opened a new pull request, #69726:
URL: https://github.com/apache/doris/pull/69726

   ### What problem does this PR solve?
   
   Issue Number: None
   
   Related PR: None
   
   Problem Summary: Three decode primitives of the SNII index format take 
numbers read from the file and do arithmetic on them without checking for 
overflow.
   
   - The FRQ prelude added the untrusted `sbdir_len` to the header length 
before comparing it with the buffer, and summed the super-block lengths into 
the window region length unchecked. A crafted length wraps the sum to a small 
value, so the bounds check passes while a Slice of a huge length is cut from a 
buffer that holds no such bytes, and the block decoder then reads past the end 
of it. `memory_required` already compared `sbdir_len` with the remaining bytes 
before calling `verify_covered_crc`, but `open` did not. The overflow check now 
lives in `verify_covered_crc`, which both call, the super-block sum uses the 
file's own `checked_add_u64`, and the final region check compares against the 
room left instead of adding to the start offset.
   - `decode_varint64` accepted a tenth byte with payload above bit 63. The 
extra bits were shifted out, and the encoding decoded to a silently truncated 
value. The check sits on the terminating byte, so the loop over the 
continuation bytes is unchanged.
   - `pfor_decode` and `pfor_skip` added each exception index delta to a 32-bit 
running index and tested the sum afterwards, so a delta could wrap the index 
back into the block and be accepted. The running index is now 64 bits wide: the 
index is below the block size before every add and a delta is at most 2^32 - 1, 
so the sum cannot wrap.
   
   Nothing here is reachable from data the writers produce. The checks make a 
damaged or crafted index file fail with a corruption status instead of being 
decoded into a wrong value or an out-of-bounds read.
   
   ### Release note
   
   None
   
   ### Compatibility
   
   - No on-disk format change, and no writer is touched. Each check rejects 
only input that no writer produces: a varint64 whose tenth byte is above 1, a 
PFOR exception index that wraps past the block (the encoder writes strictly 
ascending indices below the block size), and an FRQ prelude whose untrusted 
lengths overflow the sums built from them. Files written by any released 
version decode as before.
   - `pfor.cpp`, `varint.cpp` and `frq_prelude.cpp` are identical on master and 
on the branch-4.2 tip, so this change backports without conflicts.
   
   ### Performance
   
   The three hot decoders were measured offline: the real `encoding/` and 
`format/` sources compiled with `-O3`, the old and the new binary run 
interleaved on one pinned core (70 rounds, 11 repetitions). Ratios are new / 
old.
   
   | metric | min | median |
   |---|---|---|
   | varint64, ns per value | 0.994 | 0.998 |
   | PFOR block, no exceptions | 0.991 | 0.996 |
   | PFOR block, 2 exceptions | 0.997 | 1.001 |
   | PFOR block, 10 exceptions | 1.008 | 1.012 |
   | FRQ prelude open, 64 windows | 1.002 | 0.983 |
   | FRQ prelude open, 4096 windows | 1.005 | 1.014 |
   
   Running the same code as both "old" and "new" gives ratios between 0.984 and 
1.026 on this machine, so these are noise. A first version of the checks, with 
a Status-returning helper called for every exception and a test on every varint 
byte, cost 4% to 8% on PFOR blocks with exceptions. The varint check now sits 
on the terminating byte only, and the PFOR running index is 64 bits wide, which 
keeps the old range check and removes the wraparound.
   
   ### Check List (For Author)
   
   - Test <!-- At least one of them must be included. -->
       - [ ] Regression test
       - [x] Unit Test
           - Added SniiVarint.TenthByteOverflowFails, SniiPfor.ExceptionIndex* 
and SniiFrqPreludeTest.FP10 to FP12; all BE unit tests matching *Snii* pass. 
With the three decoders reverted, five of the seven fail (the varint, the PFOR 
wraparound and the three prelude cases). The other two pin behavior that must 
not change: an index past the block is still rejected and the edge indices are 
still accepted.
       - [ ] Manual test (add detailed scripts or steps below)
       - [ ] No need to test or manual test. Explain why:
           - [ ] This is a refactor/code format and no logic has been changed.
           - [ ] Previous test can cover this change.
           - [ ] No code files have been changed.
           - [ ] Other reason
   
   - Behavior changed:
       - [x] No.
       - [ ] Yes.
   
   - Does this need documentation?
       - [x] No.
       - [ ] Yes.
   
   ### Check List (For Reviewer who merge this PR)
   
   - [ ] Confirm the release note
   - [ ] Confirm test cases
   - [ ] Confirm document
   - [ ] Add branch pick label
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to