Impact: ~2,895 assertions (302 distinct failure patterns identified) Goal: Properly reject malformed WebAssembly binaries
The Kiln decoder currently accepts malformed WebAssembly binaries that should be rejected. This plan addresses 8 categories of validation failures.
Problem: Custom section names, import/export names not validated for UTF-8 conformance.
Root Cause: process_custom_section() in streaming_decoder.rs (lines 2350-2354) does nothing - returns Ok(()) without parsing the section name.
Implementation:
- Modify
process_custom_section()to parse the section name usingvalidate_utf8_name() - Custom section format: name_len (LEB128), name (bytes), data (remaining)
- Validate the name is valid UTF-8 before proceeding
File: /Users/r/git/wrt2/kiln-decoder/src/streaming_decoder.rs lines 2350-2354
Problem: Decoder accepts duplicate non-custom sections (two start sections, two function sections).
Root Cause: process_next_section() does not track which sections have been seen.
Implementation:
- Add field to
StreamingDecoder:seen_sections: u16(bitmask for sections 1-13) - In
process_next_section():- For section_id 1-13: Check if bit already set
- If duplicate, return error "unexpected content after last section"
- Set bit after processing
- Allow multiple custom sections (ID 0), reject duplicates of IDs 1-13
File: /Users/r/git/wrt2/kiln-decoder/src/streaming_decoder.rs lines 220-244
Problem: Decoder does not verify section content exactly fills declared section size.
Implementation:
- Modify each
process_*_section()method to track bytes consumed - In
process_next_section()after callingprocess_section():- Verify all bytes consumed within section
- If content remains, return error "section size mismatch"
File: /Users/r/git/wrt2/kiln-decoder/src/streaming_decoder.rs - all process_*_section() methods
Problem: Some LEB128 integers that overflow u32 are accepted.
Implementation:
- In
/Users/r/git/wrt2/kiln-format/src/binary.rsread_leb128_u32():- On 5th byte: check
(byte & 0xF0) == 0(only low 4 bits valid) - Check before
result |= ...to prevent overflow - Reject 5+ byte encodings
- On 5th byte: check
File: /Users/r/git/wrt2/kiln-format/src/binary.rs lines 625-669
Problem: Section IDs >= 14 or LEB128-encoded section IDs accepted as custom sections.
Implementation:
- In
process_next_section():- Validate section_id <= 13
- Section ID should be single byte, not LEB128
- If section_id > 13 OR byte has continuation bit (0x80), return "malformed section id"
- Change
_ =>arm to explicitly reject unknown IDs:
match section_id {
0 => self.process_custom_section(data),
1 => self.process_type_section(data),
// ... other valid sections
_ => Err(Error::parse_error("malformed section id")),
}File: /Users/r/git/wrt2/kiln-decoder/src/streaming_decoder.rs lines 226-264
Problem: Function count != code count, data count mismatches, missing data count section.
Implementation:
-
Add tracking fields to
StreamingDecoder:function_count: Option<u32>code_count: Option<u32>data_count_value: Option<u32>data_section_count: Option<u32>uses_memory_init_or_data_drop: bool
-
In
finish()method:- If function_count and code_count both exist, must match
- If data_count_value exists, must equal data_section_count
- If uses_memory_init_or_data_drop, data_count_value must exist
File: /Users/r/git/wrt2/kiln-decoder/src/streaming_decoder.rs struct definition and finish()
Problem: Invalid limits flags (0x08, 0x10, LEB128-encoded) accepted.
Implementation:
-
In
process_table_section():- Read flags as single byte
- Basic tables: only 0x00 and 0x01 valid
- Typed tables (GC): 0x40 and 0x41 valid
- Reject others with "malformed limits flags"
-
In
process_memory_section():- MVP: only 0x00 and 0x01 valid
- Threads: 0x00-0x03 valid
- Memory64: 0x00-0x07 valid
File: /Users/r/git/wrt2/kiln-decoder/src/streaming_decoder.rs lines 1172-1188
| Issue | Count | Fix |
|---|---|---|
| END opcode expected | 2 | Verify function bodies end with 0x0B |
| Unexpected end | 6 | Better bounds checking when reading |
| Malformed reference type | 2 | Validate reftype is 0x70/0x6F in element section |
| Illegal opcode | 2 | Validate opcodes in element init expressions |
| Malformed mutability | 1 | Validate mutability is 0x00 or 0x01 |
| Integer representation too long | 4 | Stricter LEB128 validation |
| Priority | Category | Failures Fixed | Complexity |
|---|---|---|---|
| 1 | UTF-8 validation | 176 | Low |
| 2 | Section ordering | 46 | Medium |
| 3 | Cross-section validation | 20 | Medium |
| 4 | Section size mismatch | 14 | Medium |
| 5 | LEB128 overflow | 13 | Careful testing |
| 6 | Section ID validation | 10 | Low |
| 7 | Limits flags | 8 | Low |
| 8 | Remaining | 15 | Various |
| File | Changes Needed |
|---|---|
kiln-decoder/src/streaming_decoder.rs |
UTF-8, section ordering, section ID, limits flags, cross-section |
kiln-format/src/binary.rs |
LEB128 overflow checks |
kiln-decoder/src/optimized_string.rs |
UTF-8 validation utilities (reuse) |
kiln-decoder/src/decoder_no_alloc.rs |
Existing section order validation (reference) |
kiln-decoder/src/sections.rs |
Section parsing size validation |