]> xenbits.xensource.com Git - unikraft/unikraft.git/commitdiff
lib/posix-process/signal: Add kill() and sigqueueinfo()
authorMichalis Pappas <michalis@unikraft.io>
Sun, 7 Jan 2024 10:56:16 +0000 (11:56 +0100)
committerUnikraft Bot <monkey@unikraft.io>
Wed, 26 Mar 2025 08:05:34 +0000 (08:05 +0000)
Add syscalls for signalling. Internally these share common
abstractions.

The kill syscalls are used for sending signals to processes,
process groups, or threads:

* kill() allows sending a signal to a process group or process.
* tkill() allows sending a signal to a thread.
* tgkill() allows sending a signal to a thread in thread
  group.

The siqeueueinfo syscalls are similar to kill but additionally
allow to accompany the signal with data:

* rt_sigqueueinfo() allows sending signal and data to a process.
* rt_tgsigqueueinfo() allows sending signal and data to a thread
  in thread group.

For more info see kill(2), tkill(2), rt_sigqueueinfo(2)

Signed-off-by: Michalis Pappas <michalis@unikraft.io>
Reviewed-by: Ioan-Teodor Teugea <ioan_teodor.teugea@stud.acs.upb.ro>
Reviewed-by: Sergiu Moga <sergiu@unikraft.io>
Reviewed-by: Andrei Tatar <andrei@unikraft.io>
Approved-by: Andrei Tatar <andrei@unikraft.io>
GitHub-Closes: #1248

lib/posix-process/Makefile.uk
lib/posix-process/exportsyms.uk
lib/posix-process/signal/kill.c [new file with mode: 0644]
lib/posix-process/signal/rt_sigqueueinfo.c [new file with mode: 0644]
lib/posix-process/signal/rt_tgsigqueueinfo.c [new file with mode: 0644]
lib/posix-process/signal/siginfo.h [new file with mode: 0644]
lib/posix-process/signal/signal.c
lib/posix-process/signal/signal.h
lib/posix-process/signal/tgkill.c [new file with mode: 0644]
lib/posix-process/signal/tkill.c [new file with mode: 0644]

index 7c4a61db6f2157baf848390d41c475869092fe14..7fcc5dec47959e4412ac2238c228150278aff409 100644 (file)
@@ -24,6 +24,11 @@ LIBPOSIX_PROCESS_SRCS-y += $(LIBPOSIX_PROCESS_BASE)/signal/sigaltstack.c
 LIBPOSIX_PROCESS_SRCS-y += $(LIBPOSIX_PROCESS_BASE)/signal/rt_sigpending.c
 LIBPOSIX_PROCESS_SRCS-y += $(LIBPOSIX_PROCESS_BASE)/signal/rt_sigprocmask.c
 LIBPOSIX_PROCESS_SRCS-y += $(LIBPOSIX_PROCESS_BASE)/signal/rt_sigaction.c
+LIBPOSIX_PROCESS_SRCS-y += $(LIBPOSIX_PROCESS_BASE)/signal/rt_sigqueueinfo.c
+LIBPOSIX_PROCESS_SRCS-y += $(LIBPOSIX_PROCESS_BASE)/signal/rt_tgsigqueueinfo.c
+LIBPOSIX_PROCESS_SRCS-y += $(LIBPOSIX_PROCESS_BASE)/signal/kill.c
+LIBPOSIX_PROCESS_SRCS-y += $(LIBPOSIX_PROCESS_BASE)/signal/tgkill.c
+LIBPOSIX_PROCESS_SRCS-y += $(LIBPOSIX_PROCESS_BASE)/signal/tkill.c
 
 LIBPOSIX_PROCESS_SRCS-$(CONFIG_LIBPOSIX_PROCESS_CLONE) += $(LIBPOSIX_PROCESS_BASE)/clone.c
 LIBPOSIX_PROCESS_SRCS-$(CONFIG_LIBPOSIX_PROCESS_CLONE) += $(LIBPOSIX_PROCESS_BASE)/clonetab.ld
@@ -41,6 +46,11 @@ UK_PROVIDED_SYSCALLS-$(CONFIG_LIBPOSIX_PROCESS) += sigaltstack-2
 UK_PROVIDED_SYSCALLS-$(CONFIG_LIBPOSIX_PROCESS) += rt_sigpending-2
 UK_PROVIDED_SYSCALLS-$(CONFIG_LIBPOSIX_PROCESS) += rt_sigprocmask-4
 UK_PROVIDED_SYSCALLS-$(CONFIG_LIBPOSIX_PROCESS) += rt_sigaction-4
+UK_PROVIDED_SYSCALLS-$(CONFIG_LIBPOSIX_PROCESS) += rt_sigqueueinfo-3
+UK_PROVIDED_SYSCALLS-$(CONFIG_LIBPOSIX_PROCESS) += rt_tgsigqueueinfo-4
+UK_PROVIDED_SYSCALLS-$(CONFIG_LIBPOSIX_PROCESS) += kill-2
+UK_PROVIDED_SYSCALLS-$(CONFIG_LIBPOSIX_PROCESS) += tgkill-3
+UK_PROVIDED_SYSCALLS-$(CONFIG_LIBPOSIX_PROCESS) += tkill-2
 UK_PROVIDED_SYSCALLS-$(CONFIG_LIBPOSIX_PROCESS_VFORK) += vfork-2e
 UK_PROVIDED_SYSCALLS-$(CONFIG_LIBPOSIX_PROCESS) += wait4-4 waitid-4
 UK_PROVIDED_SYSCALLS-$(CONFIG_LIBPOSIX_PROCESS) += getpgid-1
index 7a705d2c82f17ba3ebe9e5b942c137d0380a6d79..414d9bf4bc8ff72a3d9633ac6d8698913a8b7461 100644 (file)
@@ -42,5 +42,7 @@ uk_posix_process_create
 uk_posix_process_kill
 clone
 vfork
+kill
 sigaltstack
 sigprocmask
+tgkill
diff --git a/lib/posix-process/signal/kill.c b/lib/posix-process/signal/kill.c
new file mode 100644 (file)
index 0000000..833b356
--- /dev/null
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2023, Unikraft GmbH and The Unikraft Authors.
+ * Licensed under the BSD-3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ */
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <uk/syscall.h>
+
+#include "signal.h"
+
+#if CONFIG_LIBPOSIX_PROCESS_SIGNAL
+UK_SYSCALL_R_DEFINE(int, kill, pid_t, pid, int, signum)
+{
+       return pprocess_signal_process_do(pid, signum, NULL);
+}
+#else /* !CONFIG_LIBPOSIX_PROCESS_SIGNAL */
+UK_SYSCALL_R_DEFINE(int, kill, pid_t, pid, int, signum)
+{
+       UK_WARN_STUBBED();
+       return 0;
+}
+#endif /* !CONFIG_LIBPOSIX_PROCESS_SIGNAL */
diff --git a/lib/posix-process/signal/rt_sigqueueinfo.c b/lib/posix-process/signal/rt_sigqueueinfo.c
new file mode 100644 (file)
index 0000000..7cd23bb
--- /dev/null
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2023, Unikraft GmbH and The Unikraft Authors.
+ * Licensed under the BSD-3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ */
+
+#include <errno.h>
+#include <signal.h>
+
+#include <uk/essentials.h>
+#include <uk/process.h>
+#include <uk/syscall.h>
+
+#include "signal.h"
+
+#if CONFIG_LIBPOSIX_PROCESS_SIGNAL
+UK_LLSYSCALL_R_DEFINE(int, rt_sigqueueinfo,
+                     int, tgid,
+                     int, signum,
+                     siginfo_t *, siginfo)
+{
+       if (unlikely(!siginfo))
+               return -EFAULT;
+
+       /* The si_code must be valid when targeting a
+        * different process.
+        */
+       if (unlikely(tgid != uk_sys_getpid() && siginfo->si_code != SI_QUEUE))
+               return -EPERM;
+
+       return pprocess_signal_process_do(tgid, signum, siginfo);
+}
+#else /* !CONFIG_LIBPOSIX_PROCESS_SIGNAL */
+UK_LLSYSCALL_R_DEFINE(int, rt_sigqueueinfo,
+                     int, tgid,
+                     int, signum,
+                     siginfo_t *, siginfo)
+{
+       UK_WARN_STUBBED();
+       return 0;
+}
+#endif /* !CONFIG_LIBPOSIX_PROCESS_SIGNAL */
diff --git a/lib/posix-process/signal/rt_tgsigqueueinfo.c b/lib/posix-process/signal/rt_tgsigqueueinfo.c
new file mode 100644 (file)
index 0000000..b5ad2e4
--- /dev/null
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2023, Unikraft GmbH and The Unikraft Authors.
+ * Licensed under the BSD-3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ */
+
+#include <errno.h>
+#include <signal.h>
+
+#include <uk/essentials.h>
+#include <uk/process.h>
+#include <uk/syscall.h>
+
+#include "signal.h"
+
+#if CONFIG_LIBPOSIX_PROCESS_SIGNAL
+
+UK_LLSYSCALL_R_DEFINE(int, rt_tgsigqueueinfo,
+                     int, tgid, int, tid,
+                     int, signum, siginfo_t *, siginfo)
+{
+       struct posix_process *proc;
+       struct posix_thread *pthread;
+
+       if (unlikely(!IS_VALID(signum)))
+               return -EINVAL;
+
+       if (unlikely(!siginfo))
+               return -EFAULT;
+
+       pthread = tid2pthread(tid);
+       if (unlikely(!pthread))
+               return -EINVAL;
+
+       /* Make sure tid is part of by tgid */
+       proc = tid2pprocess(tid);
+       if (unlikely(!proc || proc->pid != tgid))
+               return -ESRCH;
+
+       /* The si_code must be valid when targeting a
+        * different process.
+        */
+       if (unlikely(siginfo->si_code != SI_QUEUE))
+               return -EPERM;
+
+       return pprocess_signal_thread_do(tid, signum, siginfo);
+}
+#else /* !CONFIG_LIBPOSIX_PROCESS_SIGNAL */
+UK_LLSYSCALL_R_DEFINE(int, rt_tgsigqueueinfo,
+                     int, tgid, int, tid,
+                     int, signum, siginfo_t *, siginfo)
+{
+       UK_WARN_STUBBED();
+       return 0;
+}
+#endif /* !CONFIG_LIBPOSIX_PROCESS_SIGNAL */
diff --git a/lib/posix-process/signal/siginfo.h b/lib/posix-process/signal/siginfo.h
new file mode 100644 (file)
index 0000000..43e3a8d
--- /dev/null
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2023, Unikraft GmbH and The Unikraft Authors.
+ * Licensed under the BSD-3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ */
+
+#ifndef __UK_PROCESS_SIGINFO_H__
+#define __UK_PROCESS_SIGINFO_H__
+
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <uk/process.h>
+
+#include "process.h"
+
+static inline void set_siginfo_kill(int signum, siginfo_t *si)
+{
+       UK_ASSERT(si);
+
+       si->si_signo = signum;
+       si->si_code  = SI_USER;
+       si->si_pid   = uk_sys_getpid();
+       si->si_uid   = 0;
+}
+
+static inline void set_siginfo_sigqueue(int signum, siginfo_t *si,
+                                       siginfo_t *si_usr)
+{
+       UK_ASSERT(si);
+       UK_ASSERT(si_usr);
+
+       si->si_signo = signum;
+
+       /* The remaining fields are set by the caller
+        * without verification.
+        */
+       si->si_code  = si_usr->si_code;
+       si->si_pid   = si_usr->si_pid;
+       si->si_uid   = si_usr->si_uid;
+       si->si_value = si_usr->si_value;
+}
+
+#endif /* __UK_PROCESS_SIGINFO_H__ */
index 924f449c1a9bf4d763c858ab0e878da2d825020a..0620b4cbafb6638a521c5c672c30fc57b4ee8718 100644 (file)
 
 #include "process.h"
 #include "sigset.h"
+#include "siginfo.h"
 #include "signal.h"
 
+/* Check permissions to signal target process.
+ *
+ * For a process to be permitted to send a signal to another
+ * process, its real / effective uid must match the target's
+ * real / saved set-user-id. We don't support these, so we
+ * deliver to every process.
+ */
+#define signal_check_perm(_target_process) true
+
 /* Enqueue signal for a thread or a process
  *
  * Setting pthread to NULL signifies that the signal
@@ -161,6 +171,144 @@ int pprocess_signal_sigaction_new(struct uk_alloc *alloc, struct uk_signal_pdesc
        return 0;
 }
 
+int pprocess_signal_send(struct posix_process *proc, int signum,
+                        siginfo_t *siginfo)
+{
+       struct uk_signal *sig;
+       int rc;
+
+       sig = uk_signal_alloc(proc->_a);
+       if (unlikely(!sig)) {
+               uk_pr_err("Could not allocate signal\n");
+               return -EAGAIN;
+       }
+
+       if (siginfo)
+               set_siginfo_sigqueue(signum, &sig->siginfo, siginfo);
+       else
+               set_siginfo_kill(signum, &sig->siginfo);
+
+       rc = pprocess_signal_enqueue(proc, NULL, sig);
+       if (unlikely(rc)) {
+               /* issue a warning as this may be temporary */
+               uk_pr_warn("Could not queue signal\n");
+               uk_signal_free(proc->_a, sig);
+               return -EAGAIN;
+       }
+
+       return 0;
+}
+
+int pprocess_signal_process_do(pid_t pid, int signum, siginfo_t *siginfo)
+{
+       struct posix_process *pproc = NULL;
+       struct posix_thread *thread, *threadn;
+       int rc;
+
+       if (unlikely(signum != 0 && !IS_VALID(signum)))
+               return -EINVAL;
+
+       if (unlikely(signum == SIGSTOP || signum == SIGCONT)) {
+               uk_pr_warn("Process stop / resume not supported. Ignoring\n");
+               return 0;
+       }
+
+       /* pid == 0 -> Send the signal to every process in the process group
+        *             of the calling process.
+        * pid < -1 -> Send the signal to every process in the process group
+        *             with ID equal to -pid.
+        */
+       if (!pid || pid < -1) {
+               uk_pr_warn("pgroups not supported, delivering to every process\n");
+               pid = -1;
+       }
+
+       /* pid == -1 -> Send the signal to every process for which the
+        *              calling process has permissions to signal.
+        */
+       if (pid == -1) {
+               uk_pprocess_foreach(pproc) {
+                       if (!signal_check_perm(pproc))
+                               continue;
+
+                       if (IS_IGNORED(pproc, signum))
+                               continue;
+
+                       rc = pprocess_signal_send(pproc, signum, siginfo);
+                       if (unlikely(rc))
+                               return rc;
+               }
+               return 0;
+       }
+
+       /* Default: Send to process with pid */
+       pproc = pid2pprocess(pid);
+       if (unlikely(!pproc))
+               return -ESRCH;
+
+       if (unlikely(signal_check_perm(pproc) == false))
+               return -EPERM;
+
+       /* If signum == 0 do only pid exist & permissions check */
+       if (!signum)
+               return 0;
+
+       /* If this signal is currently ignored, don't even try */
+       if (IS_IGNORED(pproc, signum))
+               return 0;
+
+       rc = pprocess_signal_send(pproc, signum, siginfo);
+       if (unlikely(rc))
+               return rc;
+
+       /* Wake up any threads that may be paused */
+       uk_pprocess_foreach_pthread(pproc, thread, threadn) {
+               if (thread->state == POSIX_THREAD_BLOCKED_SIGNAL)
+                       uk_semaphore_up(&thread->signal->deliver_semaphore);
+       }
+
+       return 0;
+}
+
+int pprocess_signal_thread_do(int tid, int signum, siginfo_t *siginfo)
+{
+       struct posix_thread *pthread;
+       struct posix_process *pproc;
+       struct uk_signal *sig;
+       int rc;
+
+       pthread = tid2pthread(tid);
+       if (unlikely(!pthread))
+               return -EINVAL;
+
+       pproc = tid2pprocess(tid);
+       UK_ASSERT(pproc);
+
+       sig = uk_signal_alloc(pthread->_a);
+       if (unlikely(!sig)) {
+               uk_pr_err("Could not allocate signal\n");
+               return -EAGAIN;
+       }
+
+       if (siginfo)
+               set_siginfo_sigqueue(signum, &sig->siginfo, siginfo);
+       else
+               set_siginfo_kill(signum, &sig->siginfo);
+
+       rc = pprocess_signal_enqueue(pproc, pthread, sig);
+       if (unlikely(rc)) {
+               /* issue a warning as this may be temporary */
+               uk_pr_warn("Could not queue signal\n");
+               uk_signal_free(pthread->_a, sig);
+               return rc;
+       }
+
+       if (pthread->state == POSIX_THREAD_BLOCKED_SIGNAL)
+               uk_semaphore_up(&pthread->signal->deliver_semaphore);
+
+       return 0;
+}
+
 int pprocess_signal_pdesc_alloc(struct posix_process *process)
 {
        UK_ASSERT(process);
index d1695ed98a0bfbf688f499d8fd956a7d52585661..fbb7a3d78b1419c187cc816660cdde47fddc6c15 100644 (file)
@@ -252,6 +252,15 @@ void pprocess_signal_clear_pending(struct posix_process *proc, int signum);
 /* Get next pending signal of a given thread */
 struct uk_signal *pprocess_signal_next_pending_t(struct posix_thread *pthread);
 
+/* Signal a process (abstraction for kill / sigqueueinfo) */
+int pprocess_signal_process_do(pid_t pid, int signum, siginfo_t *siginfo);
+
+/* Signal a thread (abstraction for kill / sigqueueinfo) */
+int pprocess_signal_thread_do(int tid, int signum, siginfo_t *siginfo);
+
+/* Signal a process */
+int pprocess_signal_send(struct posix_process *proc, int signum,
+                        siginfo_t *siginfo);
 #endif /* CONFIG_LIBPOSIX_PROCESS_PIDS */
 
 #endif /* __UK_PROCESS_SIGNAL_H__ */
diff --git a/lib/posix-process/signal/tgkill.c b/lib/posix-process/signal/tgkill.c
new file mode 100644 (file)
index 0000000..e98e8aa
--- /dev/null
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2023, Unikraft GmbH and The Unikraft Authors.
+ * Licensed under the BSD-3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ */
+
+#include <errno.h>
+
+#include <uk/process.h>
+#include <uk/syscall.h>
+
+#include "signal.h"
+
+#if CONFIG_LIBPOSIX_PROCESS_SIGNAL
+UK_SYSCALL_R_DEFINE(int, tgkill, int, tgid,
+                   int, tid, int, signum)
+{
+       struct posix_process *pproc;
+
+       /* Chack tid is part of my tgid */
+       pproc = tid2pprocess(tid);
+       if (unlikely(!pproc || pproc->pid != tgid))
+               return -ESRCH;
+
+       return pprocess_signal_thread_do(tid, signum, NULL);
+}
+#else /* !CONFIG_LIBPOSIX_PROCESS_SIGNAL */
+UK_SYSCALL_R_DEFINE(int, tgkill, int, tgid,
+                   int, tid, int, signum)
+{
+       UK_WARN_STUBBED();
+       return 0;
+}
+#endif /* !CONFIG_LIBPOSIX_PROCESS_SIGNAL */
diff --git a/lib/posix-process/signal/tkill.c b/lib/posix-process/signal/tkill.c
new file mode 100644 (file)
index 0000000..27aab5f
--- /dev/null
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2023, Unikraft GmbH and The Unikraft Authors.
+ * Licensed under the BSD-3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ */
+
+#include <stddef.h>
+#include <uk/syscall.h>
+
+#include "signal.h"
+
+#if CONFIG_LIBPOSIX_PROCESS_SIGNAL
+UK_LLSYSCALL_R_DEFINE(int, tkill, int, tid, int, signum)
+{
+       return pprocess_signal_thread_do(tid, signum, NULL);
+}
+#else /* !CONFIG_LIBPOSIX_PROCESS_SIGNAL */
+UK_LLSYSCALL_R_DEFINE(int, tkill, int, tid, int, signum)
+{
+       UK_WARN_STUBBED();
+       return 0;
+}
+#endif /* !CONFIG_LIBPOSIX_PROCESS_SIGNAL */