Skip to content

Security

Finn Bear edited this page Sep 24, 2024 · 14 revisions

Introduction

bitcode is designed to decode arbitrary, possibly corrupt or malicious, input without misbehaving.

Panics

bitcode should only panic due to programmer error or resource exhaustion, for example:

Undefined behavior

bitcode should not trigger vulnerable undefined behavior, regardless of the usage of the public API, the input, the OS, or the architecture.

While bitcode does intentionally invoke undefined behavior in release mode on certain architectures, it is for measurable performance benefit and precautions have been taken to make it safe (in the colloquial sense). We're looking into replacing it with assembly or waiting until Rust adds a new intrinsic.

Excessive allocations

bitcode avoids allocating memory without consuming part of the input, so the total memory used is proportional to the input size. Consider imposing a size limit on messages before decoding.

However, you need to avoid enum's with variants of very unbalanced sizes:

#[derive(Decode)]
enum Message {
    Smol,
    Chonk([u8; 1_000_000_000]),
}

In this case, an small input buffer could contain many instances of Message::Smol, each of which would need to allocate 1GB, the size of Message.

bitcode does not handle allocation errors that do occur.

Memory leaks

bitcode should not leak memory, except in the case of very specific panics (bitcode::Decode is optimized by decoding in place, meaning that a panic from PartialEq, Ord, or Hash can fail to drop certain allocations).

Non-termination

bitcode functions should always terminate, provided PartialEq, Ord, or Hash terminate

Fuzzing

bitcode has a fuzzer that runs in CI.

Reporting vulnerabilities

Please report confirmed/suspected vulnerabilities here :)