From patchwork Wed Dec 18 23:53:28 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sargun Dhillon X-Patchwork-Id: 11302441 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 470B014E3 for ; Wed, 18 Dec 2019 23:53:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 2509A21582 for ; Wed, 18 Dec 2019 23:53:32 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=sargun.me header.i=@sargun.me header.b="xT1nyXIQ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726704AbfLRXxb (ORCPT ); Wed, 18 Dec 2019 18:53:31 -0500 Received: from mail-il1-f193.google.com ([209.85.166.193]:40170 "EHLO mail-il1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726571AbfLRXxb (ORCPT ); Wed, 18 Dec 2019 18:53:31 -0500 Received: by mail-il1-f193.google.com with SMTP id c4so3250887ilo.7 for ; Wed, 18 Dec 2019 15:53:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sargun.me; s=google; h=date:from:to:cc:subject:message-id:mime-version:content-disposition :user-agent; bh=CX/EMM8AnWfaI4rNz03pFAf5OWqiTpv8JaYTV9Mz/lc=; b=xT1nyXIQt4g7KeMROF00XdFlDcMJlPPSB0k5I3q3zaze+uv9zHWUzpmF+Objzre2bE vj6o+i17XYxtdKTLbME0YHvc9u+93nCtPJgQvPOZ+HLlV8cTOfn1j4COrnt5tSc+hgVm YiVFjIW1ovFnH0ZdJLDUwO3b6oyVDhCnjPrSk= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:mime-version :content-disposition:user-agent; bh=CX/EMM8AnWfaI4rNz03pFAf5OWqiTpv8JaYTV9Mz/lc=; b=Qua0DKJWyocwzzHtwl3VRHroQnrtY5o8rtVcl/BfFvoNdR5GVDJJLLp6AO3uFXzD1q IL+P1nD1kqAFePMdmxXjZ6LBnXL/1jpNE53n/QDOYQBOu+DFNDfvTs7OUkGsj0x/yRwK sB7U4xSXNcXXzb1p9QLHwZ3W6X2rdWu0CKSvX4xwVogufNpa/Y5taRC+SbbmApXahFEf hDNeivmZxMUO1P/Khy+VNzeF4CnwSFS9zwgFqVxc7VTUDrQaKypiIsTXZxRssUlzib4X C8jwCYQVqYOzoURdjjSixJqSpT9sz3BVkS2LgtILk2OfLUSIRvSXTSJZesLt7dxAq7sQ hpZg== X-Gm-Message-State: APjAAAXJ5T/u+6xrKMf+4AeCtBABlKck/y3tSt3kLUV6ZciwLckLYGFC ezA5ZUrXlcs363x0GECyk6HNiQ== X-Google-Smtp-Source: APXvYqyDAcI9Qp/Mf2NvtcZBmoftpN5CG8w3ekpYEYJZnQufCnCSCNtzHl+YOdbrHP7vL+XPt9RsIw== X-Received: by 2002:a92:8307:: with SMTP id f7mr4208307ild.183.1576713210234; Wed, 18 Dec 2019 15:53:30 -0800 (PST) Received: from ircssh-2.c.rugged-nimbus-611.internal (80.60.198.104.bc.googleusercontent.com. [104.198.60.80]) by smtp.gmail.com with ESMTPSA id h6sm789370iom.43.2019.12.18.15.53.29 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 18 Dec 2019 15:53:30 -0800 (PST) Date: Wed, 18 Dec 2019 23:53:28 +0000 From: Sargun Dhillon To: linux-kernel@vger.kernel.org, containers@lists.linux-foundation.org, linux-api@vger.kernel.org, linux-fsdevel@vger.kernel.org Cc: tycho@tycho.ws, jannh@google.com, cyphar@cyphar.com, christian.brauner@ubuntu.com, oleg@redhat.com, luto@amacapital.net, viro@zeniv.linux.org.uk, gpascutto@mozilla.com, ealvarez@mozilla.com, fweimer@redhat.com, jld@mozilla.com, arnd@arndb.de Subject: [PATCH v4 1/5] vfs, fdtable: Add get_task_file helper Message-ID: <20191218235326.GA17265@ircssh-2.c.rugged-nimbus-611.internal> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.24 (2015-08-30) Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org This introduces a function which can be used to fetch a file, given an arbitrary task. As long as the user holds a reference (refcnt) to the task_struct it is safe to call, and will either return NULL on failure, or a pointer to the file, with a refcnt. Signed-off-by: Sargun Dhillon --- fs/file.c | 22 ++++++++++++++++++++-- include/linux/file.h | 2 ++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/fs/file.c b/fs/file.c index 2f4fcf985079..0ceeb046f4f3 100644 --- a/fs/file.c +++ b/fs/file.c @@ -706,9 +706,9 @@ void do_close_on_exec(struct files_struct *files) spin_unlock(&files->file_lock); } -static struct file *__fget(unsigned int fd, fmode_t mask, unsigned int refs) +static struct file *__fget_files(struct files_struct *files, unsigned int fd, + fmode_t mask, unsigned int refs) { - struct files_struct *files = current->files; struct file *file; rcu_read_lock(); @@ -729,6 +729,11 @@ static struct file *__fget(unsigned int fd, fmode_t mask, unsigned int refs) return file; } +static struct file *__fget(unsigned int fd, fmode_t mask, unsigned int refs) +{ + return __fget_files(current->files, fd, mask, refs); +} + struct file *fget_many(unsigned int fd, unsigned int refs) { return __fget(fd, FMODE_PATH, refs); @@ -746,6 +751,19 @@ struct file *fget_raw(unsigned int fd) } EXPORT_SYMBOL(fget_raw); +struct file *fget_task(struct task_struct *task, unsigned int fd) +{ + struct file *file = NULL; + + task_lock(task); + if (task->files) + file = __fget_files(task->files, fd, 0, 1); + + task_unlock(task); + + return file; +} + /* * Lightweight file lookup - no refcnt increment if fd table isn't shared. * diff --git a/include/linux/file.h b/include/linux/file.h index 3fcddff56bc4..c6c7b24ea9f7 100644 --- a/include/linux/file.h +++ b/include/linux/file.h @@ -16,6 +16,7 @@ extern void fput(struct file *); extern void fput_many(struct file *, unsigned int); struct file_operations; +struct task_struct; struct vfsmount; struct dentry; struct inode; @@ -47,6 +48,7 @@ static inline void fdput(struct fd fd) extern struct file *fget(unsigned int fd); extern struct file *fget_many(unsigned int fd, unsigned int refs); extern struct file *fget_raw(unsigned int fd); +extern struct file *fget_task(struct task_struct *task, unsigned int fd); extern unsigned long __fdget(unsigned int fd); extern unsigned long __fdget_raw(unsigned int fd); extern unsigned long __fdget_pos(unsigned int fd); From patchwork Wed Dec 18 23:55:01 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sargun Dhillon X-Patchwork-Id: 11302443 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D582A14E3 for ; Wed, 18 Dec 2019 23:55:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id A631622314 for ; Wed, 18 Dec 2019 23:55:05 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=sargun.me header.i=@sargun.me header.b="A2p+MAMq" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726623AbfLRXzE (ORCPT ); Wed, 18 Dec 2019 18:55:04 -0500 Received: from mail-il1-f193.google.com ([209.85.166.193]:45936 "EHLO mail-il1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726559AbfLRXzE (ORCPT ); Wed, 18 Dec 2019 18:55:04 -0500 Received: by mail-il1-f193.google.com with SMTP id p8so3224745iln.12 for ; Wed, 18 Dec 2019 15:55:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sargun.me; s=google; h=date:from:to:cc:subject:message-id:mime-version:content-disposition :user-agent; bh=7Lr3kTkvItIIpHjMeDA8GxtDtNg/P3eKulqPK+7nAVw=; b=A2p+MAMq4LUN7tkM+pO+4I1Mjb7gQUd7ZkYMZtb6d0lEkrTN/GsHc4K3FoSsAFJtyu 8xLR7qXkszqIjGfNzcRpPTUunLgomUwaJNfdRpOfSu7r1clMLJ2lrcJMr6mlmoVJkTR/ fYMFAzpM0pyVICBd8Q4omVAVYwRu7jgpvDLHY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:mime-version :content-disposition:user-agent; bh=7Lr3kTkvItIIpHjMeDA8GxtDtNg/P3eKulqPK+7nAVw=; b=OM0SB2/Cwo8dsfYb194FshzhqF/l4uSy0YOuFYxtqZZVTQwb8Jm2F2+8eiEUY/Xt1x /qrm35Yel/S7xYxz32Cfw5iNZqtIqE2nPYbhK8sDIOAgB47eVoGg90pc2gsgXqD8KfiM RfjvML2a2svedGCZfo6yiRFx6+3iilTJG+JMHtfKhlSOOvCjzDUvFCcGrxlswHx6mHub 5IWU6cH0JfDLfKxPBzvR4ie74IvpafFEc0SeCxI29oodkruxZcHN0tROxJ5rxn2ZsM2k UBaqqxjE5YZo+RTsQEuPIrtQxXbfKB4+G+M9YgCF+0CCmqLCqTFvpEFaMvVgEVuKfolr pajQ== X-Gm-Message-State: APjAAAVITwhukr/ofiy65kBcHy07zQDEmrLjbdSz2pCUab556fvpJdxB XMbaOhlS6+RdOfTHSds892j9Fg== X-Google-Smtp-Source: APXvYqzybGUSUeJ3Zlzi93nDfkx+ie/7+AIqeAPKutkA3q5osrsoEu83slkGf7ZHiB87OBYjvh1zkA== X-Received: by 2002:a92:cc42:: with SMTP id t2mr4453841ilq.111.1576713303449; Wed, 18 Dec 2019 15:55:03 -0800 (PST) Received: from ircssh-2.c.rugged-nimbus-611.internal (80.60.198.104.bc.googleusercontent.com. [104.198.60.80]) by smtp.gmail.com with ESMTPSA id s4sm1144794ilp.21.2019.12.18.15.55.03 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 18 Dec 2019 15:55:03 -0800 (PST) Date: Wed, 18 Dec 2019 23:55:01 +0000 From: Sargun Dhillon To: linux-kernel@vger.kernel.org, containers@lists.linux-foundation.org, linux-api@vger.kernel.org, linux-fsdevel@vger.kernel.org Cc: tycho@tycho.ws, jannh@google.com, cyphar@cyphar.com, christian.brauner@ubuntu.com, oleg@redhat.com, luto@amacapital.net, viro@zeniv.linux.org.uk, gpascutto@mozilla.com, ealvarez@mozilla.com, fweimer@redhat.com, jld@mozilla.com, arnd@arndb.de Subject: [PATCH v4 2/5] pid: Add PIDFD_IOCTL_GETFD to fetch file descriptors from processes Message-ID: <20191218235459.GA17271@ircssh-2.c.rugged-nimbus-611.internal> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.24 (2015-08-30) Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org This adds an ioctl which allows file descriptors to be extracted from processes based on their pidfd. One reason to use this is to allow sandboxers to take actions on file descriptors on the behalf of another process. For example, this can be combined with seccomp-bpf's user notification to do on-demand fd extraction and take privileged actions. For example, it can be used to bind a socket to a privileged port. This is similar to ptrace, and using ptrace parasitic code injection to extract a file descriptor from a process, but without breaking debuggers, or paying the ptrace overhead cost. You must have the ability to ptrace the process in order to extract any file descriptors from it. ptrace can already be used to extract file descriptors based on parasitic code injections, so the permissions model is aligned. The ioctl takes a pointer to pidfd_getfd_args. pidfd_getfd_args contains a size, which allows for gradual evolution of the API. There is an options field, which can be used to state whether the fd should be opened with CLOEXEC, or not. An additional options field may be added in the future to include the ability to clear cgroup information about the file descriptor at a later point. If the structure is from a newer kernel, and includes members which make it larger than the structure that's known to this kernel version, E2BIG will be returned. Signed-off-by: Sargun Dhillon --- .../userspace-api/ioctl/ioctl-number.rst | 1 + MAINTAINERS | 1 + include/uapi/linux/pidfd.h | 10 +++ kernel/fork.c | 77 +++++++++++++++++++ 4 files changed, 89 insertions(+) create mode 100644 include/uapi/linux/pidfd.h diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst index 4ef86433bd67..9f9be681662b 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -273,6 +273,7 @@ Code Seq# Include File Comments 'p' A1-A5 linux/pps.h LinuxPPS +'p' B0-CF linux/pidfd.h 'q' 00-1F linux/serio.h 'q' 80-FF linux/telephony.h Internet PhoneJACK, Internet LineJACK linux/ixjuser.h diff --git a/MAINTAINERS b/MAINTAINERS index cc0a4a8ae06a..bc370ff59dbf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13014,6 +13014,7 @@ M: Christian Brauner L: linux-kernel@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux.git +F: include/uapi/linux/pidfd.h F: samples/pidfd/ F: tools/testing/selftests/pidfd/ F: tools/testing/selftests/clone3/ diff --git a/include/uapi/linux/pidfd.h b/include/uapi/linux/pidfd.h new file mode 100644 index 000000000000..90ff535be048 --- /dev/null +++ b/include/uapi/linux/pidfd.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_PID_H +#define _UAPI_LINUX_PID_H + +#include +#include + +#define PIDFD_IOCTL_GETFD _IOWR('p', 0xb0, __u32) + +#endif /* _UAPI_LINUX_PID_H */ diff --git a/kernel/fork.c b/kernel/fork.c index 2508a4f238a3..09b5f233b5a8 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -94,6 +94,7 @@ #include #include #include +#include #include #include @@ -1790,9 +1791,85 @@ static __poll_t pidfd_poll(struct file *file, struct poll_table_struct *pts) return poll_flags; } +static struct file *__pidfd_getfd_fget_task(struct task_struct *task, u32 fd) +{ + struct file *file; + int ret; + + ret = mutex_lock_killable(&task->signal->cred_guard_mutex); + if (ret) + return ERR_PTR(ret); + + if (!ptrace_may_access(task, PTRACE_MODE_READ_REALCREDS)) { + file = ERR_PTR(-EPERM); + goto out; + } + + file = fget_task(task, fd); + if (!file) + file = ERR_PTR(-EBADF); + +out: + mutex_unlock(&task->signal->cred_guard_mutex); + return file; +} + +static long pidfd_getfd(struct pid *pid, u32 fd) +{ + struct task_struct *task; + struct file *file; + int ret, retfd; + + task = get_pid_task(pid, PIDTYPE_PID); + if (!task) + return -ESRCH; + + file = __pidfd_getfd_fget_task(task, fd); + put_task_struct(task); + if (IS_ERR(file)) + return PTR_ERR(file); + + retfd = get_unused_fd_flags(O_CLOEXEC); + if (retfd < 0) { + ret = retfd; + goto out; + } + + /* + * security_file_receive must come last since it may have side effects + * and cannot be reversed. + */ + ret = security_file_receive(file); + if (ret) + goto out_put_fd; + + fd_install(retfd, file); + return retfd; + +out_put_fd: + put_unused_fd(retfd); +out: + fput(file); + return ret; +} + +static long pidfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct pid *pid = file->private_data; + + switch (cmd) { + case PIDFD_IOCTL_GETFD: + return pidfd_getfd(pid, arg); + default: + return -EINVAL; + } +} + const struct file_operations pidfd_fops = { .release = pidfd_release, .poll = pidfd_poll, + .unlocked_ioctl = pidfd_ioctl, + .compat_ioctl = compat_ptr_ioctl, #ifdef CONFIG_PROC_FS .show_fdinfo = pidfd_show_fdinfo, #endif From patchwork Wed Dec 18 23:55:11 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sargun Dhillon X-Patchwork-Id: 11302445 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7E2BC14E3 for ; Wed, 18 Dec 2019 23:55:15 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 51DD824650 for ; Wed, 18 Dec 2019 23:55:15 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=sargun.me header.i=@sargun.me header.b="Fu6vHjGl" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726726AbfLRXzO (ORCPT ); Wed, 18 Dec 2019 18:55:14 -0500 Received: from mail-il1-f193.google.com ([209.85.166.193]:35515 "EHLO mail-il1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726609AbfLRXzO (ORCPT ); Wed, 18 Dec 2019 18:55:14 -0500 Received: by mail-il1-f193.google.com with SMTP id g12so3273472ild.2 for ; Wed, 18 Dec 2019 15:55:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sargun.me; s=google; h=date:from:to:cc:subject:message-id:mime-version:content-disposition :user-agent; bh=jNutB9PnCuNZ95WEy1zSnjhlufU614JfWZptXrTBQH4=; b=Fu6vHjGlL/GH1eV7tcptnhPDdnMaMlZ1u+cSr49T/PE6mngY6Wl88yR722XZyQQ0I8 vKoXDoyxZW+QZhUxLFqja9SGdiGpmLIlezzZOUbZkH3GE+rc/84pWH5jMHEdvoIrKz+D PlASsYGepBq/8ggsXjtrtc4Jbvllp12UZTN6w= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:mime-version :content-disposition:user-agent; bh=jNutB9PnCuNZ95WEy1zSnjhlufU614JfWZptXrTBQH4=; b=HpwXh0Ov1FlOZ1W4RTnWVFNJddWkAEqB0+bHGRIXkNAMtwAO77pVXF7J0qRrofRxQc 8+j+7nM1rLy2qRG8VdklvpkfzAXUUIdZq+JO9xC7ra2TZD+9inbdfLI0PSWKYKx1nHV1 xz9bv8U5ybNPc5kMsIQAJO97KLvQxs+tFUV67h9m4SWPfwHmojMXiRqyRQZ5gG293Od5 uUFQZ53dxa0nfW4xy/FehX1SKnF5l7lfeKUMBIZn3hfe69jEO53Is64utnu4OeGA6Poz MOyOQcqdU89Y1kPx7Tr6szBw1qGwouZd67NGWcUDxARa/KwWAbGLXypEKGaAvb5NvYmh ri9A== X-Gm-Message-State: APjAAAXdSqtuqlh6G2m9OtEEG22NraUR/VOM9i9bzyTMp6x+3njZ813v pzYDNnpI8uKJTCCu4YSoEYDe4p+V4vfOhg== X-Google-Smtp-Source: APXvYqyQEzZ1r3wOrmUcpTCYhPv7/5LplJLrf51wTid4y7ubYaS1Jyw0E+Pn0DuEdiRc/vd6mELNvg== X-Received: by 2002:a92:da41:: with SMTP id p1mr4211134ilq.65.1576713313028; Wed, 18 Dec 2019 15:55:13 -0800 (PST) Received: from ircssh-2.c.rugged-nimbus-611.internal (80.60.198.104.bc.googleusercontent.com. [104.198.60.80]) by smtp.gmail.com with ESMTPSA id 8sm1156266ilq.85.2019.12.18.15.55.12 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 18 Dec 2019 15:55:12 -0800 (PST) Date: Wed, 18 Dec 2019 23:55:11 +0000 From: Sargun Dhillon To: linux-kernel@vger.kernel.org, containers@lists.linux-foundation.org, linux-api@vger.kernel.org, linux-fsdevel@vger.kernel.org Cc: tycho@tycho.ws, jannh@google.com, cyphar@cyphar.com, christian.brauner@ubuntu.com, oleg@redhat.com, luto@amacapital.net, viro@zeniv.linux.org.uk, gpascutto@mozilla.com, ealvarez@mozilla.com, fweimer@redhat.com, jld@mozilla.com, arnd@arndb.de Subject: [PATCH v4 3/5] samples: split generalized user-trap code into helper file Message-ID: <20191218235508.GA17277@ircssh-2.c.rugged-nimbus-611.internal> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.24 (2015-08-30) Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org This moves the code for setting up a syscall interceptor with user notification and sending the user notification file descriptor over a socket using SCM_RIGHTS into a file that can be shared between multiple samples. Signed-off-by: Sargun Dhillon --- samples/seccomp/Makefile | 6 ++- samples/seccomp/user-trap-helper.c | 84 +++++++++++++++++++++++++++++ samples/seccomp/user-trap-helper.h | 13 +++++ samples/seccomp/user-trap.c | 85 +----------------------------- 4 files changed, 103 insertions(+), 85 deletions(-) create mode 100644 samples/seccomp/user-trap-helper.c create mode 100644 samples/seccomp/user-trap-helper.h diff --git a/samples/seccomp/Makefile b/samples/seccomp/Makefile index 009775b52538..82b7347318d1 100644 --- a/samples/seccomp/Makefile +++ b/samples/seccomp/Makefile @@ -16,9 +16,13 @@ HOSTCFLAGS_bpf-direct.o += -I$(objtree)/usr/include HOSTCFLAGS_bpf-direct.o += -idirafter $(objtree)/include bpf-direct-objs := bpf-direct.o + +HOSTCFLAGS_user-trap-helper.o += -I$(objtree)/usr/include +HOSTCFLAGS_user-trap-helper.o += -idirafter $(objtree)/include + HOSTCFLAGS_user-trap.o += -I$(objtree)/usr/include HOSTCFLAGS_user-trap.o += -idirafter $(objtree)/include -user-trap-objs := user-trap.o +user-trap-objs := user-trap.o user-trap-helper.o # Try to match the kernel target. ifndef CONFIG_64BIT diff --git a/samples/seccomp/user-trap-helper.c b/samples/seccomp/user-trap-helper.c new file mode 100644 index 000000000000..f91ae9d947c5 --- /dev/null +++ b/samples/seccomp/user-trap-helper.c @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "user-trap-helper.h" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) + +int user_trap_syscall(int nr, unsigned int flags) +{ + struct sock_filter filter[] = { + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, + offsetof(struct seccomp_data, nr)), + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, nr, 0, 1), + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_USER_NOTIF), + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), + }; + + struct sock_fprog prog = { + .len = (unsigned short)ARRAY_SIZE(filter), + .filter = filter, + }; + + return seccomp(SECCOMP_SET_MODE_FILTER, flags, &prog); +} + +int send_fd(int sock, int fd) +{ + struct msghdr msg = {}; + struct cmsghdr *cmsg; + char buf[CMSG_SPACE(sizeof(int))] = {0}, c = 'c'; + struct iovec io = { + .iov_base = &c, + .iov_len = 1, + }; + + msg.msg_iov = &io; + msg.msg_iovlen = 1; + msg.msg_control = buf; + msg.msg_controllen = sizeof(buf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + *((int *)CMSG_DATA(cmsg)) = fd; + msg.msg_controllen = cmsg->cmsg_len; + + if (sendmsg(sock, &msg, 0) < 0) { + perror("sendmsg"); + return -1; + } + + return 0; +} + +int recv_fd(int sock) +{ + struct msghdr msg = {}; + struct cmsghdr *cmsg; + char buf[CMSG_SPACE(sizeof(int))] = {0}, c = 'c'; + struct iovec io = { + .iov_base = &c, + .iov_len = 1, + }; + + msg.msg_iov = &io; + msg.msg_iovlen = 1; + msg.msg_control = buf; + msg.msg_controllen = sizeof(buf); + + if (recvmsg(sock, &msg, 0) < 0) { + perror("recvmsg"); + return -1; + } + + cmsg = CMSG_FIRSTHDR(&msg); + + return *((int *)CMSG_DATA(cmsg)); +} diff --git a/samples/seccomp/user-trap-helper.h b/samples/seccomp/user-trap-helper.h new file mode 100644 index 000000000000..a5ebda25fdfe --- /dev/null +++ b/samples/seccomp/user-trap-helper.h @@ -0,0 +1,13 @@ +#include +#include +#include + +static inline int seccomp(unsigned int op, unsigned int flags, void *args) +{ + errno = 0; + return syscall(__NR_seccomp, op, flags, args); +} + +int user_trap_syscall(int nr, unsigned int flags); +int send_fd(int sock, int fd); +int recv_fd(int sock); diff --git a/samples/seccomp/user-trap.c b/samples/seccomp/user-trap.c index 6d0125ca8af7..1b6526587456 100644 --- a/samples/seccomp/user-trap.c +++ b/samples/seccomp/user-trap.c @@ -5,101 +5,18 @@ #include #include #include -#include #include #include #include #include #include #include -#include #include #include -#include #include #include -#include #include - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) - -static int seccomp(unsigned int op, unsigned int flags, void *args) -{ - errno = 0; - return syscall(__NR_seccomp, op, flags, args); -} - -static int send_fd(int sock, int fd) -{ - struct msghdr msg = {}; - struct cmsghdr *cmsg; - char buf[CMSG_SPACE(sizeof(int))] = {0}, c = 'c'; - struct iovec io = { - .iov_base = &c, - .iov_len = 1, - }; - - msg.msg_iov = &io; - msg.msg_iovlen = 1; - msg.msg_control = buf; - msg.msg_controllen = sizeof(buf); - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - *((int *)CMSG_DATA(cmsg)) = fd; - msg.msg_controllen = cmsg->cmsg_len; - - if (sendmsg(sock, &msg, 0) < 0) { - perror("sendmsg"); - return -1; - } - - return 0; -} - -static int recv_fd(int sock) -{ - struct msghdr msg = {}; - struct cmsghdr *cmsg; - char buf[CMSG_SPACE(sizeof(int))] = {0}, c = 'c'; - struct iovec io = { - .iov_base = &c, - .iov_len = 1, - }; - - msg.msg_iov = &io; - msg.msg_iovlen = 1; - msg.msg_control = buf; - msg.msg_controllen = sizeof(buf); - - if (recvmsg(sock, &msg, 0) < 0) { - perror("recvmsg"); - return -1; - } - - cmsg = CMSG_FIRSTHDR(&msg); - - return *((int *)CMSG_DATA(cmsg)); -} - -static int user_trap_syscall(int nr, unsigned int flags) -{ - struct sock_filter filter[] = { - BPF_STMT(BPF_LD+BPF_W+BPF_ABS, - offsetof(struct seccomp_data, nr)), - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, nr, 0, 1), - BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_USER_NOTIF), - BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), - }; - - struct sock_fprog prog = { - .len = (unsigned short)ARRAY_SIZE(filter), - .filter = filter, - }; - - return seccomp(SECCOMP_SET_MODE_FILTER, flags, &prog); -} +#include "user-trap-helper.h" static int handle_req(struct seccomp_notif *req, struct seccomp_notif_resp *resp, int listener) From patchwork Wed Dec 18 23:55:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sargun Dhillon X-Patchwork-Id: 11302447 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1B06B921 for ; Wed, 18 Dec 2019 23:55:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id DF988222C2 for ; Wed, 18 Dec 2019 23:55:51 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=sargun.me header.i=@sargun.me header.b="0eEjh/Od" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726725AbfLRXzo (ORCPT ); Wed, 18 Dec 2019 18:55:44 -0500 Received: from mail-il1-f194.google.com ([209.85.166.194]:36077 "EHLO mail-il1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726536AbfLRXzn (ORCPT ); Wed, 18 Dec 2019 18:55:43 -0500 Received: by mail-il1-f194.google.com with SMTP id b15so3251951iln.3 for ; Wed, 18 Dec 2019 15:55:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sargun.me; s=google; h=date:from:to:cc:subject:message-id:mime-version:content-disposition :user-agent; bh=bsnkXvaQ10kV4zp6dMk/ZIEKA3y1WpZ3zC9oUJDDtdc=; b=0eEjh/OdXeIgj1aM+Oh0HGrXT18ou7SPtI0uu6STMMXHzd+/P0jiJg6aZXHKPs9WF2 Lf7dzYsADi2eixaE/+87i6jd70S4iS40f14z2dq8omFw2tq79VSEXHZ5MaCzZRtDPz4q j2ZcBoOsXVy2jKuDlDWkNM5ivXZOtHQ2tr9LQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:mime-version :content-disposition:user-agent; bh=bsnkXvaQ10kV4zp6dMk/ZIEKA3y1WpZ3zC9oUJDDtdc=; b=V8UQeY5fq9CDC8fMBxxYxSl3c8w9lhbHgPCkdwkhG/ZKuGPoZO00SJzvmFxxc6Sj0G 463Hc+tazQeY3GZaysgi4FgvVNblXK+NqLpqkxWmlbOKUIrm5JdIZ4HEE4vYlAQADFNH h0zY5hVRxLi4BAhF8WvBShlpDQowyMOredES0mdkFOYQrSoz7p7peKvSULjsF9XzH4Hy 2TSz9x3rRyOkA0MPFJPTUBF+r19adKUowMReTQ+K3UWN2BlWqzywD4zpWiKOhLkjDDKt 0Jd7PJkIlvnce89Na5H4G80CWNYPHOgXBKLdQXEtEKXbiMZGksMr4gIsuqrtfzsl/nwL Ohsg== X-Gm-Message-State: APjAAAWLlunDHLx+dLs2gLcflbrA4dUupe8geJwMwM8RBNJ5Kqueeo4i 37yymAz3hQ1uKJnihkcJ0+UKhw== X-Google-Smtp-Source: APXvYqyLi/IAbJ3dTC0X8anY2lW59DQH0iawE3xmYPpzw17E1PpQfk+e44xl8dYr9z7EhMAjT8y5vw== X-Received: by 2002:a92:ab0b:: with SMTP id v11mr4147786ilh.159.1576713342545; Wed, 18 Dec 2019 15:55:42 -0800 (PST) Received: from ircssh-2.c.rugged-nimbus-611.internal (80.60.198.104.bc.googleusercontent.com. [104.198.60.80]) by smtp.gmail.com with ESMTPSA id p5sm1135927ilg.69.2019.12.18.15.55.41 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 18 Dec 2019 15:55:41 -0800 (PST) Date: Wed, 18 Dec 2019 23:55:40 +0000 From: Sargun Dhillon To: linux-kernel@vger.kernel.org, containers@lists.linux-foundation.org, linux-api@vger.kernel.org, linux-fsdevel@vger.kernel.org Cc: tycho@tycho.ws, jannh@google.com, cyphar@cyphar.com, christian.brauner@ubuntu.com, oleg@redhat.com, luto@amacapital.net, viro@zeniv.linux.org.uk, gpascutto@mozilla.com, ealvarez@mozilla.com, fweimer@redhat.com, jld@mozilla.com, arnd@arndb.de Subject: [PATCH v4 4/5] samples: Add example of using pidfd getfd in conjunction with user trap Message-ID: <20191218235538.GA17292@ircssh-2.c.rugged-nimbus-611.internal> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.24 (2015-08-30) Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org This sample adds the usage of SECCOMP_RET_USER_NOTIF together with pidfd GETFD ioctl. It shows trapping a syscall, and handling it by extracting the FD into the parent process without stopping the child process. Although, in this example, there's no explicit policy separation in the two processes, it can be generalized into the example of a transparent proxy. Signed-off-by: Sargun Dhillon --- samples/seccomp/.gitignore | 1 + samples/seccomp/Makefile | 9 +- samples/seccomp/user-trap-pidfd.c | 185 ++++++++++++++++++++++++++++++ 3 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 samples/seccomp/user-trap-pidfd.c diff --git a/samples/seccomp/.gitignore b/samples/seccomp/.gitignore index d1e2e817d556..f37e3692a1dd 100644 --- a/samples/seccomp/.gitignore +++ b/samples/seccomp/.gitignore @@ -2,3 +2,4 @@ bpf-direct bpf-fancy dropper user-trap +user-trap-pidfd diff --git a/samples/seccomp/Makefile b/samples/seccomp/Makefile index 82b7347318d1..c3880869cadc 100644 --- a/samples/seccomp/Makefile +++ b/samples/seccomp/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 ifndef CROSS_COMPILE -hostprogs-y := bpf-fancy dropper bpf-direct user-trap +hostprogs-y := bpf-fancy dropper bpf-direct user-trap user-trap-pidfd HOSTCFLAGS_bpf-fancy.o += -I$(objtree)/usr/include HOSTCFLAGS_bpf-fancy.o += -idirafter $(objtree)/include @@ -24,6 +24,11 @@ HOSTCFLAGS_user-trap.o += -I$(objtree)/usr/include HOSTCFLAGS_user-trap.o += -idirafter $(objtree)/include user-trap-objs := user-trap.o user-trap-helper.o +HOSTCFLAGS_user-trap-pidfd.o += -I$(objtree)/usr/include +HOSTCFLAGS_user-trap-pidfd.o += -idirafter $(objtree)/include +user-trap-pidfd-objs := user-trap-pidfd.o user-trap-helper.o + + # Try to match the kernel target. ifndef CONFIG_64BIT @@ -39,10 +44,12 @@ HOSTCFLAGS_dropper.o += $(MFLAG) HOSTCFLAGS_bpf-helper.o += $(MFLAG) HOSTCFLAGS_bpf-fancy.o += $(MFLAG) HOSTCFLAGS_user-trap.o += $(MFLAG) +HOSTCFLAGS_user-trap-pidfd.o += $(MFLAG) HOSTLDLIBS_bpf-direct += $(MFLAG) HOSTLDLIBS_bpf-fancy += $(MFLAG) HOSTLDLIBS_dropper += $(MFLAG) HOSTLDLIBS_user-trap += $(MFLAG) +HOSTLDLIBS_user-trap-pidfd += $(MFLAG) endif always := $(hostprogs-y) endif diff --git a/samples/seccomp/user-trap-pidfd.c b/samples/seccomp/user-trap-pidfd.c new file mode 100644 index 000000000000..bd5730347a81 --- /dev/null +++ b/samples/seccomp/user-trap-pidfd.c @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "user-trap-helper.h" + +#define CHILD_PORT_TRY_BIND 80 +#define CHILD_PORT_ACTUAL_BIND 4998 + +static int tracee(void) +{ + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = htons(CHILD_PORT_TRY_BIND), + .sin_addr = { + .s_addr = htonl(INADDR_ANY) + } + }; + socklen_t addrlen = sizeof(addr); + int sock, ret = 1; + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == -1) { + perror("socket"); + goto out; + } + + + if (bind(sock, (struct sockaddr *) &addr, sizeof(addr))) { + perror("bind"); + goto out; + } + + printf("Child successfully performed bind operation\n"); + if (getsockname(sock, (struct sockaddr *) &addr, &addrlen)) { + perror("getsockname"); + goto out; + } + + + printf("Socket bound to port %d\n", ntohs(addr.sin_port)); + assert(ntohs(addr.sin_port) == CHILD_PORT_ACTUAL_BIND); + + ret = 0; +out: + return ret; +} + +static int handle_req(int listener, int pidfd) +{ + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = htons(CHILD_PORT_ACTUAL_BIND), + .sin_addr = { + .s_addr = htonl(INADDR_LOOPBACK) + } + }; + struct seccomp_notif_sizes sizes; + struct seccomp_notif_resp *resp; + struct seccomp_notif *req; + int fd, ret = 1; + + if (seccomp(SECCOMP_GET_NOTIF_SIZES, 0, &sizes) < 0) { + perror("seccomp(GET_NOTIF_SIZES)"); + goto out; + } + req = malloc(sizes.seccomp_notif); + if (!req) + goto out; + memset(req, 0, sizeof(*req)); + + resp = malloc(sizes.seccomp_notif_resp); + if (!resp) + goto out_free_req; + memset(resp, 0, sizeof(*resp)); + + if (ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, req)) { + perror("ioctl recv"); + goto out; + } + printf("Child tried to call bind with fd: %lld\n", req->data.args[0]); + fd = ioctl(pidfd, PIDFD_IOCTL_GETFD, req->data.args[0]); + if (fd == -1) { + perror("ioctl pidfd"); + goto out_free_resp; + } + if (bind(fd, (struct sockaddr *) &addr, sizeof(addr))) { + perror("bind"); + goto out_free_resp; + } + + resp->id = req->id; + resp->error = 0; + resp->val = 0; + if (ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, resp) < 0) { + perror("ioctl send"); + goto out_free_resp; + } + + ret = 0; +out_free_resp: + free(resp); +out_free_req: + free(req); +out: + return ret; +} + +static int pidfd_open(pid_t pid, unsigned int flags) +{ + errno = 0; + return syscall(__NR_pidfd_open, pid, flags); +} + +int main(void) +{ + int pidfd, listener, sk_pair[2], ret = 1; + pid_t pid; + + if (socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sk_pair) < 0) { + perror("socketpair"); + goto out; + } + + pid = fork(); + if (pid < 0) { + perror("fork"); + goto close_pair; + } + + if (pid == 0) { + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { + perror("prctl(NO_NEW_PRIVS)"); + exit(1); + } + listener = user_trap_syscall(__NR_bind, + SECCOMP_FILTER_FLAG_NEW_LISTENER); + if (listener < 0) { + perror("seccomp"); + exit(1); + } + if (send_fd(sk_pair[1], listener) < 0) + exit(1); + close(listener); + exit(tracee()); + } + + pidfd = pidfd_open(pid, 0); + if (pidfd < 0) { + perror("pidfd_open"); + goto kill_child; + } + + listener = recv_fd(sk_pair[0]); + if (listener < 0) + goto kill_child; + + if (handle_req(listener, pidfd)) + goto kill_child; + + /* Wait for child to finish */ + waitpid(pid, NULL, 0); + + ret = 0; + goto close_pair; + +kill_child: + kill(pid, SIGKILL); +close_pair: + close(sk_pair[0]); + close(sk_pair[1]); +out: + return ret; +} From patchwork Wed Dec 18 23:55:50 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sargun Dhillon X-Patchwork-Id: 11302449 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 10351921 for ; Wed, 18 Dec 2019 23:55:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D65C321D7D for ; Wed, 18 Dec 2019 23:55:53 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=sargun.me header.i=@sargun.me header.b="kA5mq4Jz" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726708AbfLRXzx (ORCPT ); Wed, 18 Dec 2019 18:55:53 -0500 Received: from mail-io1-f65.google.com ([209.85.166.65]:45491 "EHLO mail-io1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726599AbfLRXzw (ORCPT ); Wed, 18 Dec 2019 18:55:52 -0500 Received: by mail-io1-f65.google.com with SMTP id i11so3848413ioi.12 for ; Wed, 18 Dec 2019 15:55:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sargun.me; s=google; h=date:from:to:cc:subject:message-id:mime-version:content-disposition :user-agent; bh=iTAiv8quXKS4hPnW6sSgwcFpK7vvhhF/AJU45qhXQyk=; b=kA5mq4Jzu7LvrOWSfHqMNLnfMmBatbn6jDLXcpyUOA1zmQO+F4Usx9rEKXucy0d66c Mcgw7Y4l9dj3C1WmfEdP3Q/lzu49oA1+RZpSDHui3ZYgXRsPx2HwbsVmneeiye2i5Ncu dQdsqU+yTn2zOdCdvgZcQjRxAURgYoY2pIMmc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:mime-version :content-disposition:user-agent; bh=iTAiv8quXKS4hPnW6sSgwcFpK7vvhhF/AJU45qhXQyk=; b=FC2LqktR3hQLzFPxBVTiK4iWFlg/coKshO1oWAa0QqAyH6jmcPNf7KrVqQKtZtm9sW wPjq3rebIZgFUH1DK+Rb3XDR7Tnv6wYJwaThGOflQtCo/rGIxtXgXghvLyUkRDHMa6Zb YDABupDzzXVSKzoqhP2ZUrkfJiKJI9gjVllvLjqAiML7glR1hvhEvPIy1s4i+I/qjq9e dqKtfFj+fQwDxv3iVblzNdMBH2w9PtDS1lYHD9k4h8gviSj7rS6IkN7nnPCi8vxnBhft cRhaeVUBm1GMHUIva4tyJcRoXlpml2R7je9y4KXjFATWG4nv3h/a5a9fwSnf5NMy64n2 Se7A== X-Gm-Message-State: APjAAAVs/HgS8TXNI2wHMEhDEjoxg8jYL/ugkE962wC++4eFegV6qZkt 0JXSJuaZIJ+3011smqQo4Wub8A== X-Google-Smtp-Source: APXvYqyWtVRd9TMXfXith93Pu6yTQeuPGhen310X+v5/AsuM6xA9q7qEGEHa7wFriy7cQ+YnqDaZ2g== X-Received: by 2002:a5e:d602:: with SMTP id w2mr3598937iom.94.1576713351956; Wed, 18 Dec 2019 15:55:51 -0800 (PST) Received: from ircssh-2.c.rugged-nimbus-611.internal (80.60.198.104.bc.googleusercontent.com. [104.198.60.80]) by smtp.gmail.com with ESMTPSA id g79sm1162957ilf.10.2019.12.18.15.55.51 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 18 Dec 2019 15:55:51 -0800 (PST) Date: Wed, 18 Dec 2019 23:55:50 +0000 From: Sargun Dhillon To: linux-kernel@vger.kernel.org, containers@lists.linux-foundation.org, linux-api@vger.kernel.org, linux-fsdevel@vger.kernel.org Cc: tycho@tycho.ws, jannh@google.com, cyphar@cyphar.com, christian.brauner@ubuntu.com, oleg@redhat.com, luto@amacapital.net, viro@zeniv.linux.org.uk, gpascutto@mozilla.com, ealvarez@mozilla.com, fweimer@redhat.com, jld@mozilla.com, arnd@arndb.de Subject: [PATCH v4 5/5] test: Add test for pidfd getfd Message-ID: <20191218235547.GA17298@ircssh-2.c.rugged-nimbus-611.internal> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.24 (2015-08-30) Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org This adds four tests: * Fetch FD, and then compare via kcmp * Read data from FD to make sure it works * Make sure getfd can be blocked by blocking ptrace_may_access * Making sure fetching bad FDs fails Signed-off-by: Sargun Dhillon --- tools/testing/selftests/pidfd/.gitignore | 1 + tools/testing/selftests/pidfd/Makefile | 2 +- .../selftests/pidfd/pidfd_getfd_test.c | 231 ++++++++++++++++++ 3 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/pidfd/pidfd_getfd_test.c diff --git a/tools/testing/selftests/pidfd/.gitignore b/tools/testing/selftests/pidfd/.gitignore index 8d069490e17b..3a779c084d96 100644 --- a/tools/testing/selftests/pidfd/.gitignore +++ b/tools/testing/selftests/pidfd/.gitignore @@ -2,3 +2,4 @@ pidfd_open_test pidfd_poll_test pidfd_test pidfd_wait +pidfd_getfd_test diff --git a/tools/testing/selftests/pidfd/Makefile b/tools/testing/selftests/pidfd/Makefile index 43db1b98e845..75a545861375 100644 --- a/tools/testing/selftests/pidfd/Makefile +++ b/tools/testing/selftests/pidfd/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only CFLAGS += -g -I../../../../usr/include/ -pthread -TEST_GEN_PROGS := pidfd_test pidfd_fdinfo_test pidfd_open_test pidfd_poll_test pidfd_wait +TEST_GEN_PROGS := pidfd_test pidfd_fdinfo_test pidfd_open_test pidfd_poll_test pidfd_wait pidfd_getfd_test include ../lib.mk diff --git a/tools/testing/selftests/pidfd/pidfd_getfd_test.c b/tools/testing/selftests/pidfd/pidfd_getfd_test.c new file mode 100644 index 000000000000..25c11a030afc --- /dev/null +++ b/tools/testing/selftests/pidfd/pidfd_getfd_test.c @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pidfd.h" +#include "../kselftest.h" + +#define WELL_KNOWN_CHILD_FD 100 +#define UNKNOWN_FD 111 +#define SECRET_MESSAGE "secret" + +static int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, + unsigned long idx2) +{ + return syscall(SYS_kcmp, pid1, pid2, type, idx1, idx2); +} + +static int child(bool disable_ptrace, int sk) +{ + char buf[1024]; + int ret, fd; + + ret = prctl(PR_SET_PDEATHSIG, SIGKILL); + if (ret) + ksft_exit_fail_msg("%s: Child could not set DEATHSIG\n", + strerror(errno)); + + fd = syscall(SYS_memfd_create, "test", 0); + if (fd < 0) + ksft_exit_fail_msg("%s: Child could not create memfd\n", + strerror(errno)); + + ret = write(fd, SECRET_MESSAGE, sizeof(SECRET_MESSAGE)); + if (ret < 0) + ksft_exit_fail_msg("%s: Child could not write secret message\n", + strerror(errno)); + + ret = dup2(fd, WELL_KNOWN_CHILD_FD); + if (ret < 0) + ksft_exit_fail_msg("%s: Could not dup fd into well-known FD\n", + strerror(errno)); + + ret = close(fd); + if (ret < 0) + ksft_exit_fail_msg("%s: Child could close old fd\n", + strerror(errno)); + + if (disable_ptrace) { + ret = prctl(PR_SET_DUMPABLE, 0); + if (ret < 0) + ksft_exit_fail_msg("%s: Child failed to disable ptrace\n", + strerror(errno)); + } + ret = send(sk, "L", 1, 0); + if (ret < 0) + ksft_exit_fail_msg("%s: Child failed to send launched message\n", + strerror(errno)); + if (ret == 0) + ksft_exit_fail_msg("Failed to send launch message; other side is closed\n"); + + close(sk); + pause(); + + return EXIT_SUCCESS; +} + +static int start_child(bool disable_ptrace, pid_t *childpid) +{ + int pidfd, ret, sk_pair[2]; + char buf[1]; + + if (socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sk_pair) < 0) + ksft_exit_fail_msg("%s: failed to create socketpair\n", + strerror(errno)); + *childpid = fork(); + if (*childpid < 0) + ksft_exit_fail_msg("%s: failed to fork a child process\n", + strerror(errno)); + + if (*childpid == 0) + exit(child(disable_ptrace, sk_pair[1])); + + close(sk_pair[1]); + + pidfd = sys_pidfd_open(*childpid, 0); + if (pidfd < 0) + ksft_exit_fail_msg("%s: failed to pidfd_open\n", + strerror(errno)); + + ret = recv(sk_pair[0], &buf, 1, 0); + if (ret < 0) + ksft_exit_fail_msg("%s: failed read from launch socket\n", + strerror(errno)); + if (ret == 0) + ksft_exit_fail_msg("Failed to read from launch socket, child failed\n"); + + return pidfd; +} + +static void test_kcmp_and_fetch_fd(void) +{ + char buf[sizeof(SECRET_MESSAGE)]; + int fd, pidfd, ret; + pid_t child_pid; + + pidfd = start_child(false, &child_pid); + + fd = ioctl(pidfd, PIDFD_IOCTL_GETFD, WELL_KNOWN_CHILD_FD); + if (fd < 0) + ksft_exit_fail_msg("%s: getfd failed\n", strerror(errno)); + + ret = kcmp(getpid(), child_pid, KCMP_FILE, fd, WELL_KNOWN_CHILD_FD); + if (ret != 0) + ksft_exit_fail_msg("Our FD not equal to child FD\n"); + + ksft_test_result_pass("kcmp\n"); + + ret = lseek(fd, 0, SEEK_SET); + if (ret < 0) + ksft_exit_fail_msg("%s: seek failed\n", strerror(errno)); + if (ret != 0) + ksft_exit_fail_msg("%d: unexpected seek position\n", ret); + + ret = read(fd, buf, sizeof(buf)); + if (ret < 0) + ksft_exit_fail_msg("%s: failed to read secret message\n", + strerror(errno)); + + if (strncmp(SECRET_MESSAGE, buf, sizeof(buf)) != 0) + ksft_exit_fail_msg("%s: Secret message not correct\n", buf); + + ret = sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0); + close(pidfd); + if (ret < 0) + ksft_exit_fail_msg("%s: failed to send kill to child\n", + strerror(errno)); + + ksft_test_result_pass("fetch_and_read\n"); +} + +static void test_no_ptrace(void) +{ + int fd, pidfd, ret, uid; + pid_t child_pid; + + /* turn into nobody if we're root, to avoid CAP_SYS_PTRACE */ + uid = getuid(); + if (uid == 0) + seteuid(USHRT_MAX); + + pidfd = start_child(true, &child_pid); + + fd = ioctl(pidfd, PIDFD_IOCTL_GETFD, WELL_KNOWN_CHILD_FD); + if (fd != -1) + ksft_exit_fail_msg("%s: getfd succeeded when ptrace blocked\n", + strerror(errno)); + if (errno != EPERM) + ksft_exit_fail_msg("%s: getfd did not get EPERM\n", + strerror(errno)); + + ret = sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0); + close(pidfd); + if (ret < 0) + ksft_exit_fail_msg("%s: failed to send kill to child\n", + strerror(errno)); + + if (uid == 0) + seteuid(0); + + ksft_test_result_pass("no_ptrace\n"); +} + +static void test_unknown_fd(void) +{ + int fd, pidfd, ret; + pid_t child_pid; + + pidfd = start_child(false, &child_pid); + + fd = ioctl(pidfd, PIDFD_IOCTL_GETFD, UNKNOWN_FD); + if (fd != -1) + ksft_exit_fail_msg("%s: getfd succeeded when fetching unknown FD\n", + strerror(errno)); + if (errno != EBADF) + ksft_exit_fail_msg("%s: getfd did not get EBADF\n", + strerror(errno)); + + ret = sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0); + close(pidfd); + if (ret < 0) + ksft_exit_fail_msg("%s: failed to send kill to child\n", + strerror(errno)); + + ksft_test_result_pass("unknown_fd\n"); +} + +int main(int argc, char **argv) +{ + char buf[sizeof(SECRET_MESSAGE)]; + int ret, status, fd, pidfd; + pid_t child_pid; + + ksft_print_header(); + ksft_set_plan(4); + + test_kcmp_and_fetch_fd(); + test_unknown_fd(); + test_no_ptrace(); + + return ksft_exit_pass(); +}