aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/signal.c')
-rw-r--r--kernel/signal.c133
1 files changed, 127 insertions, 6 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index 5d53183e2705..b7953934aa99 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -19,7 +19,9 @@
19#include <linux/sched/task.h> 19#include <linux/sched/task.h>
20#include <linux/sched/task_stack.h> 20#include <linux/sched/task_stack.h>
21#include <linux/sched/cputime.h> 21#include <linux/sched/cputime.h>
22#include <linux/file.h>
22#include <linux/fs.h> 23#include <linux/fs.h>
24#include <linux/proc_fs.h>
23#include <linux/tty.h> 25#include <linux/tty.h>
24#include <linux/binfmts.h> 26#include <linux/binfmts.h>
25#include <linux/coredump.h> 27#include <linux/coredump.h>
@@ -3487,6 +3489,16 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait_time32, compat_sigset_t __user *, uthese,
3487#endif 3489#endif
3488#endif 3490#endif
3489 3491
3492static inline void prepare_kill_siginfo(int sig, struct kernel_siginfo *info)
3493{
3494 clear_siginfo(info);
3495 info->si_signo = sig;
3496 info->si_errno = 0;
3497 info->si_code = SI_USER;
3498 info->si_pid = task_tgid_vnr(current);
3499 info->si_uid = from_kuid_munged(current_user_ns(), current_uid());
3500}
3501
3490/** 3502/**
3491 * sys_kill - send a signal to a process 3503 * sys_kill - send a signal to a process
3492 * @pid: the PID of the process 3504 * @pid: the PID of the process
@@ -3496,16 +3508,125 @@ SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)
3496{ 3508{
3497 struct kernel_siginfo info; 3509 struct kernel_siginfo info;
3498 3510
3499 clear_siginfo(&info); 3511 prepare_kill_siginfo(sig, &info);
3500 info.si_signo = sig;
3501 info.si_errno = 0;
3502 info.si_code = SI_USER;
3503 info.si_pid = task_tgid_vnr(current);
3504 info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
3505 3512
3506 return kill_something_info(sig, &info, pid); 3513 return kill_something_info(sig, &info, pid);
3507} 3514}
3508 3515
3516#ifdef CONFIG_PROC_FS
3517/*
3518 * Verify that the signaler and signalee either are in the same pid namespace
3519 * or that the signaler's pid namespace is an ancestor of the signalee's pid
3520 * namespace.
3521 */
3522static bool access_pidfd_pidns(struct pid *pid)
3523{
3524 struct pid_namespace *active = task_active_pid_ns(current);
3525 struct pid_namespace *p = ns_of_pid(pid);
3526
3527 for (;;) {
3528 if (!p)
3529 return false;
3530 if (p == active)
3531 break;
3532 p = p->parent;
3533 }
3534
3535 return true;
3536}
3537
3538static int copy_siginfo_from_user_any(kernel_siginfo_t *kinfo, siginfo_t *info)
3539{
3540#ifdef CONFIG_COMPAT
3541 /*
3542 * Avoid hooking up compat syscalls and instead handle necessary
3543 * conversions here. Note, this is a stop-gap measure and should not be
3544 * considered a generic solution.
3545 */
3546 if (in_compat_syscall())
3547 return copy_siginfo_from_user32(
3548 kinfo, (struct compat_siginfo __user *)info);
3549#endif
3550 return copy_siginfo_from_user(kinfo, info);
3551}
3552
3553/**
3554 * sys_pidfd_send_signal - send a signal to a process through a task file
3555 * descriptor
3556 * @pidfd: the file descriptor of the process
3557 * @sig: signal to be sent
3558 * @info: the signal info
3559 * @flags: future flags to be passed
3560 *
3561 * The syscall currently only signals via PIDTYPE_PID which covers
3562 * kill(<positive-pid>, <signal>. It does not signal threads or process
3563 * groups.
3564 * In order to extend the syscall to threads and process groups the @flags
3565 * argument should be used. In essence, the @flags argument will determine
3566 * what is signaled and not the file descriptor itself. Put in other words,
3567 * grouping is a property of the flags argument not a property of the file
3568 * descriptor.
3569 *
3570 * Return: 0 on success, negative errno on failure
3571 */
3572SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig,
3573 siginfo_t __user *, info, unsigned int, flags)
3574{
3575 int ret;
3576 struct fd f;
3577 struct pid *pid;
3578 kernel_siginfo_t kinfo;
3579
3580 /* Enforce flags be set to 0 until we add an extension. */
3581 if (flags)
3582 return -EINVAL;
3583
3584 f = fdget_raw(pidfd);
3585 if (!f.file)
3586 return -EBADF;
3587
3588 /* Is this a pidfd? */
3589 pid = tgid_pidfd_to_pid(f.file);
3590 if (IS_ERR(pid)) {
3591 ret = PTR_ERR(pid);
3592 goto err;
3593 }
3594
3595 ret = -EINVAL;
3596 if (!access_pidfd_pidns(pid))
3597 goto err;
3598
3599 if (info) {
3600 ret = copy_siginfo_from_user_any(&kinfo, info);
3601 if (unlikely(ret))
3602 goto err;
3603
3604 ret = -EINVAL;
3605 if (unlikely(sig != kinfo.si_signo))
3606 goto err;
3607
3608 if ((task_pid(current) != pid) &&
3609 (kinfo.si_code >= 0 || kinfo.si_code == SI_TKILL)) {
3610 /* Only allow sending arbitrary signals to yourself. */
3611 ret = -EPERM;
3612 if (kinfo.si_code != SI_USER)
3613 goto err;
3614
3615 /* Turn this into a regular kill signal. */
3616 prepare_kill_siginfo(sig, &kinfo);
3617 }
3618 } else {
3619 prepare_kill_siginfo(sig, &kinfo);
3620 }
3621
3622 ret = kill_pid_info(sig, &kinfo, pid);
3623
3624err:
3625 fdput(f);
3626 return ret;
3627}
3628#endif /* CONFIG_PROC_FS */
3629
3509static int 3630static int
3510do_send_specific(pid_t tgid, pid_t pid, int sig, struct kernel_siginfo *info) 3631do_send_specific(pid_t tgid, pid_t pid, int sig, struct kernel_siginfo *info)
3511{ 3632{