From 05475b8318550618dd76d6ab4694e2110d0b5710 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Wed, 16 Nov 2016 11:09:01 +0200 Subject: [PATCH] lib: Make sure stdin/stdout/stderr have fd at startup and keep /dev/null always open This guarantees we will always have a fd that can be used as /dev/null. It works even inside chroots. --- src/lib/lib.c | 24 ++++++++++++++++++++++++ src/lib/lib.h | 4 ++++ 2 files changed, 28 insertions(+) diff --git a/src/lib/lib.c b/src/lib/lib.c index b0a4b63c32..c1605cad8c 100644 --- a/src/lib/lib.c +++ b/src/lib/lib.c @@ -4,13 +4,16 @@ #include "array.h" #include "env-util.h" #include "hostpid.h" +#include "fd-close-on-exec.h" #include "ipwd.h" #include "process-title.h" +#include #include #include static bool lib_initialized = FALSE; +int dev_null_fd = -1; struct atexit_callback { int priority; @@ -115,6 +118,24 @@ void lib_atexit_run(void) } } +static void lib_open_non_stdio_dev_null(void) +{ + dev_null_fd = open("/dev/null", O_WRONLY); + if (dev_null_fd == -1) + i_fatal("open(/dev/null) failed: %m"); + /* Make sure stdin, stdout and stderr fds exist. We especially rely on + stderr being available and a lot of code doesn't like fd being 0. + We'll open /dev/null as write-only also for stdin, since if any + reads are attempted from it we'll want them to fail. */ + while (dev_null_fd < STDERR_FILENO) { + dev_null_fd = dup(dev_null_fd); + if (dev_null_fd == -1) + i_fatal("dup(/dev/null) failed: %m"); + } + /* close the actual /dev/null fd on exec*(), but keep it in stdio fds */ + fd_close_on_exec(dev_null_fd, TRUE); +} + void lib_init(void) { struct timeval tv; @@ -127,6 +148,8 @@ void lib_init(void) data_stack_init(); hostpid_init(); + lib_open_non_stdio_dev_null(); + lib_initialized = TRUE; } @@ -142,6 +165,7 @@ void lib_deinit(void) lib_atexit_run(); ipwd_deinit(); hostpid_deinit(); + i_close_fd(&dev_null_fd); data_stack_deinit(); env_deinit(); failures_deinit(); diff --git a/src/lib/lib.h b/src/lib/lib.h index 9a2eea9326..1581924759 100644 --- a/src/lib/lib.h +++ b/src/lib/lib.h @@ -49,6 +49,10 @@ typedef void lib_atexit_callback_t(void); #define LIB_ATEXIT_PRIORITY_DEFAULT 0 #define LIB_ATEXIT_PRIORITY_LOW 10 +/* /dev/null opened as O_WRONLY. Opened at lib_init(), so it can be accessed + also inside chroots. */ +extern int dev_null_fd; + int close_keep_errno(int *fd); /* Call unlink(). If it fails, log an error including the source filename and line number. */