Skip to content

Commit

Permalink
fd-util: Use /proc/pid/fd instead of /proc/self/fd
Browse files Browse the repository at this point in the history
Currently, we mount via file descriptors using /proc/self/fd. This
works, but it means that in /proc/mounts and various other files,
the source of the mount will be listed as /proc/self/fd/xxx. For other
software that parses these files, /proc/self/fd/xxx doesn't mean anything,
or worse, it means the completely wrong thing, as it will refer to one of
their own file descriptors instead.

Let's improve the situation by using /proc/pid/fd instead. This allows
processes parsing /proc/mounts to do the right thing more often than not.
One scenario where even this doesn't work if when containers are involved,
as with the pid namespace unshared, even /proc/pid/fd will mean the wrong
thing, but it's no worse than /proc/self/fd which will always means the wrong
thing.

This also doesn't work if we mount via file descriptor and then exit, as the pid will
be gone, but it does work as long as the process that did the mount is alive, which
makes it useful for systemd-dissect --with for example if the program we run in the
image wants to parse /proc/mounts.

(cherry picked from commit 4419735)
  • Loading branch information
DaanDeMeyer authored and keszybz committed Sep 6, 2023
1 parent 49a3ecd commit 8046167
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 8 deletions.
11 changes: 8 additions & 3 deletions src/basic/fd-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include <sys/socket.h>

#include "macro.h"
#include "format-util.h"
#include "process-util.h"
#include "stdio-util.h"

/* maximum length of fdname */
Expand Down Expand Up @@ -112,14 +114,17 @@ static inline int dir_fd_is_root_or_cwd(int dir_fd) {
return dir_fd == AT_FDCWD ? true : path_is_root_at(dir_fd, NULL);
}

/* The maximum length a buffer for a /proc/self/fd/<fd> path needs */
/* The maximum length a buffer for a /proc/<pid>/fd/<fd> path needs. We intentionally don't use /proc/self/fd
* as these paths might be read by other programs (for example when mounting file descriptors the source path
* ends up in /proc/mounts and related files) for which /proc/self/fd will be interpreted differently than
* /proc/<pid>/fd. */
#define PROC_FD_PATH_MAX \
(STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int))
(STRLEN("/proc//fd/") + DECIMAL_STR_MAX(pid_t) + DECIMAL_STR_MAX(int))

static inline char *format_proc_fd_path(char buf[static PROC_FD_PATH_MAX], int fd) {
assert(buf);
assert(fd >= 0);
assert_se(snprintf_ok(buf, PROC_FD_PATH_MAX, "/proc/self/fd/%i", fd));
assert_se(snprintf_ok(buf, PROC_FD_PATH_MAX, "/proc/" PID_FMT "/fd/%i", getpid_cached(), fd));
return buf;
}

Expand Down
15 changes: 10 additions & 5 deletions src/test/test-fd-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -382,11 +382,16 @@ TEST(close_all_fds) {
}

TEST(format_proc_fd_path) {
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(0), "/proc/self/fd/0"));
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(1), "/proc/self/fd/1"));
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(2), "/proc/self/fd/2"));
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(3), "/proc/self/fd/3"));
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(2147483647), "/proc/self/fd/2147483647"));
_cleanup_free_ char *expected = NULL;

for (int i = 0; i < 4; i++) {
assert_se(asprintf(&expected, "/proc/" PID_FMT "/fd/%i", getpid_cached(), i) >= 0);
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(i), expected));
expected = mfree(expected);
}

assert_se(asprintf(&expected, "/proc/" PID_FMT "/fd/2147483647", getpid_cached()) >= 0);
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(2147483647), expected));
}

TEST(fd_reopen) {
Expand Down

0 comments on commit 8046167

Please sign in to comment.