chiark / gitweb /
execute: when we run as PID 1 the kernel doesn't give us CAP_SETPCAP by default....
[elogind.git] / src / execute.c
index a467411f7dab13c238a8094f480240e4b8ad7cb9..745dcfcdb8526d76c8c981546ebf756f91b99a03 100644 (file)
@@ -646,7 +646,7 @@ static int enforce_groups(const ExecContext *context, const char *username, gid_
                 char **i;
 
                 /* Final step, initialize any manually set supplementary groups */
-                ngroups_max = (int) sysconf(_SC_NGROUPS_MAX);
+                assert_se((ngroups_max = (int) sysconf(_SC_NGROUPS_MAX)) > 0);
 
                 if (!(gids = new(gid_t, ngroups_max)))
                         return -ENOMEM;
@@ -904,6 +904,68 @@ 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;
+}
+
 int exec_spawn(ExecCommand *command,
                char **argv,
                const ExecContext *context,
@@ -981,7 +1043,7 @@ int exec_spawn(ExecCommand *command,
 
                 /* This string must fit in 10 chars (i.e. the length
                  * of "/sbin/init") */
-                rename_process("sd:exec");
+                rename_process("sd.exec");
 
                 /* We reset exactly these signals, since they are the
                  * only ones we set to SIG_IGN in the main daemon. All
@@ -1106,7 +1168,8 @@ int exec_spawn(ExecCommand *command,
                                 snprintf(t, sizeof(t), "%i", adj);
                                 char_array_0(t);
 
-                                if (write_one_line_file("/proc/self/oom_adj", t) < 0) {
+                                if (write_one_line_file("/proc/self/oom_adj", t) < 0
+                                    && errno != EACCES) {
                                         r = EXIT_OOM_ADJUST;
                                         goto fail_child;
                                 }
@@ -1250,13 +1313,10 @@ int exec_spawn(ExecCommand *command,
                         }
 
                         if (context->capability_bounding_set_drop)
-                                for (i = 0; i <= CAP_LAST_CAP; i++)
-                                        if (context->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) i)) {
-                                                if (prctl(PR_CAPBSET_DROP, i) < 0) {
-                                                        r = EXIT_CAPABILITIES;
-                                                        goto fail_child;
-                                                }
-                                        }
+                                if (do_capability_bounding_set_drop(context->capability_bounding_set_drop) < 0) {
+                                        r = EXIT_CAPABILITIES;
+                                        goto fail_child;
+                                }
 
                         if (context->user)
                                 if (enforce_user(context, uid) < 0) {
@@ -1650,7 +1710,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
                 fprintf(f,
                         "%sSyslogFacility: %s\n"
                         "%sSyslogLevel: %s\n",
-                        prefix, log_facility_to_string(LOG_FAC(c->syslog_priority)),
+                        prefix, log_facility_unshifted_to_string(c->syslog_priority >> 3),
                         prefix, log_level_to_string(LOG_PRI(c->syslog_priority)));
 
         if (c->capabilities) {
@@ -1933,7 +1993,6 @@ DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
 
 static const char* const kill_mode_table[_KILL_MODE_MAX] = {
         [KILL_CONTROL_GROUP] = "control-group",
-        [KILL_PROCESS_GROUP] = "process-group",
         [KILL_PROCESS] = "process",
         [KILL_NONE] = "none"
 };