Skip to content

stdlib incorrectly handles O_PATH #62314

Closed
@cyphar

Description

@cyphar

There are several bugs here, but they all stem from the same problem -- the stdlib doesn't handle O_PATH correctly in a few places.

O_PATH requires you to set an extra (unused) mode.

O_PATH causes most other flags to be ignored, so requiring a mode is a little bit weird. Really, O_PATH should probably be handled as another OpenOptions mode.

let file = OpenOptions::new().custom_flags(libc::O_PATH).open(".")?; // gives EINVAL

This one can be worked around pretty trivially (though it is a bit silly in my view), but unfortunately that's when you hit the next issue:

Rust uses ioctl(FIOCLEX) to set close-on-exec.

This doesn't work with O_PATH because O_PATH file descriptors have empty_fops which means that all ioctl(2)s on them fail (this is a security feature).

Rust proactively sets close-on-exec in many different places, which means that any method that ends up triggering an FIOCLEX gives a spurrious EBADF. The most obvious problem is with File::try_clone() but I'm sure there are plenty of other examples:

let file = OpenOptions::new().read(true).custom_flags(libc::O_PATH).open(".")?;
let new_file = file.try_clone()?; // gives EBADF

Rust really should use fcntl(F_SETFD) because ioctl(2)s are blocked on all O_PATH descriptors (while fcntl works without issue).

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