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);
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);
+}
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));
/* 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);
}
#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"
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;
}
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);
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);
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) {
#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"
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;