Skip to content

net::recv with TRUNC flag is unsound #1654

Description

@funsafemath

For absolutely no reason I was reading the tcp(7) manpage, and it turns out tcp sockets support the MSG_TRUNC flag, which makes the kernel discard any received data instead of writing it, while still returning the number of bytes received. recv() assumes that the kernel writes min(buffer len, recv return value) bytes, so you can pass an uninit array and get a mut slice of MaybeUninit::uninit().assume_init() u8 (probably not too bad, as the syscall should prevent the compiler from making any assumptions, but it's still technically ub).

https://man7.org/linux/man-pages/man7/tcp.7.html

Since Linux 2.4, Linux supports the use of MSG_TRUNC in the flags argument of recv(2) (and recvmsg(2)). This flag causes the received bytes of data to be discarded, rather than passed back in a caller-supplied buffer. Since Linux 2.4.4, MSG_TRUNC also has this effect when used in conjunction with MSG_OOB to receive out-of-band data.

use std::{
    io::Write,
    mem::MaybeUninit,
    net::{TcpListener, TcpStream},
    thread,
    time::Duration,
};

use rustix::{self, net::RecvFlags};

fn main() -> eyre::Result<()> {
    thread::spawn(|| -> eyre::Result<()> {
        let l = TcpListener::bind("127.0.0.1:1234")?;
        let mut c = l.accept()?.0;
        c.write_all(&[0; 128])?;
        Ok(())
    });
    thread::sleep(Duration::from_millis(100));

    let s = TcpStream::connect("127.0.0.1:1234")?;
    let mut stack = [MaybeUninit::uninit(); 128];
    let stack = rustix::net::recv(s, &mut stack, RecvFlags::TRUNC)?.0.0;
    println!("{stack:?}");
    assert!(stack != [0; 128] && stack.len() == 128);
    Ok(())
}

(rustix::net is configured out on the playground)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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