chiark / gitweb /
main: run crash shell as subprocess, so that we can gdb pid 1
[elogind.git] / execute.c
index 5264b5009e73c919162d06c6e614e637f17f0337..5ac5eefd33150f2c16cd172d25ad65963ae16592 100644 (file)
--- a/execute.c
+++ b/execute.c
@@ -44,6 +44,9 @@
 #include "securebits.h"
 #include "cgroup.h"
 
+/* This assumes there is a 'tty' group */
+#define TTY_MODE 0620
+
 static int shift_fds(int fds[], unsigned n_fds) {
         int start, restart_from;
 
@@ -70,7 +73,7 @@ static int shift_fds(int fds[], unsigned n_fds) {
                         if ((nfd = fcntl(fds[i], F_DUPFD, i+3)) < 0)
                                 return -errno;
 
-                        assert_se(close_nointr(fds[i]) == 0);
+                        close_nointr_nofail(fds[i]);
                         fds[i] = nfd;
 
                         /* Hmm, the fd we wanted isn't free? Then
@@ -134,7 +137,7 @@ static int open_null_as(int flags, int nfd) {
 
         if (fd != nfd) {
                 r = dup2(fd, nfd) < 0 ? -errno : nfd;
-                close_nointr(fd);
+                close_nointr_nofail(fd);
         } else
                 r = nfd;
 
@@ -188,7 +191,7 @@ static int connect_logger_as(const ExecContext *context, ExecOutput output, cons
 
         if (fd != nfd) {
                 r = dup2(fd, nfd) < 0 ? -errno : nfd;
-                close_nointr(fd);
+                close_nointr_nofail(fd);
         } else
                 r = nfd;
 
@@ -290,6 +293,7 @@ static int setup_output(const ExecContext *context, const char *ident) {
 
 static int setup_error(const ExecContext *context, const char *ident) {
         assert(context);
+        assert(ident);
 
         /* This expects the input and output are already set up */
 
@@ -326,6 +330,25 @@ static int setup_error(const ExecContext *context, const char *ident) {
         }
 }
 
+static int chown_terminal(int fd, uid_t uid) {
+        struct stat st;
+
+        assert(fd >= 0);
+
+        /* This might fail. What matters are the results. */
+        fchown(fd, uid, -1);
+        fchmod(fd, TTY_MODE);
+
+        if (fstat(fd, &st) < 0)
+                return -errno;
+
+        if (st.st_uid != uid ||
+            st.st_mode != TTY_MODE)
+                return -EPERM;
+
+        return 0;
+}
+
 static int setup_confirm_stdio(const ExecContext *context,
                                int *_saved_stdin,
                                int *_saved_stdout) {
@@ -354,6 +377,11 @@ static int setup_confirm_stdio(const ExecContext *context,
                 goto fail;
         }
 
+        if (chown_terminal(fd, getuid()) < 0) {
+                r = EXIT_STDIN;
+                goto fail;
+        }
+
         if (dup2(fd, STDIN_FILENO) < 0) {
                 r = EXIT_STDIN;
                 goto fail;
@@ -814,6 +842,12 @@ int exec_spawn(ExecCommand *command,
                                 goto fail;
                         }
 
+                if (is_terminal_input(context->std_input))
+                        if (chown_terminal(STDIN_FILENO, uid) < 0) {
+                                r = EXIT_STDIN;
+                                goto fail;
+                        }
+
                 if (apply_chroot) {
                         if (context->root_directory)
                                 if (chroot(context->root_directory) < 0) {