Skip to content

Panic when sending more than 64 file descriptors on unix systems #395

@simonwuelker

Description

@simonwuelker

The following code panics as of ipc-channel 0.19.0:

use ipc_channel::ipc::{IpcSharedMemory, channel};
use std::iter;

fn main() {
    let regions: Vec<IpcSharedMemory> = iter::repeat_n(b"foobar".as_slice(), 65)
        .map(IpcSharedMemory::from_bytes)
        .collect();
    let (sender, receiver) = channel().unwrap();
    sender.send(regions).unwrap();
    receiver.recv().unwrap();
}
Full Backtrace
thread 'main' panicked at /home/alaska/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ipc-channel-0.19.0/src/ipc.rs:562:78:
index out of bounds: the len is 64 but the index is 64
stack backtrace:
   0: rust_begin_unwind
             at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library/std/src/panicking.rs:695:5
   1: core::panicking::panic_fmt
             at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library/core/src/panicking.rs:75:14
   2: core::panicking::panic_bounds_check
             at /rustc/05f9846f893b09a1be1fc8560e33fc3c815cfecb/library/core/src/panicking.rs:273:5
   3: <usize as core::slice::index::SliceIndex<[T]>>::index_mut
             at /home/alaska/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/slice/index.rs:280:14
   4: core::slice::index::<impl core::ops::index::IndexMut<I> for [T]>::index_mut
             at /home/alaska/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/slice/index.rs:27:9
   5: <alloc::vec::Vec<T,A> as core::ops::index::IndexMut<I>>::index_mut
             at /home/alaska/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/vec/mod.rs:3370:9
   6: <ipc_channel::ipc::IpcSharedMemory as serde::de::Deserialize>::deserialize::{{closure}}
             at /home/alaska/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ipc-channel-0.19.0/src/ipc.rs:562:78
   7: std::thread::local::LocalKey<T>::try_with
             at /home/alaska/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/local.rs:310:12
   8: std::thread::local::LocalKey<T>::with
             at /home/alaska/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/local.rs:274:15
   9: <ipc_channel::ipc::IpcSharedMemory as serde::de::Deserialize>::deserialize
             at /home/alaska/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ipc-channel-0.19.0/src/ipc.rs:558:32
  10: <core::marker::PhantomData<T> as serde::de::DeserializeSeed>::deserialize
             at /home/alaska/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde-1.0.219/src/de/mod.rs:800:9
  11: <<&mut bincode::de::Deserializer<R,O> as serde::de::Deserializer>::deserialize_tuple::Access<R,O> as serde::de::SeqAccess>::next_element_seed
             at /home/alaska/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bincode-1.3.3/src/de/mod.rs:314:25
  12: serde::de::SeqAccess::next_element
             at /home/alaska/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde-1.0.219/src/de/mod.rs:1734:9
  13: <serde::de::impls::<impl serde::de::Deserialize for alloc::vec::Vec<T>>::deserialize::VecVisitor<T> as serde::de::Visitor>::visit_seq
             at /home/alaska/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde-1.0.219/src/de/impls.rs:1175:46
  14: <&mut bincode::de::Deserializer<R,O> as serde::de::Deserializer>::deserialize_tuple
             at /home/alaska/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bincode-1.3.3/src/de/mod.rs:326:9
  15: <&mut bincode::de::Deserializer<R,O> as serde::de::Deserializer>::deserialize_seq
             at /home/alaska/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bincode-1.3.3/src/de/mod.rs:350:9
  16: serde::de::impls::<impl serde::de::Deserialize for alloc::vec::Vec<T>>::deserialize
             at /home/alaska/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde-1.0.219/src/de/impls.rs:1186:9
  17: <core::marker::PhantomData<T> as serde::de::DeserializeSeed>::deserialize
             at /home/alaska/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/serde-1.0.219/src/de/mod.rs:800:9
  18: bincode::internal::deserialize_seed
             at /home/alaska/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bincode-1.3.3/src/internal.rs:118:15
  19: bincode::internal::deserialize
             at /home/alaska/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bincode-1.3.3/src/internal.rs:106:5
  20: bincode::config::Options::deserialize
             at /home/alaska/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bincode-1.3.3/src/config/mod.rs:200:9
  21: bincode::deserialize
             at /home/alaska/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bincode-1.3.3/src/lib.rs:181:5
  22: ipc_channel::ipc::IpcMessage::to::{{closure}}::{{closure}}
             at /home/alaska/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ipc-channel-0.19.0/src/ipc.rs:726:34
  23: std::thread::local::LocalKey<T>::try_with
             at /home/alaska/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/local.rs:310:12
  24: std::thread::local::LocalKey<T>::with
             at /home/alaska/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/local.rs:274:15
  25: ipc_channel::ipc::IpcMessage::to::{{closure}}
             at /home/alaska/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ipc-channel-0.19.0/src/ipc.rs:713:13
  26: std::thread::local::LocalKey<T>::try_with
             at /home/alaska/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/local.rs:310:12
  27: std::thread::local::LocalKey<T>::with
             at /home/alaska/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/thread/local.rs:274:15
  28: ipc_channel::ipc::IpcMessage::to
             at /home/alaska/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ipc-channel-0.19.0/src/ipc.rs:712:9
  29: ipc_channel::ipc::IpcReceiver<T>::recv
             at /home/alaska/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/ipc-channel-0.19.0/src/ipc.rs:254:9
  30: ipc_test::main
             at ./src/main.rs:10:5
  31: core::ops::function::FnOnce::call_once
             at /home/alaska/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

The problem is that the receiver expects to receive at most 64 file descriptors (one of which may be reserved for fragmented messages).
The IpcSender has no such limit and will happily send as many file descriptors as you give it. (In the example above, one IpcSharedMemory is one fd). This causes the file descriptors to be lost, so the deserialization code panics when they're not there.

Relevant sections of the code are

const MAX_FDS_IN_CMSG: u32 = 64;

// If the message is small enough, try sending it in a single fragment.
if data.len() <= Self::get_max_fragment_size() {
match send_first_fragment(self.fd.0, &fds[..], data, data.len()) {
Ok(_) => return Ok(()),
Err(error) => {
// ENOBUFS means the kernel failed to allocate a buffer large enough
// to actually transfer the message,
// although the message was small enough to fit the maximum send size --
// so we have to proceed with a fragmented send nevertheless,
// using a reduced send buffer size.
//
// Any other errors we might get here are non-recoverable.
if !(matches!(error, UnixError::Errno(libc::ENOBUFS))
&& downsize(&mut sendbuf_size, data.len()).is_ok())
{
return Err(error);
}
},
}
}

This was first discovered in servo/servo#36792.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions