From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.1 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5D7C2C43441 for ; Mon, 19 Nov 2018 10:33:50 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 0A78220823 for ; Mon, 19 Nov 2018 10:33:49 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=brauner.io header.i=@brauner.io header.b="UY3Ewh34" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0A78220823 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=brauner.io Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728027AbeKSU5A (ORCPT ); Mon, 19 Nov 2018 15:57:00 -0500 Received: from mail-pl1-f193.google.com ([209.85.214.193]:33352 "EHLO mail-pl1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727947AbeKSU47 (ORCPT ); Mon, 19 Nov 2018 15:56:59 -0500 Received: by mail-pl1-f193.google.com with SMTP id z23so3158772plo.0 for ; Mon, 19 Nov 2018 02:33:47 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=brauner.io; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ypnAEQr2pPVfgeHXxl0uTmHsonpkGSyBmX5Kki2tpqc=; b=UY3Ewh34E3OMltOE3MRGyT5QajgQH62bFtxuhu2MdcaUwDEiO3C0TIrgHysgVPq92N cPB5DinoHv41e/1F5xpY6OWsuWs1S3FgWq8oCo1tjRb3EVg4RXa0fXx11GlI9PtoNp+4 K2sLt5ROD/09XsP5Q/r0lHO7TwM55DEKlfl4/k6wRiF9Iv9xURr52gTWqtNEqSZyENAC q0RtV9OfW3C61JzetSanBhhRxRf5MlKvZq1dSrTd4kyLAdFdlnOLKjgkF+lViv+HgLkW idiO85lSPyiTESD8UDsZKFgQ/9eeIUnq5YFed9OviEh2aGhc8HrnwAlaEjkoYXesQ5p7 HQ8w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ypnAEQr2pPVfgeHXxl0uTmHsonpkGSyBmX5Kki2tpqc=; b=GTl1b3HTEOF2QDinNFuo9CdGmDKD54J5omfygOytwGPs8Mp7Q3ABE8vTw2dKI8LZTB 9d6hmkYJL/4Erzdwe4J/NrUP1d2CXSJz8N9mpbuocl50gmKET6KFx6izoDdWp5e99FlE jHor8jXYd9H/hI1IxESCL4SHGewRcimoGqs+7rkJzBffn6kdWuapi5Clims2pl2KdU4Q 5j70ADrH5xt0rYMPaPdPd35bYpXHmRleewvKqXYr2Fcle1hHv7SReoG5IN4QDzC5D+Jv LJlEI14qLakG4w2K/HIAoIsXZ4u5wJrfO4/lBqHQC23JUgsg1OTystCLOLjkG0atHmE2 IInA== X-Gm-Message-State: AGRZ1gJjFOkUpSHd3om/5aCAAwEmKfeY09KO5Zx6TLtQMCrSUc2McLEL xc6iyZ7f0vGjzwVrvv/seLi/pQ== X-Google-Smtp-Source: AJdET5eJSWKr/cCjRL01SE5ntIY8owEi5HuCqcUYm4hrXeOj0yjX8vRS1adQL8OCs5JxC2CyqHktnw== X-Received: by 2002:a17:902:b03:: with SMTP id 3-v6mr21986283plq.233.1542623627048; Mon, 19 Nov 2018 02:33:47 -0800 (PST) Received: from localhost.localdomain ([2404:4404:133a:4500:9d11:de0b:446c:8485]) by smtp.gmail.com with ESMTPSA id d21sm32958139pgv.37.2018.11.19.02.33.40 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 19 Nov 2018 02:33:46 -0800 (PST) From: Christian Brauner To: ebiederm@xmission.com, linux-kernel@vger.kernel.org Cc: serge@hallyn.com, jannh@google.com, luto@kernel.org, akpm@linux-foundation.org, oleg@redhat.com, cyphar@cyphar.com, viro@zeniv.linux.org.uk, linux-fsdevel@vger.kernel.org, linux-api@vger.kernel.org, dancol@google.com, timmurray@google.com, linux-man@vger.kernel.org, Christian Brauner , Kees Cook Subject: [PATCH v1 2/2] signal: add procfd_signal() syscall Date: Mon, 19 Nov 2018 11:32:39 +0100 Message-Id: <20181119103241.5229-3-christian@brauner.io> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181119103241.5229-1-christian@brauner.io> References: <20181119103241.5229-1-christian@brauner.io> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The kill() syscall operates on process identifiers. After a process has exited its pid can be reused by another process. If a caller sends a signal to a reused pid it will end up signaling the wrong process. This issue has often surfaced and there has been a push [1] to address this problem. A prior patch has introduced the ability to get a file descriptor referencing struct pid by opening /proc/. This guarantees a stable handle on a process which can be used to send signals to the referenced process. Discussion has shown that a dedicated syscall is preferable over ioctl()s. Thus, the new syscall procfd_signal() is introduced to solve this problem. It operates on a process file descriptor. The syscall takes an additional siginfo_t and flags argument. If siginfo_t is NULL then procfd_signal() behaves like kill() if it is not NULL it behaves like rt_sigqueueinfo. The flags argument is added to allow for future extensions of this syscall. It currently needs to be passed as 0. With this patch a process can be killed via: #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include int main(int argc, char *argv[]) { int ret; char buf[1000]; if (argc < 2) exit(EXIT_FAILURE); ret = snprintf(buf, sizeof(buf), "/proc/%s", argv[1]); if (ret < 0) exit(EXIT_FAILURE); int fd = open(buf, O_DIRECTORY | O_CLOEXEC); if (fd < 0) { printf("%s - Failed to open \"%s\"\n", strerror(errno), buf); exit(EXIT_FAILURE); } ret = syscall(__NR_procfd_signal, fd, SIGKILL, NULL, 0); if (ret < 0) { printf("Failed to send SIGKILL \"%s\"\n", strerror(errno)); close(fd); exit(EXIT_FAILURE); } close(fd); exit(EXIT_SUCCESS); } [1]: https://lkml.org/lkml/2018/11/18/130 Cc: "Eric W. Biederman" Cc: Serge Hallyn Cc: Jann Horn Cc: Kees Cook Cc: Andy Lutomirsky Cc: Andrew Morton Cc: Oleg Nesterov Cc: Aleksa Sarai Cc: Al Viro Signed-off-by: Christian Brauner --- Changelog: v1: - patch introduced --- arch/x86/entry/syscalls/syscall_32.tbl | 1 + arch/x86/entry/syscalls/syscall_64.tbl | 1 + fs/proc/base.c | 6 ++ include/linux/proc_fs.h | 1 + include/linux/syscalls.h | 2 + kernel/signal.c | 76 ++++++++++++++++++++++++-- 6 files changed, 81 insertions(+), 6 deletions(-) diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl index 3cf7b533b3d1..e637eab883e9 100644 --- a/arch/x86/entry/syscalls/syscall_32.tbl +++ b/arch/x86/entry/syscalls/syscall_32.tbl @@ -398,3 +398,4 @@ 384 i386 arch_prctl sys_arch_prctl __ia32_compat_sys_arch_prctl 385 i386 io_pgetevents sys_io_pgetevents __ia32_compat_sys_io_pgetevents 386 i386 rseq sys_rseq __ia32_sys_rseq +387 i386 procfd_signal sys_procfd_signal __ia32_sys_procfd_signal diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl index f0b1709a5ffb..e95f6741ab42 100644 --- a/arch/x86/entry/syscalls/syscall_64.tbl +++ b/arch/x86/entry/syscalls/syscall_64.tbl @@ -343,6 +343,7 @@ 332 common statx __x64_sys_statx 333 common io_pgetevents __x64_sys_io_pgetevents 334 common rseq __x64_sys_rseq +335 common procfd_signal __x64_sys_procfd_signal # # x32-specific system call numbers start at 512 to avoid cache impact diff --git a/fs/proc/base.c b/fs/proc/base.c index 6365a4fea314..a12c9de92bd0 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -3055,6 +3055,12 @@ static const struct file_operations proc_tgid_base_operations = { .release = proc_tgid_release, }; +bool proc_is_procfd(const struct file *file) +{ + return d_is_dir(file->f_path.dentry) && + (file->f_op == &proc_tgid_base_operations); +} + static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { return proc_pident_lookup(dir, dentry, diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index d0e1f1522a78..2d53a47fba34 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -73,6 +73,7 @@ struct proc_dir_entry *proc_create_net_single_write(const char *name, umode_t mo int (*show)(struct seq_file *, void *), proc_write_t write, void *data); +extern bool proc_is_procfd(const struct file *file); #else /* CONFIG_PROC_FS */ diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 2ac3d13a915b..a5ca8cb84566 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -907,6 +907,8 @@ asmlinkage long sys_statx(int dfd, const char __user *path, unsigned flags, unsigned mask, struct statx __user *buffer); asmlinkage long sys_rseq(struct rseq __user *rseq, uint32_t rseq_len, int flags, uint32_t sig); +asmlinkage long sys_procfd_signal(int fd, int sig, siginfo_t __user *info, + int flags); /* * Architecture-specific system calls diff --git a/kernel/signal.c b/kernel/signal.c index 9a32bc2088c9..e8a8929de710 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -19,7 +19,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -3286,6 +3288,16 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese, } #endif +static inline void prepare_kill_siginfo(int sig, struct kernel_siginfo *info) +{ + clear_siginfo(info); + info->si_signo = sig; + info->si_errno = 0; + info->si_code = SI_USER; + info->si_pid = task_tgid_vnr(current); + info->si_uid = from_kuid_munged(current_user_ns(), current_uid()); +} + /** * sys_kill - send a signal to a process * @pid: the PID of the process @@ -3295,16 +3307,68 @@ SYSCALL_DEFINE2(kill, pid_t, pid, int, sig) { struct kernel_siginfo info; - clear_siginfo(&info); - info.si_signo = sig; - info.si_errno = 0; - info.si_code = SI_USER; - info.si_pid = task_tgid_vnr(current); - info.si_uid = from_kuid_munged(current_user_ns(), current_uid()); + prepare_kill_siginfo(sig, &info); return kill_something_info(sig, &info, pid); } +/** + * sys_procfd_signal - send a signal to a process through a process file + * descriptor + * @fd: the file descriptor of the process + * @sig: signal to be sent + * @info: the signal info + * @flags: future flags to be passed + */ +SYSCALL_DEFINE4(procfd_signal, int, fd, int, sig, siginfo_t __user *, info, + int, flags) +{ + int ret; + struct pid *pid; + kernel_siginfo_t kinfo; + struct fd f; + + /* Enforce flags be set to 0 until we add an extension. */ + if (flags) + return -EINVAL; + + f = fdget_raw(fd); + if (!f.file) + return -EBADF; + + ret = -EINVAL; + /* Is this a process file descriptor? */ + if (!proc_is_procfd(f.file)) + goto err; + + pid = f.file->private_data; + if (!pid) + goto err; + + if (info) { + ret = __copy_siginfo_from_user(sig, &kinfo, info); + if (unlikely(ret)) + goto err; + /* + * Not even root can pretend to send signals from the kernel. + * Nor can they impersonate a kill()/tgkill(), which adds + * source info. + */ + ret = -EPERM; + if ((kinfo.si_code >= 0 || kinfo.si_code == SI_TKILL) && + (task_pid(current) != pid)) + goto err; + } else { + prepare_kill_siginfo(sig, &kinfo); + } + + ret = kill_pid_info(sig, &kinfo, pid); + +err: + fdput(f); + return ret; +} + static int do_send_specific(pid_t tgid, pid_t pid, int sig, struct kernel_siginfo *info) { -- 2.19.1