From patchwork Tue Dec 17 01:01:21 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sargun Dhillon X-Patchwork-Id: 11296355 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 BA4C6930 for ; Tue, 17 Dec 2019 01:01:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9829D24679 for ; Tue, 17 Dec 2019 01:01:26 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=sargun.me header.i=@sargun.me header.b="Vux6gcbD" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726558AbfLQBBZ (ORCPT ); Mon, 16 Dec 2019 20:01:25 -0500 Received: from mail-io1-f66.google.com ([209.85.166.66]:44437 "EHLO mail-io1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727345AbfLQBBY (ORCPT ); Mon, 16 Dec 2019 20:01:24 -0500 Received: by mail-io1-f66.google.com with SMTP id b10so9094602iof.11 for ; Mon, 16 Dec 2019 17:01:24 -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=toA0jzwuketdr2e1YvJhPtQZTwWvbzIQDMih6NbAho0=; b=Vux6gcbDzir2dvv72u14dZyT7A+Xu//TUpa4d8Q262GwSxLJmt+V15Z/jfeB+txgJc qIZ6FQoD4QleBDoeLZJZoFaSx1gkf+MFzeqkjO3RomC124M8P/QEyG0SszkbAv6uiLBR R36L6QmDCO0E5jbRr/S0Y+Bt1snK25AU0uPqA= 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=toA0jzwuketdr2e1YvJhPtQZTwWvbzIQDMih6NbAho0=; b=P7CYBgzNm94hYWAtVcSguzqJ6Itp3Q2cJPMpJ1aJ37zMhT61pqJL2QOKLgKd545ZuZ My2N8GX0qthx/4PMFlJrVeCfKX710qtL3bh4NFye7+1lledwunAf2K46p/9al9BS9iGJ ByOjpDrU1ZBoaLUUeMsT8SKMsLyhclqn7ebLGF5fewE63lXBjYiE2gMcQ8mZmBlCUhyH wqb7z7ueA341Mb5JYYNnPfD707l4jq0g6iCCROWkLs/JfK44xHTRnCZFd/gCZhK2HB2Q nR4lSgbnmSAcTk2MgktqzDxP5YAxGnSOUQbLWJhc1VUXwfJYq92URyoDCj8NBxry4VHg 32RQ== X-Gm-Message-State: APjAAAV4XHy9vp0JxeKCQQRe/XqWlXz94Nk2LJiM5LoD+TLafVNja/hQ VqzB4GiajYU2dLAd6m97sl0xFw== X-Google-Smtp-Source: APXvYqw7XFCaDfOkRDKO1vqm5NO1I4w3iLozscNNT7OpT7LMGnda1O0Xl6WJYAMAUltY1ohkkANcug== X-Received: by 2002:a5d:9046:: with SMTP id v6mr1727984ioq.302.1576544483409; Mon, 16 Dec 2019 17:01:23 -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 t203sm4684121iod.15.2019.12.16.17.01.23 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 16 Dec 2019 17:01:23 -0800 (PST) Date: Tue, 17 Dec 2019 01:01:21 +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 Subject: [PATCH v3 1/4] vfs, fdtable: Add get_task_file helper Message-ID: <20191217010119.GA14488@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 3da91a112bab..63272d15be61 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 Tue Dec 17 01:00:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sargun Dhillon X-Patchwork-Id: 11296349 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 8F903139A for ; Tue, 17 Dec 2019 01:00:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 62CE620CC7 for ; Tue, 17 Dec 2019 01:00:12 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=sargun.me header.i=@sargun.me header.b="oRLMMSkO" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728303AbfLQBAI (ORCPT ); Mon, 16 Dec 2019 20:00:08 -0500 Received: from mail-il1-f195.google.com ([209.85.166.195]:44902 "EHLO mail-il1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727968AbfLQBAH (ORCPT ); Mon, 16 Dec 2019 20:00:07 -0500 Received: by mail-il1-f195.google.com with SMTP id z12so6972084iln.11 for ; Mon, 16 Dec 2019 17:00:07 -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=Sm2OFZZDnAm6HtYHTigzrKnwqviaFvFk+BMgRHfZfe0=; b=oRLMMSkO+qHMibdj8oUxIIvrRnjhoJEziOmUykia3GgnJrLlCi9Hd6JWEfmfATUNep YBi5QHH+F6MEu4kv3rp4K5VhB4YLNozdd8+XLVxEFY+HFLdap4Z2+L08GakI6ZUdmKGp k5QE6YgyJ75tucqvsFI8KGKybCrDhDGNlji3w= 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=Sm2OFZZDnAm6HtYHTigzrKnwqviaFvFk+BMgRHfZfe0=; b=n80DrmXXyIkNZJoHG41UQGZEggYRXzjtPZ+7cTPqZY+bAgXKGhvi6pYCJSWQhIxKRU rS7M4KQZq3TqfOfUzP9c6nOta3DX2wD3Hrm3vIfVoPmX9qSYgKxo+kErCTvnQfEbNfSL jRkdPgp/vmRH/YA1kC5zsDDmipv18dgYUP4xre6eSCtNGP7dxZGyaTu7+GaIKWkZ7MWx iBhNAIDF7yr2ynVLG6gSwcle7kSA7ppxEoVTIDDzKBUQ/y7V9UqS8Cyb/lgf7VVnMQm1 gEpUOsDEg+kbb538rkmyvbT8F4Um3kBP68Ijzs4F+Aw3sWc8GugjjqGkzAYfLMvHfAwV vZQg== X-Gm-Message-State: APjAAAVqgYjFMV7eQDsFZLpbdyGq3j1P1fQ/yX/K+q9r1DakpCUuG5WQ jdAqK0XKOYXMOgpMqMfujbrQXQ== X-Google-Smtp-Source: APXvYqwDTW2pfVKMawWRTUOtmh1yg1fQppqbiiKryZiM1i1L4nbkUdOL3QTYQt4FCw4ea7tt7oGqYQ== X-Received: by 2002:a92:485a:: with SMTP id v87mr14375978ila.128.1576544406791; Mon, 16 Dec 2019 17:00:06 -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 h6sm4832431iom.43.2019.12.16.17.00.05 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 16 Dec 2019 17:00:06 -0800 (PST) Date: Tue, 17 Dec 2019 01:00:04 +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 Subject: [PATCH v3 2/4] pid: Add PIDFD_IOCTL_GETFD to fetch file descriptors from processes Message-ID: <20191217010001.GA14461@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 --- Documentation/ioctl/ioctl-number.rst | 1 + include/linux/pid.h | 1 + include/uapi/linux/pid.h | 26 ++++++++++ kernel/fork.c | 72 ++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+) create mode 100644 include/uapi/linux/pid.h diff --git a/Documentation/ioctl/ioctl-number.rst b/Documentation/ioctl/ioctl-number.rst index bef79cd4c6b4..be2efb93acd1 100644 --- a/Documentation/ioctl/ioctl-number.rst +++ b/Documentation/ioctl/ioctl-number.rst @@ -272,6 +272,7 @@ Code Seq# Include File Comments 'p' A1-A5 linux/pps.h LinuxPPS +'p' B0-CF uapi/linux/pid.h 'q' 00-1F linux/serio.h 'q' 80-FF linux/telephony.h Internet PhoneJACK, Internet LineJACK linux/ixjuser.h diff --git a/include/linux/pid.h b/include/linux/pid.h index 9645b1194c98..65f1a73040c9 100644 --- a/include/linux/pid.h +++ b/include/linux/pid.h @@ -5,6 +5,7 @@ #include #include #include +#include enum pid_type { diff --git a/include/uapi/linux/pid.h b/include/uapi/linux/pid.h new file mode 100644 index 000000000000..4ec02ed8b39a --- /dev/null +++ b/include/uapi/linux/pid.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_PID_H +#define _UAPI_LINUX_PID_H + +#include +#include + +/* options to pass in to pidfd_getfd_args flags */ +#define PIDFD_GETFD_CLOEXEC (1 << 0) /* open the fd with cloexec */ + +struct pidfd_getfd_args { + __u32 size; /* sizeof(pidfd_getfd_args) */ + __u32 fd; /* the tracee's file descriptor to get */ + __u32 flags; +}; + +#define PIDFD_IOC_MAGIC 'p' +#define PIDFD_IO(nr) _IO(PIDFD_IOC_MAGIC, nr) +#define PIDFD_IOR(nr, type) _IOR(PIDFD_IOC_MAGIC, nr, type) +#define PIDFD_IOW(nr, type) _IOW(PIDFD_IOC_MAGIC, nr, type) +#define PIDFD_IOWR(nr, type) _IOWR(PIDFD_IOC_MAGIC, nr, type) + +#define PIDFD_IOCTL_GETFD PIDFD_IOWR(0xb0, \ + struct pidfd_getfd_args) + +#endif /* _UAPI_LINUX_PID_H */ diff --git a/kernel/fork.c b/kernel/fork.c index 6cabc124378c..d9971e664e82 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1726,9 +1726,81 @@ static __poll_t pidfd_poll(struct file *file, struct poll_table_struct *pts) return poll_flags; } +static long pidfd_getfd(struct pid *pid, struct pidfd_getfd_args __user *buf) +{ + struct pidfd_getfd_args args; + unsigned int fd_flags = 0; + struct task_struct *task; + struct file *file; + u32 user_size; + int ret, fd; + + ret = get_user(user_size, &buf->size); + if (ret) + return ret; + + ret = copy_struct_from_user(&args, sizeof(args), buf, user_size); + if (ret) + return ret; + if ((args.flags & ~(PIDFD_GETFD_CLOEXEC)) != 0) + return -EINVAL; + if (args.flags & PIDFD_GETFD_CLOEXEC) + fd_flags |= O_CLOEXEC; + + task = get_pid_task(pid, PIDTYPE_PID); + if (!task) + return -ESRCH; + ret = -EPERM; + if (!ptrace_may_access(task, PTRACE_MODE_READ_REALCREDS)) + goto out; + ret = -EBADF; + file = fget_task(task, args.fd); + if (!file) + goto out; + + fd = get_unused_fd_flags(fd_flags); + if (fd < 0) { + ret = fd; + goto out_put_file; + } + /* + * 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(fd, file); + put_task_struct(task); + return fd; + +out_put_fd: + put_unused_fd(fd); +out_put_file: + fput(file); +out: + put_task_struct(task); + return ret; +} + +static long pidfd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct pid *pid = file->private_data; + void __user *buf = (void __user *)arg; + + switch (cmd) { + case PIDFD_IOCTL_GETFD: + return pidfd_getfd(pid, buf); + default: + return -EINVAL; + } +} + const struct file_operations pidfd_fops = { .release = pidfd_release, .poll = pidfd_poll, + .unlocked_ioctl = pidfd_ioctl, #ifdef CONFIG_PROC_FS .show_fdinfo = pidfd_show_fdinfo, #endif From patchwork Tue Dec 17 01:00:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sargun Dhillon X-Patchwork-Id: 11296351 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 848A7930 for ; Tue, 17 Dec 2019 01:00:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 57BE824683 for ; Tue, 17 Dec 2019 01:00:28 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=sargun.me header.i=@sargun.me header.b="Mqtxg1bO" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727795AbfLQBA1 (ORCPT ); Mon, 16 Dec 2019 20:00:27 -0500 Received: from mail-io1-f65.google.com ([209.85.166.65]:44344 "EHLO mail-io1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728047AbfLQBAT (ORCPT ); Mon, 16 Dec 2019 20:00:19 -0500 Received: by mail-io1-f65.google.com with SMTP id b10so9092109iof.11 for ; Mon, 16 Dec 2019 17:00:19 -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=Mqtxg1bODF0az/WYzqiTEFT+iACXA78wSudLXZFTA94ymiUxdJBI3gMvuRm9IIp4ge I5T3o+b3jNzq9Q1CSMbCGIff+McGHZ8wvq9R1Kl4YzOQL5Z4fogEjQxk9Aez3mTEzLmo NmGpLrP8qJve90iMoBwqSckOiVdg3rA/9DuAI= 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=AbE7ZzrfLJGd0bw3pfOTP3UTO2STcSh1gGoQ7jc2RtL87fGiVFYuCMlu/e4ZOQYGsS lU6SaFNZZM8WJfXIdTz+dQ49EfS1Yn6ACGp/Rg8A6dvv/UUdSDKKvCBw3lPnHQdbPBso NKID9zdxFVcVdNeQTcKWoQoTmjKMxR/0WbutA017GYsoMEVCiuhx1jRyqr1tnQhVj7XI +BcfOroqMhGIYcUc7sjzOVwgTOmdlkMEQAjksa+RnykJy3Rgf0YPVbCrPCeWVj5s6UlC V9aa75PBfqjxc2Jfdtx5MzueqJxo5IHnWn50G/haNXm/lC618hbXsK3aqA3nnF6PDpJ8 YzYA== X-Gm-Message-State: APjAAAXI56v3YIPYaEpwWEhh4h3Grz52EIXsTN852IfKVS6ud1Wj6f0/ RDQp+FQ5siH6RHF+qkU0YvtTRw== X-Google-Smtp-Source: APXvYqxPnsnDlmTtm5UBuWSnOAOJ6tzOVibfDvwnPw1QTcZOJ5ICRVowYB46fgHIHU7m2JN24Dcy3Q== X-Received: by 2002:a02:335d:: with SMTP id k29mr5864060jak.22.1576544418494; Mon, 16 Dec 2019 17:00:18 -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 p12sm4413125ilk.66.2019.12.16.17.00.18 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 16 Dec 2019 17:00:18 -0800 (PST) Date: Tue, 17 Dec 2019 01:00:16 +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 Subject: [PATCH v3 3/4] samples: split generalized user-trap code into helper file Message-ID: <20191217010014.GA14470@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 Tue Dec 17 01:00:27 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sargun Dhillon X-Patchwork-Id: 11296353 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 39487930 for ; Tue, 17 Dec 2019 01:00:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 0C7AE24679 for ; Tue, 17 Dec 2019 01:00:51 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=sargun.me header.i=@sargun.me header.b="ovsMlGiX" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727152AbfLQBAr (ORCPT ); Mon, 16 Dec 2019 20:00:47 -0500 Received: from mail-il1-f195.google.com ([209.85.166.195]:36783 "EHLO mail-il1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727704AbfLQBAa (ORCPT ); Mon, 16 Dec 2019 20:00:30 -0500 Received: by mail-il1-f195.google.com with SMTP id b15so7029075iln.3 for ; Mon, 16 Dec 2019 17:00:29 -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=IYhFGBzidPzrRndBAfLKjrCbVqpN5/cVaIxnudwawfg=; b=ovsMlGiXBMvNV0eH19SohbbZR8kUAlVOX5ty/bdnINY79xJOYs+0wfgq1C64iKkIDQ huiF62g3ibh8nrGAiRCQd+q3VkqOgcAeADVTTQCrEGvmovCu2gCWv2eInmTb72G9tADX Ps8D4+L02dfzvuOXhLWUZK2HfeSGRnKBWBkTM= 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=IYhFGBzidPzrRndBAfLKjrCbVqpN5/cVaIxnudwawfg=; b=SUGkQFzqbFL8a1yHM8Ay06mKGPxJVqYNBcUQgQmLJHsnQ9CEfNjziqapdDjLAXfB3a u9nmN4hMZRl+5v0nYx2gaTEP9kjtI4TIaeSZhHkkjLQK76AZORNn95HVO2VwV/LMIv4W Vew67iXSkMD2dWTF/aYQSvVGB1LB7MVbs3nvOzJmLP8huTeiw7quFCeNoBFrfLIWX9AZ Yg0p4yJFhZYHchWpGPUF06D0JQQIvQKaqp0zZVVSeRzgK5IHlYoyzfNVPAgmUe5lBQFm KeNG+YuPUJVshpuEo8T2XNgzn0HD6WJ+ME7phuXX37hpd2vymYJ4QQlkw6IgdryhBzQ9 U3yg== X-Gm-Message-State: APjAAAV8Lw9FH3zxwTOUdG28ScoNl+KWl8CYYbtUUG1rpJ29dkh/FCcP fgZYF3vP5s9EaCgvQTAWRPSDYQ== X-Google-Smtp-Source: APXvYqyORfsGK6ATxnwAd9xikaahiE8GsRHnWmCz1g5oQmb+igeBHtioDM8PjKK03uUjzYMQUMDEkw== X-Received: by 2002:a92:7d07:: with SMTP id y7mr14538891ilc.270.1576544429319; Mon, 16 Dec 2019 17:00:29 -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 n5sm6254217ila.7.2019.12.16.17.00.28 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 16 Dec 2019 17:00:28 -0800 (PST) Date: Tue, 17 Dec 2019 01:00:27 +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 Subject: [PATCH v3 4/4] samples: Add example of using pidfd getfd in conjunction with user trap Message-ID: <20191217010025.GA14479@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 | 190 ++++++++++++++++++++++++++++++ 3 files changed, 199 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..960e58982063 --- /dev/null +++ b/samples/seccomp/user-trap-pidfd.c @@ -0,0 +1,190 @@ +// 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 pidfd_getfd_args getfd_args = { + .flags = PIDFD_GETFD_CLOEXEC + }; + struct seccomp_notif_sizes sizes; + struct seccomp_notif_resp *resp; + struct seccomp_notif *req; + int fd, ret = 1; + + getfd_args.size = sizeof(getfd_args); + 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]); + getfd_args.fd = req->data.args[0]; + fd = ioctl(pidfd, PIDFD_IOCTL_GETFD, &getfd_args); + 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; +}