summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/basic/fd-util.c37
-rw-r--r--src/basic/fd-util.h2
-rw-r--r--src/basic/log.c9
-rw-r--r--src/libelogind/sd-bus/bus-container.c2
-rw-r--r--src/libelogind/sd-bus/bus-socket.c12
-rw-r--r--src/libelogind/sd-event/sd-event.c6
-rw-r--r--src/test/test-fd-util.c19
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;
}