Skip to content

pset: check commitment lengths before FFI parsing - #295

Open
ethicnology wants to merge 1 commit into
ElementsProject:masterfrom
ethicnology:pset-commitment-length-check
Open

pset: check commitment lengths before FFI parsing#295
ethicnology wants to merge 1 commit into
ElementsProject:masterfrom
ethicnology:pset-commitment-length-check

Conversation

@ethicnology

Copy link
Copy Markdown

The PSET input fields issuance_value_comm and issuance_inflation_keys_comm, and the output fields amount_comm and asset_comm, deserialize attacker-controlled byte strings via PedersenCommitment::from_slice and Generator::from_slice. Those wrap FFI functions (secp256k1_pedersen_commitment_parse, secp256k1_generator_parse) that take no length argument and unconditionally read 33 bytes from the slice pointer. An empty or short value therefore triggers an out-of-bounds read; on an empty value the dangling pointer (address 0x1) is dereferenced and the process segfaults instead of returning an error.

Found by libFuzzer/AddressSanitizer on the deserialize_pset target: SEGV on unknown address 0x1, read access, zero page. Reproduced on 0.25.3, 0.26.2 and current master (8765552). Any application parsing untrusted PSETs (wallets, signing or watch-only services) can be crashed by a malicious PSET: denial of service. The faulting access is a fixed read at 0x1; we did not assess further exploitability.

Reject any length other than 33 bytes at the PSET deserialization boundary, before reaching FFI. Adds regression tests for empty, short and invalid-content inputs, plus the minimized 397-byte fuzz artifact. The full test suite passes (160 tests) and a 6.3M-execution ASan run of deserialize_pset with the fix found no further crash.

The same missing length check exists in the safe secp256k1-zkp::zkp wrappers themselves (PedersenCommitment::from_slice, Generator::from_slice); to be reported separately to BlockstreamResearch/rust-secp256k1-zkp.

The PSET input fields `issuance_value_comm` and
`issuance_inflation_keys_comm`, and the output fields `amount_comm`
and `asset_comm`, deserialize attacker-controlled byte strings via
`PedersenCommitment::from_slice` and `Generator::from_slice`. Those
wrap FFI functions that take no length argument and unconditionally
read 33 bytes from the slice pointer. An empty or short value
therefore triggers an out-of-bounds read; on an empty value the
dangling pointer (address 0x1) is dereferenced and the process
segfaults instead of returning an error.

Found by libFuzzer/AddressSanitizer on the `deserialize_pset`
target: SEGV on unknown address 0x1, read access. Reproduced on
0.25.3, 0.26.2 and master.

Reject any length other than 33 bytes at the PSET deserialization
boundary, before reaching FFI. Add regression tests for empty, short
and invalid-content inputs, plus the minimized fuzz artifact.

The same missing length check exists in the safe `secp256k1-zkp`
wrappers themselves; to be reported separately upstream.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant