Skip to content

acceptfilter() returns dangling &CStr referencing dropped stack memory #233

@SebTardif

Description

@SebTardif

Bug

In library/std/src/sys/net/connection/socket/unix.rs (lines 524-532), the acceptfilter() method returns a &CStr that references stack-local memory:

pub fn acceptfilter(&self) -> io::Result<&CStr> {
    let arg: libc::accept_filter_arg =
        unsafe { getsockopt(self, libc::SOL_SOCKET, libc::SO_ACCEPTFILTER)? };
    let s: &[u8] =
        unsafe { core::slice::from_raw_parts(arg.af_name.as_ptr() as *const u8, 16) };
    let name = CStr::from_bytes_with_nul(s).unwrap();
    Ok(name)
}

arg is a stack-local accept_filter_arg. The from_raw_parts creates a slice borrowing arg.af_name on the stack. The returned &CStr has its lifetime tied to &self, but the data it points to is dropped when the function returns. This is a use-after-free.

Impact

Any program calling .acceptfilter() on a TcpListener on FreeBSD/NetBSD reads freed stack memory, producing garbage or crashing. Behind unstable feature gate acceptfilter (issue rust-lang#121891).

Fix

Return an owned CString instead of &CStr:

pub fn acceptfilter(&self) -> io::Result<CString> {
    let arg: libc::accept_filter_arg =
        unsafe { getsockopt(self, libc::SOL_SOCKET, libc::SO_ACCEPTFILTER)? };
    let s: &[u8] =
        unsafe { core::slice::from_raw_parts(arg.af_name.as_ptr() as *const u8, 16) };
    let name = CStr::from_bytes_with_nul(s).unwrap();
    Ok(name.to_owned())
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-netNetworking (TCP, UDP, sockets)I-unsoundUndefined behavior or soundness issueO-freebsdFreeBSD / NetBSDP-highHigh impact: affects correctness on common paths

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions