From f385b3f3dde55702de8643cd0a5cb1b2bdedffef Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Sun, 14 Dec 2025 14:47:20 +0100 Subject: [PATCH] core/service: pass credentials to ExecReload*= if refreshed Closes #35227 --- src/core/service.c | 66 +++++++++++++++++++++++++++++++++++----------- src/core/service.h | 1 + 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/src/core/service.c b/src/core/service.c index 93253b45f49..49dd82ebb8c 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -1689,11 +1689,16 @@ static Service *service_get_triggering_service(Service *s) { return NULL; } -static ExecFlags service_exec_flags(ServiceExecCommand command_id, ExecFlags cred_flag) { +static ExecFlags service_exec_flags( + const Service *s, + ServiceExecCommand command_id, + ExecFlags cred_flag) { + /* All service main/control processes honor sandboxing and namespacing options (except those explicitly excluded in service_spawn()) */ ExecFlags flags = EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT; + assert(s); assert(command_id >= 0); assert(command_id < _SERVICE_EXEC_COMMAND_MAX); assert((cred_flag & ~(EXEC_SETUP_CREDENTIALS_FRESH|EXEC_SETUP_CREDENTIALS)) == 0); @@ -1725,6 +1730,12 @@ static ExecFlags service_exec_flags(ServiceExecCommand command_id, ExecFlags cre if (!IN_SET(command_id, SERVICE_EXEC_CONDITION, SERVICE_EXEC_START_PRE)) flags |= EXEC_CONTROL_CGROUP; + /* Pass credentials to ExecReload*= too, but only if the credentials are actually refreshed, + * to make sure they have the same understanding of the world as the main process. */ + if (IN_SET(command_id, SERVICE_EXEC_RELOAD, SERVICE_EXEC_RELOAD_POST) && + FLAGS_SET(s->refreshed_mask, SERVICE_RELOAD_CREDENTIALS)) + flags |= EXEC_SETUP_CREDENTIALS; + if (IN_SET(command_id, SERVICE_EXEC_STOP, SERVICE_EXEC_STOP_POST)) flags |= EXEC_SETENV_RESULT; @@ -2250,7 +2261,7 @@ static void service_enter_stop_post(Service *s, ServiceResult f) { r = service_spawn(s, s->control_command, - service_exec_flags(s->control_command_id, /* cred_flag= */ 0), + service_exec_flags(s, s->control_command_id, /* cred_flag = */ 0), s->timeout_stop_usec, &s->control_pid); if (r < 0) { @@ -2362,7 +2373,7 @@ static void service_enter_stop(Service *s, ServiceResult f) { r = service_spawn(s, s->control_command, - service_exec_flags(s->control_command_id, /* cred_flag= */ 0), + service_exec_flags(s, s->control_command_id, /* cred_flag = */ 0), s->timeout_stop_usec, &s->control_pid); if (r < 0) { @@ -2447,7 +2458,7 @@ static void service_enter_start_post(Service *s) { r = service_spawn(s, s->control_command, - service_exec_flags(s->control_command_id, /* cred_flag= */ 0), + service_exec_flags(s, s->control_command_id, /* cred_flag = */ 0), s->timeout_start_usec, &s->control_pid); if (r < 0) { @@ -2557,7 +2568,7 @@ static void service_enter_start(Service *s) { r = service_spawn(s, c, - service_exec_flags(SERVICE_EXEC_START, EXEC_SETUP_CREDENTIALS_FRESH), + service_exec_flags(s, SERVICE_EXEC_START, EXEC_SETUP_CREDENTIALS_FRESH), timeout, &pidref); if (r < 0) { @@ -2617,7 +2628,7 @@ static void service_enter_start_pre(Service *s) { r = service_spawn(s, s->control_command, - service_exec_flags(s->control_command_id, /* cred_flag= */ 0), + service_exec_flags(s, s->control_command_id, /* cred_flag = */ 0), s->timeout_start_usec, &s->control_pid); if (r < 0) { @@ -2653,7 +2664,7 @@ static void service_enter_condition(Service *s) { r = service_spawn(s, s->control_command, - service_exec_flags(s->control_command_id, /* cred_flag= */ 0), + service_exec_flags(s, s->control_command_id, /* cred_flag = */ 0), s->timeout_start_usec, &s->control_pid); if (r < 0) { @@ -2757,7 +2768,7 @@ static void service_enter_reload_post(Service *s) { r = service_spawn(s, s->control_command, - service_exec_flags(s->control_command_id, /* cred_flag= */ 0), + service_exec_flags(s, s->control_command_id, /* cred_flag = */ 0), s->timeout_start_usec, &s->control_pid); if (r < 0) { @@ -2832,7 +2843,7 @@ static void service_enter_reload(Service *s) { r = service_spawn(s, s->control_command, - service_exec_flags(s->control_command_id, /* cred_flag= */ 0), + service_exec_flags(s, s->control_command_id, /* cred_flag = */ 0), s->timeout_start_usec, &s->control_pid); if (r < 0) { @@ -3063,7 +3074,7 @@ static void service_run_next_control(Service *s) { r = service_spawn(s, s->control_command, - service_exec_flags(s->control_command_id, /* cred_flag= */ 0), + service_exec_flags(s, s->control_command_id, /* cred_flag = */ 0), timeout, &s->control_pid); if (r < 0) { @@ -3094,7 +3105,7 @@ static void service_run_next_main(Service *s) { r = service_spawn(s, s->main_command, - service_exec_flags(SERVICE_EXEC_START, EXEC_SETUP_CREDENTIALS), + service_exec_flags(s, SERVICE_EXEC_START, EXEC_SETUP_CREDENTIALS), s->timeout_start_usec, &pidref); if (r < 0) { @@ -3275,6 +3286,7 @@ static int service_reload(Unit *u) { assert(IN_SET(s->state, SERVICE_RUNNING, SERVICE_EXITED)); s->reload_result = SERVICE_SUCCESS; + s->refreshed_mask = 0; service_enter_refresh_extensions(s); @@ -3495,6 +3507,21 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { (void) serialize_usec(f, "reload-begin-usec", s->reload_begin_usec); + if (s->refreshed_mask > 0) { + _cleanup_strv_free_ char **l = NULL; + _cleanup_free_ char *t = NULL; + + r = service_refresh_on_reload_to_strv(s->refreshed_mask, &l); + if (r < 0) + return log_oom(); + + t = strv_join(l, " "); + if (!t) + return log_oom(); + + (void) serialize_item(f, "refreshed-mask", t); + } + return 0; } @@ -3884,7 +3911,11 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, } else if (streq(key, "reload-begin-usec")) (void) deserialize_usec(value, &s->reload_begin_usec); - else + else if (streq(key, "refreshed-mask")) { + r = service_refresh_on_reload_from_string_many(value, &s->refreshed_mask); + if (r < 0) + log_unit_debug_errno(u, r, "Failed to parse refresh-mask value: %s", value); + } else log_unit_debug(u, "Unknown serialization key: %s", key); return 0; @@ -4506,18 +4537,21 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { break; case SERVICE_REFRESH_EXTENSIONS: - if (f == SERVICE_SUCCESS) + if (f == SERVICE_SUCCESS) { + s->refreshed_mask |= SERVICE_RELOAD_EXTENSIONS; service_enter_refresh_credentials(s); - else + } else service_reload_finish(s, f); break; case SERVICE_REFRESH_CREDENTIALS: if (f == SERVICE_SUCCESS || - (f == SERVICE_FAILURE_EXIT_CODE && IN_SET(status, EXIT_NOTINSTALLED, EXIT_NOPERMISSION))) + (f == SERVICE_FAILURE_EXIT_CODE && IN_SET(status, EXIT_NOTINSTALLED, EXIT_NOPERMISSION))) { + /* Refreshing asynchronously done, proceed to reload */ + s->refreshed_mask |= f == SERVICE_SUCCESS ? SERVICE_RELOAD_CREDENTIALS : 0; service_enter_reload(s); - else + } else service_reload_finish(s, f); break; diff --git a/src/core/service.h b/src/core/service.h index 44882a6fd32..9750b19ce28 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -248,6 +248,7 @@ typedef struct Service { bool refresh_on_reload_set; ServiceRefreshOnReload refresh_on_reload_flags; + ServiceRefreshOnReload refreshed_mask; OOMPolicy oom_policy; -- 2.47.3