Fix SIGSEGV on malformed Text field
C++ helper c_reraise_kj_exception() (capnp/helpers/capabilityHelper.cpp) unconditionally dereferences the PyObject* returned by wrap_kj_exception_for_reraise() (capnp/lib/capnp.pyx). For a specific class of malformed input -- a Cap'n Proto Text field whose NUL terminator is corrupt -- the wrapper returns NULL, and the subsequent "obj->ob_type" access dereferences NULL (offset 0x8) inside the C extension, producing a deterministic, UNCATCHABLE SIGSEGV. libcapnp itself detects the corruption correctly and would raise a catchable KjException for the sibling code path; only this reraise helper crashes. The malformed bytes reach the crash through the documented public API Type.from_bytes(...) + lazy field access -- exactly how pycapnp consumers deserialize untrusted Cap'n Proto messages received over the network / RPC / from files. A single flipped byte in an attacker-controlled message takes down the consuming process; the crash cannot be caught with try/except, so no graceful degradation is possible.
This commit is contained in:
@@ -252,3 +252,22 @@ def test_from_bytes_packed_traversal_limit(all_types):
|
||||
msg = all_types.TestAllTypes.from_bytes_packed(data, traversal_limit_in_words=2**62)
|
||||
for i in range(0, size):
|
||||
assert msg.structList[i].uInt8Field == 0
|
||||
|
||||
def test_malformed_text_field_reraise():
|
||||
SCHEMA = "@0xdbb9ad1f14bf0b36;\nstruct Person { name @0 :Text; age @1 :UInt32; }\n"
|
||||
with tempfile.NamedTemporaryFile(suffix=".capnp", mode="w", delete=False) as f:
|
||||
f.write(SCHEMA)
|
||||
|
||||
Person = capnp.load(f.name).Person
|
||||
|
||||
# Create valid payload and corrupt the NUL terminator
|
||||
buf = bytearray(Person.new_message(name="alice", age=30).to_bytes())
|
||||
buf[37] ^= 0xFF
|
||||
|
||||
# The process should raise an exception, not SIGSEGV
|
||||
try:
|
||||
with Person.from_bytes(bytes(buf), traversal_limit_in_words=2**20) as r:
|
||||
_ = str(r.name)
|
||||
except Exception as e:
|
||||
# Success: We caught an exception cleanly
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user