]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/execute.c
Merge pull request #29630 from DaanDeMeyer/manager-json
[thirdparty/systemd.git] / src / core / execute.c
index 06fcc741f87bbb070b71f597cac1746592c5c226..33adcd89f0da952b90dbdfe50755efb75c9b21bc 100644 (file)
@@ -25,6 +25,7 @@
 #include "cgroup-setup.h"
 #include "constants.h"
 #include "cpu-set-util.h"
+#include "dev-setup.h"
 #include "env-file.h"
 #include "env-util.h"
 #include "errno-list.h"
@@ -106,29 +107,28 @@ int exec_context_tty_size(const ExecContext *context, unsigned *ret_rows, unsign
 }
 
 void exec_context_tty_reset(const ExecContext *context, const ExecParameters *p) {
-        _cleanup_close_ int fd = -EBADF;
+        _cleanup_close_ int _fd = -EBADF, lock_fd = -EBADF;
         const char *path = exec_context_tty_path(ASSERT_PTR(context));
+        int fd;
 
-        /* Take a lock around the device for the duration of the setup that we do here.
-         * systemd-vconsole-setup.service also takes the lock to avoid being interrupted.
-         * We open a new fd that will be closed automatically, and operate on it for convenience.
-         */
-
-        if (p && p->stdin_fd >= 0) {
-                fd = xopenat_lock(p->stdin_fd, NULL,
-                                  O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY, 0, 0, LOCK_BSD, LOCK_EX);
-                if (fd < 0)
-                        return;
-        } else if (path) {
-                fd = open_terminal(path, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
+        if (p && p->stdin_fd >= 0)
+                fd = p->stdin_fd;
+        else if (path) {
+                fd = _fd = open_terminal(path, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
                 if (fd < 0)
                         return;
-
-                if (lock_generic(fd, LOCK_BSD, LOCK_EX) < 0)
-                        return;
         } else
                 return;   /* nothing to do */
 
+        /* Take a synchronization lock for the duration of the setup that we do here.
+         * systemd-vconsole-setup.service also takes the lock to avoid being interrupted.
+         * We open a new fd that will be closed automatically, and operate on it for convenience.
+         */
+        lock_fd = lock_dev_console();
+        if (lock_fd < 0)
+                return (void) log_debug_errno(lock_fd,
+                                              "Failed to lock /dev/console: %m");
+
         if (context->tty_vhangup)
                 (void) terminal_vhangup_fd(fd);
 
@@ -1542,6 +1542,237 @@ int exec_context_get_clean_mask(ExecContext *c, ExecCleanMask *ret) {
         return 0;
 }
 
+int exec_context_get_oom_score_adjust(const ExecContext *c) {
+        int n = 0, r;
+
+        assert(c);
+
+        if (c->oom_score_adjust_set)
+                return c->oom_score_adjust;
+
+        r = get_oom_score_adjust(&n);
+        if (r < 0)
+                log_debug_errno(r, "Failed to read /proc/self/oom_score_adj, ignoring: %m");
+
+        return n;
+}
+
+uint64_t exec_context_get_coredump_filter(const ExecContext *c) {
+        _cleanup_free_ char *t = NULL;
+        uint64_t n = COREDUMP_FILTER_MASK_DEFAULT;
+        int r;
+
+        assert(c);
+
+        if (c->coredump_filter_set)
+                return c->coredump_filter;
+
+        r = read_one_line_file("/proc/self/coredump_filter", &t);
+        if (r < 0)
+                log_debug_errno(r, "Failed to read /proc/self/coredump_filter, ignoring: %m");
+        else {
+                r = safe_atoux64(t, &n);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to parse \"%s\" from /proc/self/coredump_filter, ignoring: %m", t);
+        }
+
+        return n;
+}
+
+int exec_context_get_nice(const ExecContext *c) {
+        int n;
+
+        assert(c);
+
+        if (c->nice_set)
+                return c->nice;
+
+        errno = 0;
+        n = getpriority(PRIO_PROCESS, 0);
+        if (errno > 0) {
+                log_debug_errno(errno, "Failed to get process nice value, ignoring: %m");
+                n = 0;
+        }
+
+        return n;
+}
+
+int exec_context_get_cpu_sched_policy(const ExecContext *c) {
+        int n;
+
+        assert(c);
+
+        if (c->cpu_sched_set)
+                return c->cpu_sched_policy;
+
+        n = sched_getscheduler(0);
+        if (n < 0)
+                log_debug_errno(errno, "Failed to get scheduler policy, ignoring: %m");
+
+        return n < 0 ? SCHED_OTHER : n;
+}
+
+int exec_context_get_cpu_sched_priority(const ExecContext *c) {
+        struct sched_param p = {};
+        int r;
+
+        assert(c);
+
+        if (c->cpu_sched_set)
+                return c->cpu_sched_priority;
+
+        r = sched_getparam(0, &p);
+        if (r < 0)
+                log_debug_errno(errno, "Failed to get scheduler priority, ignoring: %m");
+
+        return r >= 0 ? p.sched_priority : 0;
+}
+
+uint64_t exec_context_get_timer_slack_nsec(const ExecContext *c) {
+        int r;
+
+        assert(c);
+
+        if (c->timer_slack_nsec != NSEC_INFINITY)
+                return c->timer_slack_nsec;
+
+        r = prctl(PR_GET_TIMERSLACK);
+        if (r < 0)
+                log_debug_errno(r, "Failed to get timer slack, ignoring: %m");
+
+        return (uint64_t) MAX(r, 0);
+}
+
+char** exec_context_get_syscall_filter(const ExecContext *c) {
+        _cleanup_strv_free_ char **l = NULL;
+
+        assert(c);
+
+#if HAVE_SECCOMP
+        void *id, *val;
+        HASHMAP_FOREACH_KEY(val, id, c->syscall_filter) {
+                _cleanup_free_ char *name = NULL;
+                const char *e = NULL;
+                char *s;
+                int num = PTR_TO_INT(val);
+
+                if (c->syscall_allow_list && num >= 0)
+                        /* syscall with num >= 0 in allow-list is denied. */
+                        continue;
+
+                name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
+                if (!name)
+                        continue;
+
+                if (num >= 0) {
+                        e = seccomp_errno_or_action_to_string(num);
+                        if (e) {
+                                s = strjoin(name, ":", e);
+                                if (!s)
+                                        return NULL;
+                        } else {
+                                if (asprintf(&s, "%s:%d", name, num) < 0)
+                                        return NULL;
+                        }
+                } else
+                        s = TAKE_PTR(name);
+
+                if (strv_consume(&l, s) < 0)
+                        return NULL;
+        }
+
+        strv_sort(l);
+#endif
+
+        return l ? TAKE_PTR(l) : strv_new(NULL);
+}
+
+char** exec_context_get_syscall_archs(const ExecContext *c) {
+        _cleanup_strv_free_ char **l = NULL;
+
+        assert(c);
+
+#if HAVE_SECCOMP
+        void *id;
+        SET_FOREACH(id, c->syscall_archs) {
+                const char *name;
+
+                name = seccomp_arch_to_string(PTR_TO_UINT32(id) - 1);
+                if (!name)
+                        continue;
+
+                if (strv_extend(&l, name) < 0)
+                        return NULL;
+        }
+
+        strv_sort(l);
+#endif
+
+        return l ? TAKE_PTR(l) : strv_new(NULL);
+}
+
+char** exec_context_get_syscall_log(const ExecContext *c) {
+        _cleanup_strv_free_ char **l = NULL;
+
+        assert(c);
+
+#if HAVE_SECCOMP
+        void *id, *val;
+        HASHMAP_FOREACH_KEY(val, id, c->syscall_log) {
+                char *name = NULL;
+
+                name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
+                if (!name)
+                        continue;
+
+                if (strv_consume(&l, name) < 0)
+                        return NULL;
+        }
+
+        strv_sort(l);
+#endif
+
+        return l ? TAKE_PTR(l) : strv_new(NULL);
+}
+
+char** exec_context_get_address_families(const ExecContext *c) {
+        _cleanup_strv_free_ char **l = NULL;
+        void *af;
+
+        assert(c);
+
+        SET_FOREACH(af, c->address_families) {
+                const char *name;
+
+                name = af_to_name(PTR_TO_INT(af));
+                if (!name)
+                        continue;
+
+                if (strv_extend(&l, name) < 0)
+                        return NULL;
+        }
+
+        strv_sort(l);
+
+        return l ? TAKE_PTR(l) : strv_new(NULL);
+}
+
+char** exec_context_get_restrict_filesystems(const ExecContext *c) {
+        _cleanup_strv_free_ char **l = NULL;
+
+        assert(c);
+
+#if HAVE_LIBBPF
+        l = set_get_strv(c->restrict_filesystems);
+        if (!l)
+                return NULL;
+
+        strv_sort(l);
+#endif
+
+        return l ? TAKE_PTR(l) : strv_new(NULL);
+}
+
 void exec_status_start(ExecStatus *s, pid_t pid) {
         assert(s);
 
@@ -2002,27 +2233,18 @@ int exec_shared_runtime_deserialize_compat(Unit *u, const char *key, const char
                         return -ENOMEM;
 
         } else if (streq(key, "netns-socket-0")) {
-                int fd;
-
-                if ((fd = parse_fd(value)) < 0 || !fdset_contains(fds, fd)) {
-                        log_unit_debug(u, "Failed to parse netns socket value: %s", value);
-                        return 0;
-                }
 
                 safe_close(rt->netns_storage_socket[0]);
-                rt->netns_storage_socket[0] = fdset_remove(fds, fd);
+                rt->netns_storage_socket[0] = deserialize_fd(fds, value);
+                if (rt->netns_storage_socket[0] < 0)
+                        return 0;
 
         } else if (streq(key, "netns-socket-1")) {
-                int fd;
-
-                if ((fd = parse_fd(value)) < 0 || !fdset_contains(fds, fd)) {
-                        log_unit_debug(u, "Failed to parse netns socket value: %s", value);
-                        return 0;
-                }
 
                 safe_close(rt->netns_storage_socket[1]);
-                rt->netns_storage_socket[1] = fdset_remove(fds, fd);
-
+                rt->netns_storage_socket[1] = deserialize_fd(fds, value);
+                if (rt->netns_storage_socket[1] < 0)
+                        return 0;
         } else
                 return 0;
 
@@ -2088,13 +2310,9 @@ int exec_shared_runtime_deserialize_one(Manager *m, const char *value, FDSet *fd
                 n = strcspn(v, " ");
                 buf = strndupa_safe(v, n);
 
-                netns_fdpair[0] = parse_fd(buf);
+                netns_fdpair[0] = deserialize_fd(fds, buf);
                 if (netns_fdpair[0] < 0)
-                        return log_debug_errno(netns_fdpair[0], "Unable to parse exec-runtime specification netns-socket-0=%s: %m", buf);
-                if (!fdset_contains(fds, netns_fdpair[0]))
-                        return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
-                                               "exec-runtime specification netns-socket-0= refers to unknown fd %d: %m", netns_fdpair[0]);
-                netns_fdpair[0] = fdset_remove(fds, netns_fdpair[0]);
+                        return netns_fdpair[0];
                 if (v[n] != ' ')
                         goto finalize;
                 p = v + n + 1;
@@ -2107,13 +2325,9 @@ int exec_shared_runtime_deserialize_one(Manager *m, const char *value, FDSet *fd
                 n = strcspn(v, " ");
                 buf = strndupa_safe(v, n);
 
-                netns_fdpair[1] = parse_fd(buf);
+                netns_fdpair[1] = deserialize_fd(fds, buf);
                 if (netns_fdpair[1] < 0)
-                        return log_debug_errno(netns_fdpair[1], "Unable to parse exec-runtime specification netns-socket-1=%s: %m", buf);
-                if (!fdset_contains(fds, netns_fdpair[1]))
-                        return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
-                                               "exec-runtime specification netns-socket-1= refers to unknown fd %d: %m", netns_fdpair[1]);
-                netns_fdpair[1] = fdset_remove(fds, netns_fdpair[1]);
+                        return netns_fdpair[1];
                 if (v[n] != ' ')
                         goto finalize;
                 p = v + n + 1;
@@ -2126,13 +2340,9 @@ int exec_shared_runtime_deserialize_one(Manager *m, const char *value, FDSet *fd
                 n = strcspn(v, " ");
                 buf = strndupa_safe(v, n);
 
-                ipcns_fdpair[0] = parse_fd(buf);
+                ipcns_fdpair[0] = deserialize_fd(fds, buf);
                 if (ipcns_fdpair[0] < 0)
-                        return log_debug_errno(ipcns_fdpair[0], "Unable to parse exec-runtime specification ipcns-socket-0=%s: %m", buf);
-                if (!fdset_contains(fds, ipcns_fdpair[0]))
-                        return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
-                                               "exec-runtime specification ipcns-socket-0= refers to unknown fd %d: %m", ipcns_fdpair[0]);
-                ipcns_fdpair[0] = fdset_remove(fds, ipcns_fdpair[0]);
+                        return ipcns_fdpair[0];
                 if (v[n] != ' ')
                         goto finalize;
                 p = v + n + 1;
@@ -2145,13 +2355,9 @@ int exec_shared_runtime_deserialize_one(Manager *m, const char *value, FDSet *fd
                 n = strcspn(v, " ");
                 buf = strndupa_safe(v, n);
 
-                ipcns_fdpair[1] = parse_fd(buf);
+                ipcns_fdpair[1] = deserialize_fd(fds, buf);
                 if (ipcns_fdpair[1] < 0)
-                        return log_debug_errno(ipcns_fdpair[1], "Unable to parse exec-runtime specification ipcns-socket-1=%s: %m", buf);
-                if (!fdset_contains(fds, ipcns_fdpair[1]))
-                        return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
-                                               "exec-runtime specification ipcns-socket-1= refers to unknown fd %d: %m", ipcns_fdpair[1]);
-                ipcns_fdpair[1] = fdset_remove(fds, ipcns_fdpair[1]);
+                        return ipcns_fdpair[1];
         }
 
 finalize:
@@ -2276,18 +2482,24 @@ void exec_params_serialized_done(ExecParameters *p) {
         if (!p)
                 return;
 
-        for (size_t i = 0; p->fds && i < p->n_socket_fds + p->n_storage_fds; i++)
-                p->fds[i] = safe_close(p->fds[i]);
+        close_many_unset(p->fds, p->n_socket_fds + p->n_storage_fds);
 
         p->cgroup_path = mfree(p->cgroup_path);
 
-        p->prefix = strv_free(p->prefix);
+        if (p->prefix) {
+                for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++)
+                        free(p->prefix[t]);
+
+                p->prefix = mfree(p->prefix);
+        }
+
         p->received_credentials_directory = mfree(p->received_credentials_directory);
         p->received_encrypted_credentials_directory = mfree(p->received_encrypted_credentials_directory);
 
-        for (size_t i = 0; p->idle_pipe && i < 4; i++)
-                p->idle_pipe[i] = safe_close(p->idle_pipe[i]);
-        p->idle_pipe = mfree(p->idle_pipe);
+        if (p->idle_pipe) {
+                close_many_and_free(p->idle_pipe, 4);
+                p->idle_pipe = NULL;
+        }
 
         p->stdin_fd = safe_close(p->stdin_fd);
         p->stdout_fd = safe_close(p->stdout_fd);
@@ -2479,6 +2691,16 @@ static const char* const exec_directory_type_symlink_table[_EXEC_DIRECTORY_TYPE_
 
 DEFINE_STRING_TABLE_LOOKUP(exec_directory_type_symlink, ExecDirectoryType);
 
+static const char* const exec_directory_type_mode_table[_EXEC_DIRECTORY_TYPE_MAX] = {
+        [EXEC_DIRECTORY_RUNTIME]       = "RuntimeDirectoryMode",
+        [EXEC_DIRECTORY_STATE]         = "StateDirectoryMode",
+        [EXEC_DIRECTORY_CACHE]         = "CacheDirectoryMode",
+        [EXEC_DIRECTORY_LOGS]          = "LogsDirectoryMode",
+        [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectoryMode",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(exec_directory_type_mode, ExecDirectoryType);
+
 /* And this table maps ExecDirectoryType too, but to a generic term identifying the type of resource. This
  * one is supposed to be generic enough to be used for unit types that don't use ExecContext and per-unit
  * directories, specifically .timer units with their timestamp touch file. */