diff options
-rw-r--r-- | src/basic/fd-util.c | 37 | ||||
-rw-r--r-- | src/basic/fd-util.h | 2 | ||||
-rw-r--r-- | src/basic/log.c | 9 | ||||
-rw-r--r-- | src/libelogind/sd-bus/bus-container.c | 2 | ||||
-rw-r--r-- | src/libelogind/sd-bus/bus-socket.c | 12 | ||||
-rw-r--r-- | src/libelogind/sd-event/sd-event.c | 6 | ||||
-rw-r--r-- | src/test/test-fd-util.c | 19 |
7 files changed, 79 insertions, 8 deletions
diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c index 3e882287c..8eb65312a 100644 --- a/src/basic/fd-util.c +++ b/src/basic/fd-util.c @@ -582,3 +582,40 @@ try_dev_shm_without_o_tmpfile: return -EOPNOTSUPP; } + +int fd_move_above_stdio(int fd) { + int flags, copy; + PROTECT_ERRNO; + + /* Moves the specified file descriptor if possible out of the range [0…2], i.e. the range of + * stdin/stdout/stderr. If it can't be moved outside of this range the original file descriptor is + * returned. This call is supposed to be used for long-lasting file descriptors we allocate in our code that + * might get loaded into foreign code, and where we want ensure our fds are unlikely used accidentally as + * stdin/stdout/stderr of unrelated code. + * + * Note that this doesn't fix any real bugs, it just makes it less likely that our code will be affected by + * buggy code from others that mindlessly invokes 'fprintf(stderr, …' or similar in places where stderr has + * been closed before. + * + * This function is written in a "best-effort" and "least-impact" style. This means whenever we encounter an + * error we simply return the original file descriptor, and we do not touch errno. */ + + if (fd < 0 || fd > 2) + return fd; + + flags = fcntl(fd, F_GETFD, 0); + if (flags < 0) + return fd; + + if (flags & FD_CLOEXEC) + copy = fcntl(fd, F_DUPFD_CLOEXEC, 3); + else + copy = fcntl(fd, F_DUPFD, 3); + if (copy < 0) + return fd; + + assert(copy > 2); + + (void) close(fd); + return copy; +} diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h index eeded4417..6a9006421 100644 --- a/src/basic/fd-util.h +++ b/src/basic/fd-util.h @@ -95,3 +95,5 @@ int acquire_data_fd(const void *data, size_t size, unsigned flags); /* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */ #define ERRNO_IS_DISCONNECT(r) \ IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH) + +int fd_move_above_stdio(int fd); diff --git a/src/basic/log.c b/src/basic/log.c index cb4689cef..3963e0371 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -107,6 +107,8 @@ static int log_open_console(void) { console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); if (console_fd < 0) return console_fd; + + console_fd = fd_move_above_stdio(console_fd); } return 0; @@ -125,6 +127,7 @@ static int log_open_kmsg(void) { if (kmsg_fd < 0) return -errno; + kmsg_fd = fd_move_above_stdio(kmsg_fd); return 0; } @@ -140,11 +143,11 @@ static int create_log_socket(int type) { if (fd < 0) return -errno; + fd = fd_move_above_stdio(fd); (void) fd_inc_sndbuf(fd, SNDBUF_SIZE); - /* We need a blocking fd here since we'd otherwise lose - messages way too early. However, let's not hang forever in the - unlikely case of a deadlock. */ + /* We need a blocking fd here since we'd otherwise lose messages way too early. However, let's not hang forever + * in the unlikely case of a deadlock. */ if (getpid_cached() == 1) timeval_store(&tv, 10 * USEC_PER_MSEC); else diff --git a/src/libelogind/sd-bus/bus-container.c b/src/libelogind/sd-bus/bus-container.c index 16156d882..477f7053e 100644 --- a/src/libelogind/sd-bus/bus-container.c +++ b/src/libelogind/sd-bus/bus-container.c @@ -54,6 +54,8 @@ int bus_container_connect_socket(sd_bus *b) { if (b->input_fd < 0) return -errno; + b->input_fd = fd_move_above_stdio(b->input_fd); + b->output_fd = b->input_fd; bus_socket_setup(b); diff --git a/src/libelogind/sd-bus/bus-socket.c b/src/libelogind/sd-bus/bus-socket.c index 348f71580..4890895bc 100644 --- a/src/libelogind/sd-bus/bus-socket.c +++ b/src/libelogind/sd-bus/bus-socket.c @@ -713,6 +713,8 @@ static int bus_socket_inotify_setup(sd_bus *b) { b->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC); if (b->inotify_fd < 0) return -errno; + + b->inotify_fd = fd_move_above_stdio(b->inotify_fd); } /* Make sure the path is NUL terminated */ @@ -879,6 +881,8 @@ int bus_socket_connect(sd_bus *b) { if (b->input_fd < 0) return -errno; + b->input_fd = fd_move_above_stdio(b->input_fd); + b->output_fd = b->input_fd; bus_socket_setup(b); @@ -978,7 +982,7 @@ int bus_socket_exec(sd_bus *b) { } safe_close(s[1]); - b->output_fd = b->input_fd = s[0]; + b->output_fd = b->input_fd = fd_move_above_stdio(s[0]); bus_socket_setup(b); @@ -1206,7 +1210,7 @@ int bus_socket_read_message(sd_bus *bus) { CMSG_FOREACH(cmsg, &mh) if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - int n, *f; + int n, *f, i; n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); @@ -1225,9 +1229,9 @@ int bus_socket_read_message(sd_bus *bus) { return -ENOMEM; } - memcpy_safe(f + bus->n_fds, CMSG_DATA(cmsg), n * sizeof(int)); + for (i = 0; i < n; i++) + f[bus->n_fds++] = fd_move_above_stdio(((int*) CMSG_DATA(cmsg))[i]); bus->fds = f; - bus->n_fds += n; } else log_debug("Got unexpected auxiliary data with level=%d and type=%d", cmsg->cmsg_level, cmsg->cmsg_type); diff --git a/src/libelogind/sd-event/sd-event.c b/src/libelogind/sd-event/sd-event.c index cb9b3a454..7355921d3 100644 --- a/src/libelogind/sd-event/sd-event.c +++ b/src/libelogind/sd-event/sd-event.c @@ -457,6 +457,8 @@ _public_ int sd_event_new(sd_event** ret) { goto fail; } + e->epoll_fd = fd_move_above_stdio(e->epoll_fd); + if (secure_getenv("SD_EVENT_PROFILE_DELAYS")) { log_debug("Event loop profiling enabled. Logarithmic histogram of event loop iterations in the range 2^0 ... 2^63 us will be logged every 5s."); e->profile_delays = true; @@ -695,7 +697,7 @@ static int event_make_signal_data( return 0; } - d->fd = r; + d->fd = fd_move_above_stdio(r); ev.events = EPOLLIN; ev.data.ptr = d; @@ -1045,6 +1047,8 @@ static int event_setup_timer_fd( if (fd < 0) return -errno; + fd = fd_move_above_stdio(fd); + ev.events = EPOLLIN; ev.data.ptr = d; diff --git a/src/test/test-fd-util.c b/src/test/test-fd-util.c index 6b611b4b9..76b36053b 100644 --- a/src/test/test-fd-util.c +++ b/src/test/test-fd-util.c @@ -157,6 +157,24 @@ static void test_acquire_data_fd(void) { test_acquire_data_fd_one(ACQUIRE_NO_DEV_NULL|ACQUIRE_NO_MEMFD|ACQUIRE_NO_PIPE|ACQUIRE_NO_TMPFILE); } +static void test_fd_move_above_stdio(void) { + int original_stdin, new_fd; + + original_stdin = fcntl(0, F_DUPFD, 3); + assert_se(original_stdin >= 3); + assert_se(close_nointr(0) != EBADF); + + new_fd = open("/dev/null", O_RDONLY); + assert_se(new_fd == 0); + + new_fd = fd_move_above_stdio(new_fd); + assert_se(new_fd >= 3); + + assert_se(dup(original_stdin) == 0); + assert_se(close_nointr(original_stdin) != EBADF); + assert_se(close_nointr(new_fd) != EBADF); +} + int main(int argc, char *argv[]) { test_close_many(); test_close_nointr(); @@ -165,6 +183,7 @@ int main(int argc, char *argv[]) { #endif // 0 test_open_serialization_fd(); test_acquire_data_fd(); + test_fd_move_above_stdio(); return 0; } |