Rust: current_exe() returns invalid path on linux when exe has been deleted

Created on 21 Feb 2020  路  12Comments  路  Source: rust-lang/rust

Calling current_exe() on linux after the original executable has been deleted or replaced results in an invalid path being returned.

fn main() {
    // current_exe = /path/to/executable
    remove_file(current_exe().unwrap()).ok();
    println!("{:?}", current_exe());
}

Output

Ok("/path/to/executable (deleted)")

Desired behavior

While it is the correct behavior of the underlying /proc/self/exe to append the string (deleted) to the original pathname the result is not a valid path and might even end up pointing to a completely different file.

I would either expect the docs to explicitly mention this behavior or classify it as an error and return io::ErrorKind::NotFound accordingly.

Meta

rustc --version --verbose:

rustc 1.41.0 (5e1a79984 2020-01-27)
binary: rustc
commit-hash: 5e1a799842ba6ed4a57e91f7ab9435947482f7d8
commit-date: 2020-01-27
host: x86_64-unknown-linux-gnu
release: 1.41.0
LLVM version: 9.0

I would gladly claim this issue if you agree to it.

C-bug O-linux T-libs

Most helpful comment

That won't work if you pass the result of current_exe to another process and then exit.

All 12 comments

Since (deleted) is a valid unix path it would take extra syscalls to check if it actually exists. Additionally there are other cases where /proc/self/exe may point to something that's not accessible, e.g. when mount namespaces or chroot are in play or when a process was launched via memfd_create + fexecve.

So it probably needs a doc update. In the case of mount namespaces this might also be subject to confusion attacks, so this value generally shouldn't be given too much trust.

Rather than simply checking for " (deleted)", it makes more sense to open and stat /proc/self/exe and the path returned. If the inos are different, then the currently running binary isn't the same as the one at the path (it's been replaced or deleted) and an error should be returned.

IMHO. This doesn't explicitly go against the docs on current_exe and I think it'd be good to support that behaviour.

Isn't it Linux only?

While current_exe() might return all kinds of different paths caused by symlinks or mounts it should return something that points to the executable even if you might not have the permissions to access it.

But /path/to/exe (deleted) has at no point in time been the correct path for the executable and should thus be considered an error. In the end it comes down to how the libraries subteam wants to handle this.

Rather than simply checking for " (deleted)", it makes more sense to open and stat /proc/self/exe and the path returned. If the inos are different, then the currently running binary isn't the same as the one at the path

Does /proc/<pid>/exe have similar magical properties to /proc/<pid>/fd/*?

Isn't it Linux only?

Does /proc/<pid>/exe have similar magical properties to /proc/<pid>/fd/*?

Yes and yes.

Then another option is to simply return the symlink itself instead of the target. At least as a fallback.

After all it may be the only existing reference to an inode, e.g. in the mem_fd case

That won't work if you pass the result of current_exe to another process and then exit.

If that symlink was the last reference to the inode then it will never work. So if it's just a fallback you don't lose anything.

Returning the symlink itself would be a bad idea, even if /proc/<ID>/fd was returned:

  • Debugging purpose would break
  • Calculating parent directory would break
  • Even if the program doesn't exist, giving /proc/self/exe to another program would cause that other program to point to itself.

Even if the program doesn't exist, giving /proc/self/exe to another program would cause that other program to point to itself.

You would pass /proc/<pid>/exe which is valid for the lifetime of the program.

But yes, all of these are workarounds with their own limitations. The proper solution is, at least on linux, to pass around file descriptors which are valid for their whole existence.

As i mentioned in the other thread, it may be worth just deprecating this API in favour of another crate which offers multiple options with different guarantees.

Was this page helpful?
0 / 5 - 0 ratings