Document buffer fast-path preconditions with an assertion#33
Document buffer fast-path preconditions with an assertion#33orbisai0security wants to merge 2 commits into
Conversation
|
Please do read the code, in particular what the function |
msgpack_buffer_write_byte_and_data has a caller-side precondition: the buffer must have at least length + 1 bytes writable. Every call site in cbor_encoder_write_head (ext/cbor/packer.h) and the float paths already calls msgpack_buffer_ensure_writable with the exact required size immediately beforehand. This change does three things: * Adds assert(length + 1 <= msgpack_buffer_writable_size(b)) to the function, making the precondition executable in debug builds and documenting it in code. The assert compiles out under NDEBUG, so there is no release-build cost on the hot path. * Adds rspec coverage in spec/packer_spec.rb that exercises every cbor_encoder_write_head branch funneling into write_byte_and_data (16-bit, 32-bit, 64-bit head sizes for unsigned/negative ints, byte/text strings, array/map headers) plus the float16/32/64 paths, all via round-trip encode/decode. * Retracts an earlier draft of this PR that added a runtime ensure_writable inside write_byte_and_data and a C test stub (tests/test_invariant_buffer.h) that used a non-existent type, never invoked the function under test, and tested its own local memcpy. There is no demonstrated overflow on this code path; the earlier CRITICAL/CWE-120 framing was wrong and is withdrawn. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
aa229c2 to
6411e73
Compare
Addressed the comment. Pls review. |
|
✅ Review Feedback Addressed I've automatically addressed 1 review comment(s): @cabo's review points out that Files modified:
The changes have been pushed to this PR branch. Please review! |
Summary
Retraction and rewrite of the previous version of this PR.
msgpack_buffer_write_byte_and_datahas a caller-side precondition: the buffer must have at leastlength + 1bytes writable. Every call site incbor_encoder_write_head(ext/cbor/packer.h:85-98) and the float paths (ext/cbor/packer.h:164-190) already callsmsgpack_buffer_ensure_writablewith the exact required size on the line above. The precondition is an internal caller contract, not an attacker-reachable bug.This PR documents that contract with an
assert(length + 1 <= msgpack_buffer_writable_size(b))inside the function. UnderNDEBUGthe assertion compiles out, so there is zero hot-path cost in release builds; in debug builds it catches the exact invariant violation the original version of this PR was worried about.It also adds rspec coverage in
spec/packer_spec.rbthat exercises everycbor_encoder_write_headbranch funneling intowrite_byte_and_data(16-bit, 32-bit, 64-bit heads for unsigned/negative ints, byte/text strings, array/map headers, plus float16/32/64), via round-trip encode/decode.Retraction
The earlier version of this PR (commits
f0dc26fandaa229c2) added a redundantmsgpack_buffer_ensure_writable(b, length + 1)call insidemsgpack_buffer_write_byte_and_data, and a C test stub (tests/test_invariant_buffer.h) that referenced a non-existent type (cbor_buffer_t), never invoked the function under test, and asserted on amemcpyit executed inside the test body — it passed independent of the library code.The "CRITICAL / Confirmed exploitable / CWE-120 / V-001" framing was wrong. There is no demonstrated overflow on this code path because every caller pre-sizes the buffer. Apologies for the noise; @cabo's review was right that the right framing is "hardening / invariant documentation," not a security fix, and that the actual untrusted-length surface is the unpacker (
SANE_PREALLOCATEandread_raw_body_continunpacker.c), not the packer. The CRITICAL/CVE label is withdrawn.Changes
ext/cbor/buffer.h—#include <assert.h>; replace the function body's first line with the precondition assertion + a one-line comment naming the caller contract.spec/packer_spec.rb— newdescribe 'head-size branches into write_byte_and_data'context covering every branch by round-trip.tests/test_invariant_buffer.h— deleted (broken; the project has no C unit-test harness).Verification
bundle exec rake specshould pass — the new specs round-trip every head-size branch.RUBY_ASSERTover plain Cassert, happy to adapt.