summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/bpf-socket-bind.c9
-rw-r--r--src/core/bpf/socket_bind/socket-bind-api.bpf.h7
-rw-r--r--src/core/bpf/socket_bind/socket-bind.bpf.c3
-rw-r--r--src/core/core-varlink.c20
-rw-r--r--src/core/dbus-unit.c4
-rw-r--r--src/core/dbus-util.c2
-rw-r--r--src/core/dbus-util.h1
-rw-r--r--src/core/dynamic-user.c4
-rw-r--r--src/core/load-fragment-gperf.gperf.in4
-rw-r--r--src/core/load-fragment.c35
-rw-r--r--src/core/load-fragment.h1
-rw-r--r--src/core/main.c4
-rw-r--r--src/core/manager-serialize.c11
-rw-r--r--src/core/mount.c22
-rw-r--r--src/core/service.c12
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);
}