Skip to content

fill_buffer fast path panics on shift overflow with malformed deflate input #80

@riley-pittman

Description

@riley-pittman

The fast path in fill_buffer (line 159) uses a bare << self.nbits shift:

self.buffer |= u64::from_le_bytes(input[..8].try_into().unwrap()) << self.nbits;

When self.nbits >= 64, this panics with "attempt to shift left with overflow" — which occurs in all build modes, not just debug.

The slow path (line 167) already handles this correctly with checked_shl:

self.buffer |= u64::from_le_bytes(input_data)
.checked_shl(self.nbits as u32)
.unwrap_or(0);

How nbits reaches 64: consume_bits guards against underflow with only a debug_assert! (compiled out in release builds). Malformed deflate data can cause the decompressor to consume more bits than are in the buffer, wrapping nbits (a u8) to a large value via unsigned subtraction. On the next fill_buffer call, the shift overflows and panics.

Impact: When used via the png crate, any malformed PNG with a corrupt deflate stream can trigger this panic. In environments using panic=abort (common in embedded/mobile), this is an instant process kill with no opportunity for error recovery.

Proposed fix (3 lines):

  1. fill_buffer fast path — use checked_shl, matching the slow path:
    // before
    self.buffer |= u64::from_le_bytes(input[..8].try_into().unwrap()) << self.nbits;
    *input = &input[(63 - self.nbits as usize) / 8..];

// after
self.buffer |= u64::from_le_bytes(input[..8].try_into().unwrap())
.checked_shl(self.nbits as u32)
.unwrap_or(0);
*input = &input[(63 - self.nbits.min(63) as usize) / 8..];

  1. consume_bits — use saturating_sub to prevent wrapping on malformed input:
    // before
    self.nbits -= nbits;

// after
self.nbits = self.nbits.saturating_sub(nbits);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions