ChainSafe / ChainSafe/gossamer

Fuzzing results for DecodeHeader target

Open
#3,116 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
454
Forks
144
PR merge metrics
No merged PRs in 30d

Description

There are a few crashes that Fuzzers caught.

# Target
### ```Substrate```
```rust
#[derive(Encode, Decode, PartialEq, Eq, Clone, sp_core::RuntimeDebug, TypeInfo)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct Header + TryFrom, Hash: HashT> {
/// The parent hash.
pub parent_hash: Hash::Output,
/// The block number.
#[cfg_attr(
feature = "std",
serde(serialize_with = "serialize_number", deserialize_with = "deserialize_number")
)]
#[codec(compact)]
pub number: Number,
/// The state trie merkle root
pub state_root: Hash::Output,
/// The merkle root of the extrinsics.
pub extrinsics_root: Hash::Output,
/// A chain-specific digest of data useful for light clients or referencing auxiliary data.
pub digest: Digest,
}
```
### ```Smoldot```
```rust
#[derive(Debug, Clone)]
pub struct HeaderRef<'a> {
/// Hash of the parent block stored in the header.
pub parent_hash: &'a [u8; 32],
/// Block number stored in the header.
pub number: u64,
/// The state trie Merkle root
pub state_root: &'a [u8; 32],
/// The Merkle root of the extrinsics.
///
/// You can use the [`extrinsics_root`] function to compute this value.
pub extrinsics_root: &'a [u8; 32],
/// List of auxiliary data appended to the block header.
pub digest: DigestRef<'a>,
}

pub fn decode(scale_encoded: &[u8], block_number_bytes: usize) -> Result {
let (header, remainder) = decode_partial(scale_encoded, block_number_bytes)?;
if !remainder.is_empty() {
return Err(Error::TooLong);
}

Ok(header)
}
```
### ```Gossamer```
```go
type Header struct {
ParentHash common.Hash `json:"parentHash"`
Number uint `json:"number"`
StateRoot common.Hash `json:"stateRoot"`
ExtrinsicsRoot common.Hash `json:"extrinsicsRoot"`
Digest scale.VaryingDataTypeSlice `json:"digest"`
hash common.Hash
}

```
# ```DecodeHeader``` Reproducing Scripts
### ```Substrate```
```rust
pub fn substrate_decode_header(file_name: &String) {
println!("[+] Substrate Result:");
let buf = read_bytes(file_name).unwrap();
let mut data: &[u8] = buf.as_ref();
let ret = Header::::decode(&mut data);
if let Err(_) = ret {
println!("[-] Header decode result: {:?}", ret);
} else {
println!("[+] Header decode result: {:?}", ret);
}
}
```
### ```Smoldot```
```rust
pub fn smoldot_decode_header(file_name: &String) {
println!("[+] Smoldot Result:");
let buf = read_bytes(file_name).unwrap();
let ret = smoldot::header::decode(&buf, usize::from(buf[0]) + 1);
if let Err(_) = ret {
println!("[-] Header decode result: {:?}", ret);
} else {
println!("[+] Header decode result: {:?}", ret);
}
}
```
### ```Gossamer```
```go
func glib_decode_header(data_ptr unsafe.Pointer, data_size int) {
fmt.Println("[+] Gossamer Result:")
var data []byte
sh := (*reflect.SliceHeader)(unsafe.Pointer(&data))
sh.Data = uintptr(data_ptr)
sh.Len = data_size
sh.Cap = data_size
dec := types.NewEmptyHeader()
err := scale.Unmarshal(data, &dec)
if err != nil {
fmt.Println("[-] Header scale.Unmarshal result:", err)
} else {
fmt.Println("[+] Header scale.Unmarshal result:", dec)
}
}
```
# Crash 1

The ```DecodeHeader``` target is trying to decode the ```Header``` structure. When the fuzzers send the same inputs to the clients, the ```Smoldot``` client gives an ```attempting overflow``` panic message, the ```Substrate``` client gives an error message and the ```Gossamer``` client decodes successfully. The reproducing scripts were added to ```reproducer``` part.

```Substrate```:
```
./reproducer run gossamer decodeheader /crash-b0e60e47d206f66ee752b96b3f3d33dcf400cf2d

[+] Substrate Result:
[-] Header decode result: Err(Error { cause: Some(Error { cause: Some(Error { cause: Some(Error { cause: None, desc: "Not enough data to fill buffer" }), desc: "Could not decode `DigestItemType`, failed to read variant byte" }), desc: "Could not decode `Digest::logs`" }), desc: "Could not decode `Header::digest`" })
```
```Smoldot```:
```
./reproducer run smoldot decodeheader /crash-b0e60e47d206f66ee752b96b3f3d33dcf400cf2d

[+] Smoldot Result:
thread 'main' panicked at 'attempt to multiply with overflow', polkafuzz/clients/smoldot/src/header/babe.rs:150:27
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```
```Gossamer```:
```
./reproducer run substrate decodeheader /crash-b0e60e47d206f66ee752b96b3f3d33dcf400cf2d

[+] Gossamer Result:
[+] Header scale.Unmarshal result: ParentHash=0x0000000000000000000000000000000000000000000000000000000000000000 Number=0 StateRoot=0x0000000000000000000000000000000000000000000000000000000000000000 ExtrinsicsRoot=0x0000000000000000000000000000000000000000000000000000000000000000 Digest={{ map[2:{[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]} 4:{[0 0 0 0] []} 5:{[0 0 0 0] []} 6:{[0 0 0 0] []}]} []} Hash=0xdcdd89927d8a348e00257e1ecc8617f45edb5118efff3ea2f9961b2ad9b7690a
```
### Artifact 1
[decodeheader_crash1.zip](https://github.com/ChainSafe/gossamer/files/10724035/decodeheader_crash1.zip)

# Crash 2

The ```DecodeHeader``` target is trying to decode the ```Header``` structure. When the fuzzers send the same inputs to the clients, the ```Substrate``` client gives an error message, the ```Smoldot``` client gives an error message and the ```Gossamer``` client gives ```out of range``` panic. The reproducing scripts were added to ```reproducer``` part.

```Substrate```:
```
./reproducer run substrate decodeheader /crash-04ff29f9cd8283a4011514b853d55584f5992daf

[+] Substrate Result:
[-] Header decode result: Err(Error { cause: Some(Error { cause: Some(Error { cause: None, desc: "out of range decoding Compact" }), desc: "Could not decode `Digest::logs`" }), desc: "Could not decode `Header::digest`" })
```
```Smoldot```:
```
./reproducer run smoldot decodeheader /crash-04ff29f9cd8283a4011514b853d55584f5992daf

[+] Smoldot Result:
[-] Header decode result: Err(DigestItemLenDecodeError)
```
```Gossamer```:
```
./reproducer run gossamer decodeheader /crash-04ff29f9cd8283a4011514b853d55584f5992daf

[+] Gossamer Result:
panic: runtime error: makeslice: len out of range

goroutine 17 [running, locked to thread]:
github.com/ChainSafe/gossamer/pkg/scale.(*decodeState).decodeBytes(0xc00011e000, {0x55d3e4044620?, 0xc0001a0ec8?, 0x55d3e3775751?})
polkafuzz/clients/gossamer/pkg/scale/decode.go:575 +0x72
github.com/ChainSafe/gossamer/pkg/scale.(*decodeState).unmarshal(0x55d3e4044620?, {0x55d3e4044620?, 0xc0001a0ec8?, 0x55d3e40a65e0?})
polkafuzz/clients/gossamer/pkg/scale/decode.go:131 +0x2b1
github.com/ChainSafe/gossamer/pkg/scale.(*decodeState).decodeStruct(0x55d3e409b600?, {0x55d3e409b600?, 0xc0001a0e40?, 0x55d3e4101898?})
polkafuzz/clients/gossamer/pkg/scale/decode.go:449 +0x40b
github.com/ChainSafe/gossamer/pkg/scale.(*decodeState).unmarshal(0x55d3e4074540?, {0x55d3e409b600?, 0xc0001a0e40?, 0x55d3e409b600?})
polkafuzz/clients/gossamer/pkg/scale/decode.go:156 +0x678
github.com/ChainSafe/gossamer/pkg/scale.(*decodeState).decodeVaryingDataType(0xc00011e000, {0x55d3e408ff20?, 0xc0001107b0?, 0x99?})
polkafuzz/clients/gossamer/pkg/scale/decode.go:381 +0x29b
github.com/ChainSafe/gossamer/pkg/scale.(*decodeState).unmarshal(0x55d3e40747c0?, {0x55d3e408ff20?, 0xc0001107b0?, 0x55d3e408ff20?})
polkafuzz/clients/gossamer/pkg/scale/decode.go:139 +0x111
github.com/ChainSafe/gossamer/pkg/scale.(*decodeState).decodeVaryingDataTypeSlice(0x55d3e408ffc0?, {0x55d3e408ffc0?, 0xc0001aa368?, 0x99?})
polkafuzz/clients/gossamer/pkg/scale/decode.go:342 +0x31f
github.com/ChainSafe/gossamer/pkg/scale.(*decodeState).unmarshal(0x55d3e408ffc0?, {0x55d3e408ffc0?, 0xc0001aa368?, 0x55d3e408ffc0?})
polkafuzz/clients/gossamer/pkg/scale/decode.go:141 +0x217
github.com/ChainSafe/gossamer/pkg/scale.(*decodeState).decodeStruct(0x55d3e40c42c0?, {0x55d3e40c42c0?, 0xc0001aa0c0?, 0x55d3e4101898?})
polkafuzz/clients/gossamer/pkg/scale/decode.go:449 +0x40b
github.com/ChainSafe/gossamer/pkg/scale.(*decodeState).unmarshal(0x55d3e4097460?, {0x55d3e40c42c0?, 0xc0001aa0c0?, 0xc00005e000?})
polkafuzz/clients/gossamer/pkg/scale/decode.go:156 +0x678
github.com/ChainSafe/gossamer/pkg/scale.(*decodeState).decodePointer(0xc00011e000, {0x55d3e4097460?, 0xc000126008?, 0x55d3e36fe306?})
polkafuzz/clients/gossamer/pkg/scale/decode.go:314 +0x225
github.com/ChainSafe/gossamer/pkg/scale.(*decodeState).unmarshal(0xc000198750?, {0x55d3e4097460?, 0xc000126008?, 0x7f737d9e0a68?})
polkafuzz/clients/gossamer/pkg/scale/decode.go:150 +0x4c5
github.com/ChainSafe/gossamer/pkg/scale.Unmarshal({0x55d3e47e0dd0, 0x2bc, 0x2bc}, {0x55d3e4034a60?, 0xc000126008?})
polkafuzz/clients/gossamer/pkg/scale/decode.go:80 +0x1e5
main.glib_decode_header(0x55d3e47e0dd0, 0x2bc)
polkafuzz/clients/gossamer/glib.go:162 +0x1d6
```
### Artifact 2
[decodeheader_crash2.zip](https://github.com/ChainSafe/gossamer/files/10724036/decodeheader_crash2.zip)

# Crash 3

The ```DecodeHeader``` target is trying to decode the ```Header``` structure. When the fuzzers send the same inputs to the clients, the ```Substrate``` client decodes successfully, the ```Smoldot``` client gives an error message and the ```Gossamer``` client gives an error message. The reproducing scripts were added to ```reproducer``` part.

```
./reproducer run all decodeheader /3aedad9117aa0749

[+] Smoldot Result:
[-] Header decode result: Err(TooLong)
[+] Substrate Result:
[+] Header decode result: Ok(Header { parent_hash: 0x9999990005510199999500510199999900009999050000000400000404040000, number: 0, state_root: 0x0004040004049905409908000404050000000000000400000000ef00041a0004, extrinsics_root: 0x2f0004050540990800041a0004abab2fe0e008f1000000000095005101999999, digest: Digest { logs: [] } })
[+] Gossamer Result:
[-] Header scale.Unmarshal result: unsupported Option value: 153, bytes: [153 153 0 5 81 1 153 153 149 0 81 1 153 153 153 0 0 153 153 5 0 0 0 4 0 0 4 4 4 0 0 0 0 4 4 0 4 4 153 5 64 153 8 0 4 4 5 0 0 0 0 0 0 4 0 0 0 0 239 0 4 26 0 4 47 0 4 5 5 64 153 8 0 4 26 0 4 171 171 47 224 224 8 241 0 0 0 0 0 149 0 81 1 153 153 153 0 0 153 153 5 0 0 0 4 0 0 4 4 4 0 0 0 0 4 4 0 4 4 4 0 0 0 1 1 153 153 5 64 153 8 0 4 26 0 4 171 171 47 0 4 0 0 0 4 0 0 4 4 149 0 81 1 153 153 153 0 0 153 153 58 0]
```
### Artifact 3
[decodeheader_crash3.zip](https://github.com/ChainSafe/gossamer/files/10724037/decodeheader_crash3.zip)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.