Fix UAF in streams when XADD creates a new node - #4711
Baraa-Hasheesh wants to merge 4 commits into
Conversation
Signed-off-by: Bara' Hasheesh <bara.hasheesh@gmail.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
Included review availability: Your plan provides up to 10 included reviews per hour; 8 remain after this review. 📝 WalkthroughWalkthroughThe stream append path now tracks radix-tree listpack pointers separately during replacement and insertion. A regression test covers traversal across macro nodes and restores the previous stream-node byte limit. ChangesStream macro-node handling
Priority: ⬆️ High Estimated code review effort: 2 (Simple) | ~10 minutes Severity of issue fixed: High Suggested reviewers: Merge Risk: ⚪ Minimal · up to The stream append fix updates the radix-tree pointer after listpack replacement and the regression test validates forward and reverse traversal across macro nodes. No actionable merge risk remains. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Linked Issues checkExplanation The implementation addresses the dangling-pointer path in
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| assert_equal {2-2 2-3} [lmap e [r XRANGE k - +] {lindex $e 0}] | ||
|
|
||
| # Allow nodes to grow again and keep appending. | ||
| r CONFIG SET stream-node-max-bytes 4096 |
There was a problem hiding this comment.
This hard-codes the global config to its default instead of restoring the value that was active before the test. --config stream-node-max-bytes ... and external-server runs can start with a different value, and this leaves later stream tests running with 4096. Save it with config_get_set stream-node-max-bytes 1 at the first change, then restore that saved value here.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## unstable #4711 +/- ##
============================================
- Coverage 80.63% 80.63% -0.01%
============================================
Files 192 192
Lines 100803 100852 +49
============================================
+ Hits 81287 81321 +34
- Misses 19516 19531 +15
🚀 New features to boost your workflow:
|
- Save configuration & restore it at test end Signed-off-by: Bara' Hasheesh <bara.hasheesh@gmail.com>
madolson
left a comment
There was a problem hiding this comment.
Fix looks fine, but an alternative suggestion.
- Use rax_lp local field for future comparisons - Add documentation on the test to avoid future unintended changes Signed-off-by: Bara' Hasheesh <bara.hasheesh@gmail.com>
Signed-off-by: Bara' Hasheesh <bara.hasheesh@gmail.com>
Fixes #4705.
Summary
XADDcan leave a stream's radix tree holding a dangling pointer to a freedlistpack. When the entry is later read (
XRANGE,XREVRANGE,XINFO STREAM ... FULL), we hit UB.Root cause
In
streamAppendItem(), when aXADDcannot append to the current tail node, the tail node is shrunk to fit,that in turn might relocate it to a different location in memory, while
ri.datais kept pointing to the old dangling pointer.After which a new node is created & is inserted.
Following that multiple appends happen on that node, that operation might reallocate it & it's possible that the final
allocation might just happen to reallocate to the same location as the original node
ri.data, I.E.ri.data == lpDue to this unfortunate allocation, the radix tree will never be updated with the latest values leaving it with a dangling pointer
Fix
Two changes in
streamAppendItem():ri.datais invalidated if the current tail node is shrunk & reallocated to a new locationraxInsertwhen a new node is created to avoid sending a pointer to the radix tree that might later get invalidatedTesting
Added an integration test in
tests/unit/type/stream.tclthat reliably fails with jemalloc without the fix