chiark / gitweb /
silence gcc warning on 32 bit
[elogind.git] / src / core / execute.c
index 271c57f562186974fcde25e0c76b5afb99a8c5b8..bbc430e0556d685e79a6188edfeb257d3ceb328e 100644 (file)
@@ -37,6 +37,7 @@
 #include <sys/mount.h>
 #include <linux/fs.h>
 #include <linux/oom.h>
+#include <sys/poll.h>
 
 #ifdef HAVE_PAM
 #include <security/pam_appl.h>
@@ -58,6 +59,9 @@
 #include "utmp-wtmp.h"
 #include "def.h"
 #include "loopback-setup.h"
+#include "path-util.h"
+
+#define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC)
 
 /* This assumes there is a 'tty' group */
 #define TTY_MODE 0620
@@ -701,6 +705,7 @@ static int null_conv(
 static int setup_pam(
                 const char *name,
                 const char *user,
+                uid_t uid,
                 const char *tty,
                 char ***pam_env,
                 int fds[], unsigned n_fds) {
@@ -779,10 +784,17 @@ static int setup_pam(
                 open here that have been opened by PAM. */
                 close_many(fds, n_fds);
 
-                /* Wait until our parent died. This will most likely
-                 * not work since the kernel does not allow
-                 * unprivileged parents kill their privileged children
-                 * this way. We rely on the control groups kill logic
+                /* Drop privileges - we don't need any to pam_close_session
+                 * and this will make PR_SET_PDEATHSIG work in most cases.
+                 * If this fails, ignore the error - but expect sd-pam threads
+                 * to fail to exit normally */
+                if (setresuid(uid, uid, uid) < 0)
+                        log_error("Error: Failed to setresuid() in sd-pam: %s", strerror(-r));
+
+                /* Wait until our parent died. This will only work if
+                 * the above setresuid() succeeds, otherwise the kernel
+                 * will not allow unprivileged parents kill their privileged
+                 * children this way. We rely on the control groups kill logic
                  * to do the rest for us. */
                 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
                         goto child_finish;
@@ -858,68 +870,6 @@ fail:
 }
 #endif
 
-static int do_capability_bounding_set_drop(uint64_t drop) {
-        unsigned long i;
-        cap_t old_cap = NULL, new_cap = NULL;
-        cap_flag_value_t fv;
-        int r;
-
-        /* If we are run as PID 1 we will lack CAP_SETPCAP by default
-         * in the effective set (yes, the kernel drops that when
-         * executing init!), so get it back temporarily so that we can
-         * call PR_CAPBSET_DROP. */
-
-        old_cap = cap_get_proc();
-        if (!old_cap)
-                return -errno;
-
-        if (cap_get_flag(old_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0) {
-                r = -errno;
-                goto finish;
-        }
-
-        if (fv != CAP_SET) {
-                static const cap_value_t v = CAP_SETPCAP;
-
-                new_cap = cap_dup(old_cap);
-                if (!new_cap) {
-                        r = -errno;
-                        goto finish;
-                }
-
-                if (cap_set_flag(new_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0) {
-                        r = -errno;
-                        goto finish;
-                }
-
-                if (cap_set_proc(new_cap) < 0) {
-                        r = -errno;
-                        goto finish;
-                }
-        }
-
-        for (i = 0; i <= cap_last_cap(); i++)
-                if (drop & ((uint64_t) 1ULL << (uint64_t) i)) {
-                        if (prctl(PR_CAPBSET_DROP, i) < 0) {
-                                r = -errno;
-                                goto finish;
-                        }
-                }
-
-        r = 0;
-
-finish:
-        if (new_cap)
-                cap_free(new_cap);
-
-        if (old_cap) {
-                cap_set_proc(old_cap);
-                cap_free(old_cap);
-        }
-
-        return r;
-}
-
 static void rename_process_from_path(const char *path) {
         char process_name[11];
         const char *p;
@@ -928,7 +878,7 @@ static void rename_process_from_path(const char *path) {
         /* This resulting string must fit in 10 chars (i.e. the length
          * of "/sbin/init") to look pretty in /bin/ps */
 
-        p = file_name_from_path(path);
+        p = path_get_file_name(path);
         if (isempty(p)) {
                 rename_process("(...)");
                 return;
@@ -962,6 +912,8 @@ int exec_spawn(ExecCommand *command,
                bool confirm_spawn,
                CGroupBonding *cgroup_bondings,
                CGroupAttribute *cgroup_attributes,
+               const char *cgroup_suffix,
+               int idle_pipe[2],
                pid_t *ret) {
 
         pid_t pid;
@@ -1049,6 +1001,15 @@ int exec_spawn(ExecCommand *command,
                         goto fail_child;
                 }
 
+                if (idle_pipe) {
+                        if (idle_pipe[1] >= 0)
+                                close_nointr_nofail(idle_pipe[1]);
+                        if (idle_pipe[0] >= 0) {
+                                fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT_USEC);
+                                close_nointr_nofail(idle_pipe[0]);
+                        }
+                }
+
                 /* Close sockets very early to make sure we don't
                  * block init reexecution because it cannot bind its
                  * sockets */
@@ -1140,21 +1101,21 @@ int exec_spawn(ExecCommand *command,
                 }
 
                 if (!keep_stdout) {
-                        err = setup_output(context, socket_fd, file_name_from_path(command->path), apply_tty_stdin);
+                        err = setup_output(context, socket_fd, path_get_file_name(command->path), apply_tty_stdin);
                         if (err < 0) {
                                 r = EXIT_STDOUT;
                                 goto fail_child;
                         }
                 }
 
-                err = setup_error(context, socket_fd, file_name_from_path(command->path), apply_tty_stdin);
+                err = setup_error(context, socket_fd, path_get_file_name(command->path), apply_tty_stdin);
                 if (err < 0) {
                         r = EXIT_STDERR;
                         goto fail_child;
                 }
 
                 if (cgroup_bondings) {
-                        err = cgroup_bonding_install_list(cgroup_bondings, 0);
+                        err = cgroup_bonding_install_list(cgroup_bondings, 0, cgroup_suffix);
                         if (err < 0) {
                                 r = EXIT_CGROUP;
                                 goto fail_child;
@@ -1168,22 +1129,9 @@ int exec_spawn(ExecCommand *command,
                         char_array_0(t);
 
                         if (write_one_line_file("/proc/self/oom_score_adj", t) < 0) {
-                                /* Compatibility with Linux <= 2.6.35 */
-
-                                int adj;
-
-                                adj = (context->oom_score_adjust * -OOM_DISABLE) / OOM_SCORE_ADJ_MAX;
-                                adj = CLAMP(adj, OOM_DISABLE, OOM_ADJUST_MAX);
-
-                                snprintf(t, sizeof(t), "%i", adj);
-                                char_array_0(t);
-
-                                if (write_one_line_file("/proc/self/oom_adj", t) < 0
-                                    && errno != EACCES) {
-                                        err = -errno;
-                                        r = EXIT_OOM_ADJUST;
-                                        goto fail_child;
-                                }
+                                err = -errno;
+                                r = EXIT_OOM_ADJUST;
+                                goto fail_child;
                         }
                 }
 
@@ -1222,7 +1170,7 @@ int exec_spawn(ExecCommand *command,
                                 goto fail_child;
                         }
 
-                if (context->timer_slack_nsec_set)
+                if (context->timer_slack_nsec != (nsec_t) -1)
                         if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) {
                                 err = -errno;
                                 r = EXIT_TIMERSLACK;
@@ -1281,7 +1229,7 @@ int exec_spawn(ExecCommand *command,
 
 #ifdef HAVE_PAM
                 if (context->pam_name && username) {
-                        err = setup_pam(context->pam_name, username, context->tty_path, &pam_env, fds, n_fds);
+                        err = setup_pam(context->pam_name, username, uid, context->tty_path, &pam_env, fds, n_fds);
                         if (err < 0) {
                                 r = EXIT_PAM;
                                 goto fail_child;
@@ -1375,7 +1323,7 @@ int exec_spawn(ExecCommand *command,
                         }
 
                         if (context->capability_bounding_set_drop) {
-                                err = do_capability_bounding_set_drop(context->capability_bounding_set_drop);
+                                err = capability_bounding_set_drop(context->capability_bounding_set_drop, false);
                                 if (err < 0) {
                                         r = EXIT_CAPABILITIES;
                                         goto fail_child;
@@ -1505,7 +1453,7 @@ int exec_spawn(ExecCommand *command,
          * sure that when we kill the cgroup the process will be
          * killed too). */
         if (cgroup_bondings)
-                cgroup_bonding_install_list(cgroup_bondings, pid);
+                cgroup_bonding_install_list(cgroup_bondings, pid, cgroup_suffix);
 
         log_debug("Forked %s as %lu", command->path, (unsigned long) pid);
 
@@ -1533,6 +1481,7 @@ void exec_context_init(ExecContext *c) {
         c->send_sigkill = true;
         c->control_group_persistent = -1;
         c->ignore_sigpipe = true;
+        c->timer_slack_nsec = (nsec_t) -1;
 }
 
 void exec_context_done(ExecContext *c) {
@@ -1778,8 +1727,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
                 fputs("\n", f);
         }
 
-        if (c->timer_slack_nsec_set)
-                fprintf(f, "%sTimerSlackNSec: %lu\n", prefix, c->timer_slack_nsec);
+        if (c->timer_slack_nsec != (nsec_t) -1)
+                fprintf(f, "%sTimerSlackNSec: %lu\n", prefix, (unsigned long)c->timer_slack_nsec);
 
         fprintf(f,
                 "%sStandardInput: %s\n"