Skip to content

Commit edf4a86

Browse files
DaanDeMeyerbluca
authored andcommitted
fd-util: Use /proc/pid/fd instead of /proc/self/fd
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) (cherry picked from commit 8046167)
1 parent 299e6cd commit edf4a86

File tree

2 files changed

+18
-8
lines changed

2 files changed

+18
-8
lines changed

src/basic/fd-util.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <sys/socket.h>
88

99
#include "macro.h"
10+
#include "format-util.h"
11+
#include "process-util.h"
1012
#include "stdio-util.h"
1113

1214
/* maximum length of fdname */
@@ -107,14 +109,17 @@ int fd_reopen_condition(int fd, int flags, int mask, int *ret_new_fd);
107109
int read_nr_open(void);
108110
int fd_get_diskseq(int fd, uint64_t *ret);
109111

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

114119
static inline char *format_proc_fd_path(char buf[static PROC_FD_PATH_MAX], int fd) {
115120
assert(buf);
116121
assert(fd >= 0);
117-
assert_se(snprintf_ok(buf, PROC_FD_PATH_MAX, "/proc/self/fd/%i", fd));
122+
assert_se(snprintf_ok(buf, PROC_FD_PATH_MAX, "/proc/" PID_FMT "/fd/%i", getpid_cached(), fd));
118123
return buf;
119124
}
120125

src/test/test-fd-util.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -382,11 +382,16 @@ TEST(close_all_fds) {
382382
}
383383

384384
TEST(format_proc_fd_path) {
385-
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(0), "/proc/self/fd/0"));
386-
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(1), "/proc/self/fd/1"));
387-
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(2), "/proc/self/fd/2"));
388-
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(3), "/proc/self/fd/3"));
389-
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(2147483647), "/proc/self/fd/2147483647"));
385+
_cleanup_free_ char *expected = NULL;
386+
387+
for (int i = 0; i < 4; i++) {
388+
assert_se(asprintf(&expected, "/proc/" PID_FMT "/fd/%i", getpid_cached(), i) >= 0);
389+
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(i), expected));
390+
expected = mfree(expected);
391+
}
392+
393+
assert_se(asprintf(&expected, "/proc/" PID_FMT "/fd/2147483647", getpid_cached()) >= 0);
394+
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(2147483647), expected));
390395
}
391396

392397
TEST(fd_reopen) {

0 commit comments

Comments
 (0)