tree-wide: only use .si_pid field in siginfo_t, if .si_code indicates that's safe

Fixes: #37498
This commit is contained in:
Lennart Poettering
2025-05-31 14:48:37 +02:00
committed by Zbigniew Jędrzejewski-Szmek
parent 91c60ff528
commit 1105f8d20f
7 changed files with 62 additions and 4 deletions
+1 -1
View File
@@ -1507,7 +1507,7 @@ DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);
void log_received_signal(int level, const struct signalfd_siginfo *si) {
assert(si);
if (pid_is_valid(si->ssi_pid)) {
if (si_code_from_process(si->ssi_code) && pid_is_valid(si->ssi_pid)) {
_cleanup_free_ char *p = NULL;
(void) pid_get_comm(si->ssi_pid, &p);
+22
View File
@@ -71,3 +71,25 @@ extern const struct sigaction sigaction_default;
extern const struct sigaction sigaction_nop_nocldstop;
int parse_signo(const char *s, int *ret);
static inline bool si_code_from_process(int si_code) {
/* Returns true if the .si_code field of siginfo_t or the .ssi_code field of struct signalfd_siginfo
* indicate that the signal originates from a userspace process, and hence the .si_pid/.ssi_pid field
* is valid. This check is not obvious, since on one hand SI_USER/SI_QUEUE are supposed to be the
* values that kill() and sigqueue() set, and that's documented in sigaction(2), but on the other
* hand rt_sigqueueinfo(2) says userspace can actually set any value below zero. Hence check for
* either.
*
* Also quoting POSIX:
*
* "On systems not supporting the XSI option, the si_pid and si_uid members of siginfo_t are only
* required to be valid when si_code is SI_USER or SI_QUEUE. On XSI-conforming systems, they are also
* valid for all si_code values less than or equal to 0; however, it is unspecified whether SI_USER
* and SI_QUEUE have values less than or equal to zero, and therefore XSI applications should check
* whether si_code has the value SI_USER or SI_QUEUE or is less than or equal to 0 to tell whether
* si_pid and si_uid are valid."
*
* From: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html */
return si_code < 0 || IN_SET(si_code, SI_USER, SI_QUEUE);
}
+5 -1
View File
@@ -104,7 +104,11 @@ _noreturn_ static void crash(int sig, siginfo_t *siginfo, void *context) {
siginfo_t status;
if (siginfo) {
if (siginfo->si_pid == 0)
if (!si_code_from_process(siginfo->si_code))
log_struct(LOG_EMERG,
LOG_MESSAGE("Caught <%s>.", signal_to_string(sig)),
LOG_MESSAGE_ID(SD_MESSAGE_CRASH_UNKNOWN_SIGNAL_STR));
else if (siginfo->si_pid == 0)
log_struct(LOG_EMERG,
LOG_MESSAGE("Caught <%s>, from unknown sender process.", signal_to_string(sig)),
LOG_MESSAGE_ID(SD_MESSAGE_CRASH_UNKNOWN_SIGNAL_STR));
+3 -1
View File
@@ -1170,7 +1170,9 @@ static void sigterm_handler(int signal, siginfo_t *info, void *ucontext) {
/* If the sender is not us, propagate the signal to all processes in
* the same process group */
if (pid_is_valid(info->si_pid) && info->si_pid != getpid_cached())
if (si_code_from_process(info->si_code) &&
pid_is_valid(info->si_pid) &&
info->si_pid != getpid_cached())
(void) kill(0, signal);
}
+20 -1
View File
@@ -58,6 +58,7 @@
#include "process-util.h"
#include "rm-rf.h"
#include "set.h"
#include "signal-util.h"
#include "socket-netlink.h"
#include "socket-util.h"
#include "stdio-util.h"
@@ -1645,9 +1646,15 @@ void manager_full_flush(Manager *m) {
static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
assert(si);
if (!si_code_from_process(si->ssi_code)) {
log_warning("Received SIGUSR1 with unexpected .si_code %i, ignoring.", si->ssi_code);
return 0;
}
if (m->namespace) {
log_error("Received SIGUSR1 signal from PID %u, but flushing runtime journals not supported for namespaced instances.", si->ssi_pid);
log_warning("Received SIGUSR1 signal from PID %u, but flushing runtime journals not supported for namespaced instances, ignoring.", si->ssi_pid);
return 0;
}
@@ -1681,6 +1688,12 @@ void manager_full_rotate(Manager *m) {
static int dispatch_sigusr2(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
assert(si);
if (!si_code_from_process(si->ssi_code)) {
log_warning("Received SIGUSR2 with unexpected .si_code %i, ignoring.", si->ssi_code);
return 0;
}
log_info("Received SIGUSR2 signal from PID %u, as request to rotate journal, rotating.", si->ssi_pid);
manager_full_rotate(m);
@@ -1785,6 +1798,12 @@ void manager_full_sync(Manager *m, bool wait) {
static int dispatch_sigrtmin1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
assert(si);
if (!si_code_from_process(si->ssi_code)) {
log_warning("Received SIGRTMIN1 with unexpected .si_code %i, ignoring.", si->ssi_code);
return 0;
}
log_debug("Received SIGRTMIN1 signal from PID %u, as request to sync.", si->ssi_pid);
manager_full_sync(m, /* wait = */ false);
+5
View File
@@ -21,6 +21,11 @@ int sigrtmin18_handler(sd_event_source *s, const struct signalfd_siginfo *si, vo
assert(s);
assert(si);
if (!si_code_from_process(si->ssi_code)) {
log_notice("Received control signal %s with unexpected .si_code %i, ignoring.", signal_to_string(si->ssi_signo), si->ssi_code);
return 0;
}
(void) pid_get_comm(si->ssi_pid, &comm);
if (si->ssi_code != SI_QUEUE) {
+6
View File
@@ -23,6 +23,7 @@
#include "process-util.h"
#include "rm-rf.h"
#include "set.h"
#include "signal-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "udev-manager.h"
@@ -611,6 +612,11 @@ int manager_remove_watch(Manager *manager, sd_device *dev) {
static int on_sigusr1(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
UdevWorker *worker = ASSERT_PTR(userdata);
if (!si_code_from_process(si->ssi_code)) {
log_debug("Received SIGUSR1 with unexpected .si_code %i, ignoring.", si->ssi_code);
return 0;
}
if ((pid_t) si->ssi_pid != worker->manager_pid) {
log_debug("Received SIGUSR1 from unexpected process [%"PRIu32"], ignoring.", si->ssi_pid);
return 0;