diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/bpf-socket-bind.c | 9 | ||||
-rw-r--r-- | src/core/bpf/socket_bind/socket-bind-api.bpf.h | 7 | ||||
-rw-r--r-- | src/core/bpf/socket_bind/socket-bind.bpf.c | 3 | ||||
-rw-r--r-- | src/core/core-varlink.c | 20 | ||||
-rw-r--r-- | src/core/dbus-unit.c | 4 | ||||
-rw-r--r-- | src/core/dbus-util.c | 2 | ||||
-rw-r--r-- | src/core/dbus-util.h | 1 | ||||
-rw-r--r-- | src/core/dynamic-user.c | 4 | ||||
-rw-r--r-- | src/core/load-fragment-gperf.gperf.in | 4 | ||||
-rw-r--r-- | src/core/load-fragment.c | 35 | ||||
-rw-r--r-- | src/core/load-fragment.h | 1 | ||||
-rw-r--r-- | src/core/main.c | 4 | ||||
-rw-r--r-- | src/core/manager-serialize.c | 11 | ||||
-rw-r--r-- | src/core/mount.c | 22 | ||||
-rw-r--r-- | src/core/service.c | 12 |
15 files changed, 102 insertions, 37 deletions
diff --git a/src/core/bpf-socket-bind.c b/src/core/bpf-socket-bind.c index 660ffdb..0a7ed95 100644 --- a/src/core/bpf-socket-bind.c +++ b/src/core/bpf-socket-bind.c @@ -32,6 +32,15 @@ static int update_rules_map( assert(map_fd >= 0); + if (!head) { + static const struct socket_bind_rule val = { + .address_family = SOCKET_BIND_RULE_AF_MATCH_NOTHING, + }; + + if (sym_bpf_map_update_elem(map_fd, &i, &val, BPF_ANY) != 0) + return -errno; + } + LIST_FOREACH(socket_bind_items, item, head) { struct socket_bind_rule val = { .address_family = (uint32_t) item->address_family, diff --git a/src/core/bpf/socket_bind/socket-bind-api.bpf.h b/src/core/bpf/socket_bind/socket-bind-api.bpf.h index 277b9bb..4fe08f1 100644 --- a/src/core/bpf/socket_bind/socket-bind-api.bpf.h +++ b/src/core/bpf/socket_bind/socket-bind-api.bpf.h @@ -7,13 +7,17 @@ */ #include <linux/types.h> +#include <stdint.h> /* * Bind rule is matched with socket fields accessible to cgroup/bind{4,6} hook * through bpf_sock_addr struct. - * 'address_family' is expected to be one of AF_UNSPEC, AF_INET or AF_INET6. + * 'address_family' is expected to be one of AF_UNSPEC, AF_INET, AF_INET6 or the + * magic SOCKET_BIND_RULE_AF_MATCH_NOTHING. * Matching by family is bypassed for rules with AF_UNSPEC set, which makes the * rest of a rule applicable for both IPv4 and IPv6 addresses. + * If SOCKET_BIND_RULE_AF_MATCH_NOTHING is set the rule fails unconditionally + * and other checks are skipped. * If matching by family is either successful or bypassed, a rule and a socket * are matched by ip protocol. * If 'protocol' is 0, matching is bypassed. @@ -49,3 +53,4 @@ struct socket_bind_rule { }; #define SOCKET_BIND_MAX_RULES 128 +#define SOCKET_BIND_RULE_AF_MATCH_NOTHING UINT32_MAX diff --git a/src/core/bpf/socket_bind/socket-bind.bpf.c b/src/core/bpf/socket_bind/socket-bind.bpf.c index b7972a8..da9f9d1 100644 --- a/src/core/bpf/socket_bind/socket-bind.bpf.c +++ b/src/core/bpf/socket_bind/socket-bind.bpf.c @@ -55,6 +55,9 @@ static __always_inline bool match( __u32 protocol, __u16 port, const struct socket_bind_rule *r) { + if (r->address_family == SOCKET_BIND_RULE_AF_MATCH_NOTHING) + return false; + return match_af(address_family, r) && match_protocol(protocol, r) && match_user_port(port, r); diff --git a/src/core/core-varlink.c b/src/core/core-varlink.c index 8432715..d8b16c2 100644 --- a/src/core/core-varlink.c +++ b/src/core/core-varlink.c @@ -504,13 +504,21 @@ static int manager_varlink_init_system(Manager *m) { if (!MANAGER_IS_TEST_RUN(m)) { (void) mkdir_p_label("/run/systemd/userdb", 0755); - r = varlink_server_listen_address(s, "/run/systemd/userdb/io.systemd.DynamicUser", 0666); - if (r < 0) - return log_error_errno(r, "Failed to bind to varlink socket: %m"); + FOREACH_STRING(address, "/run/systemd/userdb/io.systemd.DynamicUser", VARLINK_ADDR_PATH_MANAGED_OOM_SYSTEM) { + if (MANAGER_IS_RELOADING(m)) { + /* If manager is reloading, we skip listening on existing addresses, since + * the fd should be acquired later through deserialization. */ + if (access(address, F_OK) >= 0) + continue; + if (errno != ENOENT) + return log_error_errno(errno, + "Failed to check if varlink socket '%s' exists: %m", address); + } - r = varlink_server_listen_address(s, VARLINK_ADDR_PATH_MANAGED_OOM_SYSTEM, 0666); - if (r < 0) - return log_error_errno(r, "Failed to bind to varlink socket: %m"); + r = varlink_server_listen_address(s, address, 0666); + if (r < 0) + return log_error_errno(r, "Failed to bind to varlink socket '%s': %m", address); + } } r = varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL); diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index e2398c8..648d435 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -2159,7 +2159,7 @@ static int bus_unit_set_transient_property( return bus_set_transient_emergency_action(u, name, &u->job_timeout_action, message, flags, error); if (streq(name, "JobTimeoutRebootArgument")) - return bus_set_transient_string(u, name, &u->job_timeout_reboot_arg, message, flags, error); + return bus_set_transient_reboot_parameter(u, name, &u->job_timeout_reboot_arg, message, flags, error); if (streq(name, "StartLimitIntervalUSec")) return bus_set_transient_usec(u, name, &u->start_ratelimit.interval, message, flags, error); @@ -2183,7 +2183,7 @@ static int bus_unit_set_transient_property( return bus_set_transient_exit_status(u, name, &u->success_action_exit_status, message, flags, error); if (streq(name, "RebootArgument")) - return bus_set_transient_string(u, name, &u->reboot_arg, message, flags, error); + return bus_set_transient_reboot_parameter(u, name, &u->reboot_arg, message, flags, error); if (streq(name, "CollectMode")) return bus_set_transient_collect_mode(u, name, &u->collect_mode, message, flags, error); diff --git a/src/core/dbus-util.c b/src/core/dbus-util.c index ea044b5..d4f4054 100644 --- a/src/core/dbus-util.c +++ b/src/core/dbus-util.c @@ -6,6 +6,7 @@ #include "escape.h" #include "parse-util.h" #include "path-util.h" +#include "reboot-util.h" #include "unit-printf.h" #include "user-util.h" #include "unit.h" @@ -39,6 +40,7 @@ static inline bool valid_user_group_name_or_id_relaxed(const char *u) { BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(user_relaxed, valid_user_group_name_or_id_relaxed); BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(path, path_is_absolute); +BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(reboot_parameter, reboot_parameter_is_valid); int bus_set_transient_string( Unit *u, diff --git a/src/core/dbus-util.h b/src/core/dbus-util.h index e12631a..19abcd1 100644 --- a/src/core/dbus-util.h +++ b/src/core/dbus-util.h @@ -239,6 +239,7 @@ int bus_set_transient_mode_t(Unit *u, const char *name, mode_t *p, sd_bus_messag int bus_set_transient_unsigned(Unit *u, const char *name, unsigned *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error); int bus_set_transient_user_relaxed(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error); int bus_set_transient_path(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error); +int bus_set_transient_reboot_parameter(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error); int bus_set_transient_string(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error); int bus_set_transient_bool(Unit *u, const char *name, bool *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error); int bus_set_transient_usec_internal(Unit *u, const char *name, usec_t *p, bool fix_0, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error); diff --git a/src/core/dynamic-user.c b/src/core/dynamic-user.c index 18b36e7..cb3af96 100644 --- a/src/core/dynamic-user.c +++ b/src/core/dynamic-user.c @@ -332,8 +332,10 @@ static int dynamic_user_pop(DynamicUser *d, uid_t *ret_uid, int *ret_lock_fd) { * the lock on the socket taken. */ k = receive_one_fd_iov(d->storage_socket[0], &iov, 1, MSG_DONTWAIT, &lock_fd); - if (k < 0) + if (k < 0) { + assert(errno_is_valid(-k)); return (int) k; + } *ret_uid = uid; *ret_lock_fd = lock_fd; diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in index 81a5971..b92c725 100644 --- a/src/core/load-fragment-gperf.gperf.in +++ b/src/core/load-fragment-gperf.gperf.in @@ -303,7 +303,7 @@ Unit.IgnoreOnSnapshot, config_parse_warn_compat, Unit.JobTimeoutSec, config_parse_job_timeout_sec, 0, 0 Unit.JobRunningTimeoutSec, config_parse_job_running_timeout_sec, 0, 0 Unit.JobTimeoutAction, config_parse_emergency_action, 0, offsetof(Unit, job_timeout_action) -Unit.JobTimeoutRebootArgument, config_parse_unit_string_printf, 0, offsetof(Unit, job_timeout_reboot_arg) +Unit.JobTimeoutRebootArgument, config_parse_reboot_parameter, 0, offsetof(Unit, job_timeout_reboot_arg) Unit.StartLimitIntervalSec, config_parse_sec, 0, offsetof(Unit, start_ratelimit.interval) {# The following is a legacy alias name for compatibility #} Unit.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_ratelimit.interval) @@ -313,7 +313,7 @@ Unit.FailureAction, config_parse_emergency_action, Unit.SuccessAction, config_parse_emergency_action, 0, offsetof(Unit, success_action) Unit.FailureActionExitStatus, config_parse_exit_status, 0, offsetof(Unit, failure_action_exit_status) Unit.SuccessActionExitStatus, config_parse_exit_status, 0, offsetof(Unit, success_action_exit_status) -Unit.RebootArgument, config_parse_unit_string_printf, 0, offsetof(Unit, reboot_arg) +Unit.RebootArgument, config_parse_reboot_parameter, 0, offsetof(Unit, reboot_arg) Unit.ConditionPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, offsetof(Unit, conditions) Unit.ConditionPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, offsetof(Unit, conditions) Unit.ConditionPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, offsetof(Unit, conditions) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 5f4d4b0..11166f9 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -54,6 +54,7 @@ #include "path-util.h" #include "percent-util.h" #include "process-util.h" +#include "reboot-util.h" #if HAVE_SECCOMP #include "seccomp-util.h" #endif @@ -360,6 +361,40 @@ int config_parse_unit_string_printf( return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata); } +int config_parse_reboot_parameter( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + _cleanup_free_ char *k = NULL; + const Unit *u = ASSERT_PTR(userdata); + int r; + + assert(filename); + assert(line); + assert(rvalue); + + r = unit_full_printf(u, rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue); + return 0; + } + + if (!reboot_parameter_is_valid(k)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid reboot parameter '%s', ignoring.", k); + return 0; + } + + return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata); +} + int config_parse_unit_strv_printf( const char *unit, const char *filename, diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index c57a6b2..13292db 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -21,6 +21,7 @@ void unit_dump_config_items(FILE *f); CONFIG_PARSER_PROTOTYPE(config_parse_unit_deps); CONFIG_PARSER_PROTOTYPE(config_parse_obsolete_unit_deps); CONFIG_PARSER_PROTOTYPE(config_parse_unit_string_printf); +CONFIG_PARSER_PROTOTYPE(config_parse_reboot_parameter); CONFIG_PARSER_PROTOTYPE(config_parse_unit_strv_printf); CONFIG_PARSER_PROTOTYPE(config_parse_unit_path_printf); CONFIG_PARSER_PROTOTYPE(config_parse_colon_separated_paths); diff --git a/src/core/main.c b/src/core/main.c index 1c4b464..7b51099 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -608,7 +608,7 @@ static int parse_config_file(void) { { "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, &arg_cpu_affinity }, { "Manager", "NUMAPolicy", config_parse_numa_policy, 0, &arg_numa_policy.type }, { "Manager", "NUMAMask", config_parse_numa_mask, 0, &arg_numa_policy }, - { "Manager", "JoinControllers", config_parse_warn_compat, DISABLED_CONFIGURATION, NULL }, + { "Manager", "JoinControllers", config_parse_warn_compat, DISABLED_LEGACY, NULL }, { "Manager", "RuntimeWatchdogSec", config_parse_watchdog_sec, 0, &arg_runtime_watchdog }, { "Manager", "RuntimeWatchdogPreSec", config_parse_watchdog_sec, 0, &arg_pretimeout_watchdog }, { "Manager", "RebootWatchdogSec", config_parse_watchdog_sec, 0, &arg_reboot_watchdog }, @@ -2384,7 +2384,7 @@ static void setenv_manager_environment(void) { r = putenv_dup(*p, true); if (r < 0) - log_warning_errno(errno, "Failed to setenv \"%s\", ignoring: %m", *p); + log_warning_errno(r, "Failed to setenv \"%s\", ignoring: %m", *p); } } diff --git a/src/core/manager-serialize.c b/src/core/manager-serialize.c index 3beb8fd..3d4f471 100644 --- a/src/core/manager-serialize.c +++ b/src/core/manager-serialize.c @@ -533,21 +533,12 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { return -ENOMEM; } else if ((val = startswith(l, "varlink-server-socket-address="))) { if (!m->varlink_server && MANAGER_IS_SYSTEM(m)) { - _cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL; - - r = manager_setup_varlink_server(m, &s); + r = manager_varlink_init(m); if (r < 0) { log_warning_errno(r, "Failed to setup varlink server, ignoring: %m"); continue; } - r = varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL); - if (r < 0) { - log_warning_errno(r, "Failed to attach varlink connection to event loop, ignoring: %m"); - continue; - } - - m->varlink_server = TAKE_PTR(s); deserialize_varlink_sockets = true; } diff --git a/src/core/mount.c b/src/core/mount.c index 82ff3a7..451b429 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -1468,7 +1468,8 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) { if (IN_SET(m->state, MOUNT_REMOUNTING, MOUNT_REMOUNTING_SIGKILL, MOUNT_REMOUNTING_SIGTERM)) mount_set_reload_result(m, f); - else if (m->result == MOUNT_SUCCESS) + else if (m->result == MOUNT_SUCCESS && !IN_SET(m->state, MOUNT_MOUNTING, MOUNT_UNMOUNTING)) + /* MOUNT_MOUNTING and MOUNT_UNMOUNTING states need to be patched, see below. */ m->result = f; if (m->control_command) { @@ -1491,11 +1492,11 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) { switch (m->state) { case MOUNT_MOUNTING: - /* Our mount point has not appeared in mountinfo. Something went wrong. */ + /* Our mount point has not appeared in mountinfo. Something went wrong. */ if (f == MOUNT_SUCCESS) { - /* Either /bin/mount has an unexpected definition of success, - * or someone raced us and we lost. */ + /* Either /bin/mount has an unexpected definition of success, or someone raced us + * and we lost. */ log_unit_warning(UNIT(m), "Mount process finished, but there is no mount."); f = MOUNT_FAILURE_PROTOCOL; } @@ -1513,9 +1514,7 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) { break; case MOUNT_UNMOUNTING: - if (f == MOUNT_SUCCESS && m->from_proc_self_mountinfo) { - /* Still a mount point? If so, let's try again. Most likely there were multiple mount points * stacked on top of each other. We might exceed the timeout specified by the user overall, * but we will stop as soon as any one umount times out. */ @@ -1526,15 +1525,20 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) { mount_enter_unmounting(m); } else { log_unit_warning(u, "Mount still present after %u attempts to unmount, giving up.", m->n_retry_umount); - mount_enter_mounted(m, f); + mount_enter_mounted(m, MOUNT_FAILURE_PROTOCOL); } + } else if (f == MOUNT_FAILURE_EXIT_CODE && !m->from_proc_self_mountinfo) { + /* Hmm, umount process spawned by us failed, but the mount disappeared anyway? + * Maybe someone else is trying to unmount at the same time. */ + log_unit_notice(u, "Mount disappeared even though umount process failed, continuing."); + mount_enter_dead(m, MOUNT_SUCCESS); } else mount_enter_dead_or_mounted(m, f); break; - case MOUNT_UNMOUNTING_SIGKILL: case MOUNT_UNMOUNTING_SIGTERM: + case MOUNT_UNMOUNTING_SIGKILL: mount_enter_dead_or_mounted(m, f); break; @@ -2078,7 +2082,7 @@ static int mount_process_proc_self_mountinfo(Manager *m) { * then remove it because of an internal error. E.g., fuse.sshfs seems * to do that when the connection fails. See #17617. To handle such the * case, let's once set the state back to mounting. Then, the unit can - * correctly enter the failed state later in mount_sigchld(). */ + * correctly enter the failed state later in mount_sigchld_event(). */ mount_set_state(mount, MOUNT_MOUNTING); break; diff --git a/src/core/service.c b/src/core/service.c index cdddd49..d382aad 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -3378,8 +3378,10 @@ static void service_notify_cgroup_empty_event(Unit *u) { break; } - if (s->exit_type == SERVICE_EXIT_CGROUP && main_pid_good(s) <= 0) - service_enter_start_post(s); + if (s->exit_type == SERVICE_EXIT_CGROUP && main_pid_good(s) <= 0) { + service_enter_stop_post(s, SERVICE_SUCCESS); + break; + } _fallthrough_; case SERVICE_START_POST: @@ -3648,11 +3650,13 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { default: assert_not_reached(); } - } else if (s->exit_type == SERVICE_EXIT_CGROUP && s->state == SERVICE_START) + } else if (s->exit_type == SERVICE_EXIT_CGROUP && s->state == SERVICE_START && + !IN_SET(s->type, SERVICE_NOTIFY, SERVICE_DBUS)) /* If a main process exits very quickly, this function might be executed * before service_dispatch_exec_io(). Since this function disabled IO events * to monitor the main process above, we need to update the state here too. - * Let's consider the process is successfully launched and exited. */ + * Let's consider the process is successfully launched and exited, but + * only when we're not expecting a readiness notification or dbus name. */ service_enter_start_post(s); } |