tty-ask-password-agent: if we're spawning further agents, grant them notify access (#35855)

Alternative to #35853
This commit is contained in:
Daan De Meyer
2025-01-06 10:05:29 +01:00
committed by GitHub
8 changed files with 48 additions and 43 deletions

View File

@@ -121,7 +121,7 @@ static void sigbus_handler(int sn, siginfo_t *si, void *data) {
}
void sigbus_install(void) {
struct sigaction sa = {
static const struct sigaction sa = {
.sa_sigaction = sigbus_handler,
.sa_flags = SA_SIGINFO,
};

View File

@@ -302,6 +302,11 @@ const struct sigaction sigaction_default = {
.sa_flags = SA_RESTART,
};
const struct sigaction sigaction_nop_nocldstop = {
.sa_handler = nop_signal_handler,
.sa_flags = SA_NOCLDSTOP|SA_RESTART,
};
int parse_signo(const char *s, int *ret) {
int sig, r;

View File

@@ -68,5 +68,6 @@ void propagate_signal(int sig, siginfo_t *siginfo);
extern const struct sigaction sigaction_ignore;
extern const struct sigaction sigaction_default;
extern const struct sigaction sigaction_nop_nocldstop;
int parse_signo(const char *s, int *ret);

View File

@@ -52,8 +52,13 @@ _noreturn_ void freeze_or_exit_or_reboot(void) {
}
_noreturn_ static void crash(int sig, siginfo_t *siginfo, void *context) {
struct sigaction sa;
static const struct sigaction sa_nocldwait = {
.sa_handler = SIG_IGN,
.sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART,
};
pid_t pid;
int r;
/* NB: 💣 💣 💣 This is a signal handler, most likely executed in a situation where we have corrupted
* memory. Thus: please avoid any libc memory allocation here, or any functions that internally use
@@ -69,13 +74,8 @@ _noreturn_ static void crash(int sig, siginfo_t *siginfo, void *context) {
LOG_MESSAGE("Caught <%s>, not dumping core.", signal_to_string(sig)),
"MESSAGE_ID=" SD_MESSAGE_CRASH_NO_COREDUMP_STR);
else {
sa = (struct sigaction) {
.sa_handler = nop_signal_handler,
.sa_flags = SA_NOCLDSTOP|SA_RESTART,
};
/* We want to wait for the core process, hence let's enable SIGCHLD */
(void) sigaction(SIGCHLD, &sa, NULL);
(void) sigaction(SIGCHLD, &sigaction_nop_nocldstop, NULL);
pid = raw_clone(SIGCHLD);
if (pid < 0)
@@ -99,7 +99,6 @@ _noreturn_ static void crash(int sig, siginfo_t *siginfo, void *context) {
_exit(EXIT_EXCEPTION);
} else {
siginfo_t status;
int r;
if (siginfo) {
if (siginfo->si_pid == 0)
@@ -146,13 +145,8 @@ _noreturn_ static void crash(int sig, siginfo_t *siginfo, void *context) {
if (arg_crash_chvt >= 0)
(void) chvt(arg_crash_chvt);
sa = (struct sigaction) {
.sa_handler = SIG_IGN,
.sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART,
};
/* Let the kernel reap children for us */
(void) sigaction(SIGCHLD, &sa, NULL);
(void) sigaction(SIGCHLD, &sa_nocldwait, NULL);
if (arg_crash_shell) {
log_notice("Executing crash shell...");

View File

@@ -517,7 +517,7 @@ static int manager_enable_special_signals(Manager *m) {
#define RTSIG_IF_AVAILABLE(signum) (signum <= SIGRTMAX ? signum : -1)
static int manager_setup_signals(Manager *m) {
struct sigaction sa = {
static const struct sigaction sa = {
.sa_handler = SIG_DFL,
.sa_flags = SA_NOCLDSTOP|SA_RESTART,
};

View File

@@ -1170,13 +1170,14 @@ static void sigterm_handler(int signal, siginfo_t *info, void *ucontext) {
}
static int run_debug(int argc, char **argv, void *userdata) {
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
_cleanup_free_ char *exe = NULL, *path = NULL;
_cleanup_strv_free_ char **debugger_call = NULL;
struct sigaction sa = {
static const struct sigaction sa = {
.sa_sigaction = sigterm_handler,
.sa_flags = SA_SIGINFO,
};
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
_cleanup_free_ char *exe = NULL, *path = NULL;
_cleanup_strv_free_ char **debugger_call = NULL;
bool unlink_path = false;
const char *data, *fork_name;
size_t len;

View File

@@ -5175,11 +5175,6 @@ static int run_container(
pid_t *pid,
int *ret) {
static const struct sigaction sa = {
.sa_handler = nop_signal_handler,
.sa_flags = SA_NOCLDSTOP|SA_RESTART,
};
_cleanup_(release_lock_file) LockFile uid_shift_lock = LOCK_FILE_INIT;
_cleanup_close_ int etc_passwd_lock = -EBADF;
_cleanup_close_pair_ int
@@ -5240,7 +5235,7 @@ static int run_container(
if (r < 0)
return log_error_errno(errno, "Failed to change the signal mask: %m");
r = sigaction(SIGCHLD, &sa, NULL);
r = sigaction(SIGCHLD, &sigaction_nop_nocldstop, NULL);
if (r < 0)
return log_error_errno(errno, "Failed to install SIGCHLD handler: %m");

View File

@@ -567,21 +567,21 @@ static int parse_argv(int argc, char *argv[]) {
/*
* To be able to ask on all terminal devices of /dev/console the devices are collected. If more than one
* device is found, then on each of the terminals an inquiring task is forked. Every task has its own session
* and its own controlling terminal. If one of the tasks does handle a password, the remaining tasks will be
* and its own controlling terminal. If one of the tasks does handle a password, the remaining tasks will be
* terminated.
*/
static int ask_on_this_console(const char *tty, pid_t *ret_pid, char **arguments) {
static const struct sigaction sigchld = {
.sa_handler = nop_signal_handler,
.sa_flags = SA_NOCLDSTOP | SA_RESTART,
};
static int ask_on_this_console(const char *tty, char **arguments, pid_t *ret_pid) {
int r;
assert_se(sigaction(SIGCHLD, &sigchld, NULL) >= 0);
assert(tty);
assert(arguments);
assert(ret_pid);
assert_se(sigaction(SIGCHLD, &sigaction_nop_nocldstop, NULL) >= 0);
assert_se(sigaction(SIGHUP, &sigaction_default, NULL) >= 0);
assert_se(sigprocmask_many(SIG_UNBLOCK, NULL, SIGHUP, SIGCHLD) >= 0);
r = safe_fork("(sd-passwd)", FORK_RESET_SIGNALS|FORK_LOG, ret_pid);
r = safe_fork("(sd-passwd)", FORK_RESET_SIGNALS|FORK_KEEP_NOTIFY_SOCKET|FORK_LOG, ret_pid);
if (r < 0)
return r;
if (r == 0) {
@@ -658,12 +658,12 @@ static void terminate_agents(Set *pids) {
}
static int ask_on_consoles(char *argv[]) {
_cleanup_set_free_ Set *pids = NULL;
_cleanup_strv_free_ char **consoles = NULL, **arguments = NULL;
siginfo_t status = {};
pid_t pid;
_cleanup_set_free_ Set *pids = NULL;
int r;
assert(argv);
r = get_kernel_consoles(&consoles);
if (r < 0)
return log_error_errno(r, "Failed to determine devices of /dev/console: %m");
@@ -676,9 +676,18 @@ static int ask_on_consoles(char *argv[]) {
if (!arguments)
return log_oom();
/* Grant agents we spawn notify access too, so that once an agent establishes inotify watch
* READY=1 from them is accepted by service manager (see process_and_watch_password_files()).
*
* Note that when any agent exits STOPPING=1 would also be sent, but that's utterly what we want,
* i.e. the password is answered on one console and other agents get killed below. */
(void) sd_notify(/* unset_environment = */ false, "NOTIFYACCESS=all");
/* Start an agent on each console. */
STRV_FOREACH(tty, consoles) {
r = ask_on_this_console(*tty, &pid, arguments);
pid_t pid;
r = ask_on_this_console(*tty, arguments, &pid);
if (r < 0)
return r;
@@ -688,22 +697,22 @@ static int ask_on_consoles(char *argv[]) {
/* Wait for an agent to exit. */
for (;;) {
zero(status);
siginfo_t status = {};
if (waitid(P_ALL, 0, &status, WEXITED) < 0) {
if (errno == EINTR)
continue;
return log_error_errno(errno, "waitid() failed: %m");
return log_error_errno(errno, "Failed to wait for console ask-password agent: %m");
}
if (!is_clean_exit(status.si_code, status.si_status, EXIT_CLEAN_DAEMON, NULL))
log_error("Password agent failed with: %d", status.si_status);
set_remove(pids, PID_TO_PTR(status.si_pid));
break;
}
if (!is_clean_exit(status.si_code, status.si_status, EXIT_CLEAN_DAEMON, NULL))
log_error("Password agent failed with: %d", status.si_status);
terminate_agents(pids);
return 0;
}