Skip to content

cipher: StreamCipherCoreWrapper::get_pos() with a block size of 0 can reach unreachable_unchecked() #1275

Closed
@LegionMammal978

Description

@LegionMammal978

The safety comment in the function says "pos is set only to values smaller than block size", but if the block size of the StreamCipherCore is equal to 0 (in a contrived scenario), then initializing pos to 0 breaks this invariant. When debug assertions are disabled, this can cause get_pos() to reach the unreachable_unchecked(). This can be seen with Miri:

// RUSTFLAGS=-Cdebug-assertions=off cargo +nightly miri run
// cipher = "=0.4.3"
use cipher::{
    consts::U0, BlockSizeUser, StreamCipher, StreamCipherCore, StreamCipherCoreWrapper,
    StreamClosure,
};

struct Dummy;

impl BlockSizeUser for Dummy {
    type BlockSize = U0;
}

impl StreamCipherCore for Dummy {
    fn remaining_blocks(&self) -> Option<usize> {
        None
    }

    fn process_with_backend(&mut self, _: impl StreamClosure<BlockSize = Self::BlockSize>) {
        unimplemented!()
    }
}

fn main() {
    let mut wrapper = StreamCipherCoreWrapper::from_core(Dummy);
    wrapper.apply_keystream(&mut []);
}
error: Undefined Behavior: entering unreachable code
  --> /home/lm978/.cargo/registry/src/github.com-1ecc6299db9ec823/cipher-0.4.3/src/stream_wrapper.rs:53:22
   |
53 |             unsafe { core::hint::unreachable_unchecked() }
   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code
   |
   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
   = note: BACKTRACE:
   = note: inside `cipher::StreamCipherCoreWrapper::<Dummy>::get_pos` at /home/lm978/.cargo/registry/src/github.com-1ecc6299db9ec823/cipher-0.4.3/src/stream_wrapper.rs:53:22: 53:57
   = note: inside `<cipher::StreamCipherCoreWrapper<Dummy> as cipher::StreamCipher>::try_apply_keystream_inout` at /home/lm978/.cargo/registry/src/github.com-1ecc6299db9ec823/cipher-0.4.3/src/stream_wrapper.rs:118:19: 118:33
   = note: inside `<cipher::StreamCipherCoreWrapper<Dummy> as cipher::StreamCipher>::try_apply_keystream` at /home/lm978/.cargo/registry/src/github.com-1ecc6299db9ec823/cipher-0.4.3/src/stream.rs:94:9: 94:51
   = note: inside `<cipher::StreamCipherCoreWrapper<Dummy> as cipher::StreamCipher>::apply_keystream` at /home/lm978/.cargo/registry/src/github.com-1ecc6299db9ec823/cipher-0.4.3/src/stream.rs:120:9: 120:38
note: inside `main`
  --> src/main.rs:26:5
   |
26 |     wrapper.apply_keystream(&mut []);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to previous error

Perhaps a defensive guard against the BlockSize = U0 case could be added somewhere.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions