From patchwork Wed Jul 22 09:07:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chirantan Ekbote X-Patchwork-Id: 11677821 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 5783A159A for ; Wed, 22 Jul 2020 09:09:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 37ECD20792 for ; Wed, 22 Jul 2020 09:09:09 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="ClKEYnsa" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728852AbgGVJJI (ORCPT ); Wed, 22 Jul 2020 05:09:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58474 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726153AbgGVJJI (ORCPT ); Wed, 22 Jul 2020 05:09:08 -0400 Received: from mail-pj1-x1042.google.com (mail-pj1-x1042.google.com [IPv6:2607:f8b0:4864:20::1042]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3409DC0619DC for ; Wed, 22 Jul 2020 02:09:08 -0700 (PDT) Received: by mail-pj1-x1042.google.com with SMTP id t15so848169pjq.5 for ; Wed, 22 Jul 2020 02:09:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=1BVl/A4ZuZHtoqyknQZtUC9ho61FPvwu+Y4wN12Kj8U=; b=ClKEYnsaIWUgi6JhhYXpeesKL7NuFLd7lF4tjKH/6IFzrlaH7vmxQV3pnB1SotX9I8 TKrMfUVFy8ezmQtDP/WwkzYqb2fHZhNkxK/14IZCG+gzoEqcbnR9lQoRgj0Eiy6+YQFy JQn7azDjKxHaXaHm5UZvQ20xGJaMEwVpM7P+w= 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:mime-version :content-transfer-encoding; bh=1BVl/A4ZuZHtoqyknQZtUC9ho61FPvwu+Y4wN12Kj8U=; b=ViCzmnjV5n3A/8seq7GAUwLmyixgXgU5y6Di7D6YM80H5jHItl4OdLjxjj49jrgo2D RQ6ffi4MgDVY6XF423Bbuh8d2grwFzR7vR33h+ANy7blRFkANmRm2kFCNhoOG7Ip2XoZ M98VvIQXkqFBUGPUu6khvAoS6PHr7d50esfW35mQ77WiTLcK+sse/7iay0cZpCfAn73K SEjKHGY+EajnJb0BGfJwdAOBjFsf9fXsNDtPNgNGl4OhYs2GkVZ12jw3DIOg0RQaF4VT y4rx3VebLuxEDaYhj+U9tx2l7oP6GTj64g9U6h2GfBNtXZlJ3OyqSV6XpHGCMWzKrn2U v5Vw== X-Gm-Message-State: AOAM5337hduaPlAapV8L1U7fdMEie5dNUKohq2qSvKjcM8ZmcCw+bmgl Ft7xCxANLCbaECOV/MwhSgSeEgcmNrw= X-Google-Smtp-Source: ABdhPJx7qixZ1eBmqd5wgwg9yWvmiNDnCRwRP1EI/HV8JvuXsGxQCeAKlNQsN64LXXXjJ3a/zLUswQ== X-Received: by 2002:a17:902:5996:: with SMTP id p22mr7426415pli.233.1595408947686; Wed, 22 Jul 2020 02:09:07 -0700 (PDT) Received: from localhost ([2401:fa00:8f:2:f693:9fff:fef4:2537]) by smtp.gmail.com with ESMTPSA id v22sm22942653pfe.48.2020.07.22.02.09.04 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 22 Jul 2020 02:09:06 -0700 (PDT) From: Chirantan Ekbote To: Miklos Szeredi , Stephen Smalley Cc: Vivek Goyal , Stefan Hajnoczi , linux-fsdevel@vger.kernel.org, virtio-fs@redhat.com, Dylan Reid , Suleiman Souhlal , fuse-devel@lists.sourceforge.net, selinux@vger.kernel.org, Chirantan Ekbote Subject: [RESEND] [PATCHv4 1/2] uapi: fuse: Add FUSE_SECURITY_CTX Date: Wed, 22 Jul 2020 18:07:57 +0900 Message-Id: <20200722090758.3221812-1-chirantan@chromium.org> X-Mailer: git-send-email 2.28.0.rc0.105.gf9edc3c819-goog MIME-Version: 1.0 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org Add the FUSE_SECURITY_CTX flag for the `flags` field of the fuse_init_out struct. When this flag is set the kernel will append the security context for a newly created inode to the request (create, mkdir, mknod, and symlink). The server is responsible for ensuring that the inode appears atomically with the requested security context. For example, if the server is backed by a "real" linux file system then it can write the security context value to /proc/thread-self/attr/fscreate before making the syscall to create the inode. Signed-off-by: Chirantan Ekbote --- Changes in v4: * Added signoff to commit message. include/uapi/linux/fuse.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index 373cada898159..e2099b45fd44b 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -172,6 +172,10 @@ * - add FUSE_WRITE_KILL_PRIV flag * - add FUSE_SETUPMAPPING and FUSE_REMOVEMAPPING * - add map_alignment to fuse_init_out, add FUSE_MAP_ALIGNMENT flag + * + * 7.32 + * - add FUSE_SECURITY_CTX flag for fuse_init_out + * - add security context to create, mkdir, symlink, and mknod requests */ #ifndef _LINUX_FUSE_H @@ -207,7 +211,7 @@ #define FUSE_KERNEL_VERSION 7 /** Minor version number of this interface */ -#define FUSE_KERNEL_MINOR_VERSION 31 +#define FUSE_KERNEL_MINOR_VERSION 32 /** The node ID of the root inode */ #define FUSE_ROOT_ID 1 @@ -314,6 +318,7 @@ struct fuse_file_lock { * FUSE_NO_OPENDIR_SUPPORT: kernel supports zero-message opendir * FUSE_EXPLICIT_INVAL_DATA: only invalidate cached pages on explicit request * FUSE_MAP_ALIGNMENT: map_alignment field is valid + * FUSE_SECURITY_CTX: add security context to create, mkdir, symlink, and mknod */ #define FUSE_ASYNC_READ (1 << 0) #define FUSE_POSIX_LOCKS (1 << 1) @@ -342,6 +347,7 @@ struct fuse_file_lock { #define FUSE_NO_OPENDIR_SUPPORT (1 << 24) #define FUSE_EXPLICIT_INVAL_DATA (1 << 25) #define FUSE_MAP_ALIGNMENT (1 << 26) +#define FUSE_SECURITY_CTX (1 << 27) /** * CUSE INIT request/reply flags From patchwork Wed Jul 22 09:07:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chirantan Ekbote X-Patchwork-Id: 11677827 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 4E025159A for ; Wed, 22 Jul 2020 09:09:20 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2FF5720792 for ; Wed, 22 Jul 2020 09:09:20 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=chromium.org header.i=@chromium.org header.b="ChdwMgdG" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729217AbgGVJJT (ORCPT ); Wed, 22 Jul 2020 05:09:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58510 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726892AbgGVJJS (ORCPT ); Wed, 22 Jul 2020 05:09:18 -0400 Received: from mail-pg1-x544.google.com (mail-pg1-x544.google.com [IPv6:2607:f8b0:4864:20::544]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D4D36C0619DE for ; Wed, 22 Jul 2020 02:09:18 -0700 (PDT) Received: by mail-pg1-x544.google.com with SMTP id m22so854145pgv.9 for ; Wed, 22 Jul 2020 02:09:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=JdQz6HfIR2nAcG7c6KrVPV2eWsbuTTTRsMjCbi9sdas=; b=ChdwMgdGCMfOQETkVeTsTF3QBOc8ASgwPEwOQNtnIPlvlnPhMH26I6snjib3aghOM+ Q5c6DoBarjEuf9FkVBxbz2dZHaMumSAyRfXn7iuMiBXrkL0yl9i/+gJSx4/qdzAFUV5X 6tD3n/JW9nQ8ghFR+V/3N07twERtNVcaRj62k= 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=JdQz6HfIR2nAcG7c6KrVPV2eWsbuTTTRsMjCbi9sdas=; b=dwSxCzp/skGGmZGY37aUXFVySQVnKz5UKQDPClIY5piwnBP2EdAOdK1yTRHH5C/bnB S7SOS8buont/A5YdFMEn2X+pfUt5PkQv/04DfPb1RsWt+RYOiv9pjYM3TfMtZT9FEy+g fxdYO7UV1Xnvgvn7auT3SLviVwA5YKTKhzSH2zWzwN/T2zG7Sny/lIeLRTbtNrcn4osW CYsuctTR2MW8aRQJyagb5f7CZuvQ6eLj6PEq/bcia1JMU0ysb7UMFguGqSUBMG4znXeC XVYXSMu93LVf8jjj6mTHC2cZaDDIgCwz1sk3AAPcIHL/a3vX4Kic9WR259j+k9aAlf0c 9lqA== X-Gm-Message-State: AOAM5312kWH7BMJF6tNtCO8A7l9mfYZ21JAUwJykVbYrJDc0odpxyCA2 Ofci8JjPmxsWtBZs00tG/GoYBw== X-Google-Smtp-Source: ABdhPJwDazGYr6tNh7L+TJkRknh69QLWegvXUR3mUO5I7SyiX6nUOsOeAOR9znfGzV2bM7kpUTMToA== X-Received: by 2002:a63:8b42:: with SMTP id j63mr26652063pge.131.1595408958264; Wed, 22 Jul 2020 02:09:18 -0700 (PDT) Received: from localhost ([2401:fa00:8f:2:f693:9fff:fef4:2537]) by smtp.gmail.com with ESMTPSA id ci23sm5692133pjb.29.2020.07.22.02.09.15 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 22 Jul 2020 02:09:17 -0700 (PDT) From: Chirantan Ekbote To: Miklos Szeredi , Stephen Smalley Cc: Vivek Goyal , Stefan Hajnoczi , linux-fsdevel@vger.kernel.org, virtio-fs@redhat.com, Dylan Reid , Suleiman Souhlal , fuse-devel@lists.sourceforge.net, selinux@vger.kernel.org, Chirantan Ekbote Subject: [RESEND] [PATCHv4 2/2] fuse: Call security hooks on new inodes Date: Wed, 22 Jul 2020 18:07:58 +0900 Message-Id: <20200722090758.3221812-2-chirantan@chromium.org> X-Mailer: git-send-email 2.28.0.rc0.105.gf9edc3c819-goog In-Reply-To: <20200722090758.3221812-1-chirantan@chromium.org> References: <20200722090758.3221812-1-chirantan@chromium.org> MIME-Version: 1.0 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org Add a new `init_security` field to `fuse_conn` that controls whether we initialize security when a new inode is created. Set this to true when the `flags` field of the fuse_init_out struct contains FUSE_SECURITY_CTX. When set to true, get the security context for a newly created inode via `security_dentry_init_security` and append it to the create, mkdir, mknod, and symlink requests. Signed-off-by: Chirantan Ekbote --- Changes in v4: * Added signoff to commit message. * Fixed style warnings reported by checkpatch.pl. Changes in v3: * Moved uapi changes into a separate patch. * Refactored duplicated common code into create_new_entry. * Dropped check if security_ctxlen > 0 since kfree can handle NULL. Changes in v2: * Added the FUSE_SECURITY_CTX flag for init_out responses. * Switched to security_dentry_init_security. * Send security context with create, mknod, mkdir, and symlink requests instead of applying it after creation. fs/fuse/dir.c | 60 ++++++++++++++++++++++++++++++++++++++++++++---- fs/fuse/fuse_i.h | 3 +++ fs/fuse/inode.c | 5 +++- 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index ee190119f45cc..c6791c49afe4d 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -16,6 +16,9 @@ #include #include #include +#include +#include +#include static void fuse_advise_use_readdirplus(struct inode *dir) { @@ -442,6 +445,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, struct fuse_entry_out outentry; struct fuse_inode *fi; struct fuse_file *ff; + void *security_ctx = NULL; + u32 security_ctxlen = 0; /* Userspace expects S_IFREG in create mode */ BUG_ON((mode & S_IFMT) != S_IFREG); @@ -477,6 +482,21 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, args.out_args[0].value = &outentry; args.out_args[1].size = sizeof(outopen); args.out_args[1].value = &outopen; + + if (fc->init_security) { + err = security_dentry_init_security(entry, mode, &entry->d_name, + &security_ctx, + &security_ctxlen); + if (err) + goto out_put_forget_req; + + if (security_ctxlen > 0) { + args.in_numargs = 3; + args.in_args[2].size = security_ctxlen; + args.in_args[2].value = security_ctx; + } + } + err = fuse_simple_request(fc, &args); if (err) goto out_free_ff; @@ -513,6 +533,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, return err; out_free_ff: + kfree(security_ctx); fuse_file_free(ff); out_put_forget_req: kfree(forget); @@ -569,13 +590,15 @@ static int fuse_atomic_open(struct inode *dir, struct dentry *entry, */ static int create_new_entry(struct fuse_conn *fc, struct fuse_args *args, struct inode *dir, struct dentry *entry, - umode_t mode) + umode_t mode, bool init_security) { struct fuse_entry_out outarg; struct inode *inode; struct dentry *d; int err; struct fuse_forget_link *forget; + void *security_ctx = NULL; + u32 security_ctxlen = 0; forget = fuse_alloc_forget(); if (!forget) @@ -586,7 +609,29 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_args *args, args->out_numargs = 1; args->out_args[0].size = sizeof(outarg); args->out_args[0].value = &outarg; + + if (init_security) { + unsigned short idx = args->in_numargs; + + if ((size_t)idx >= ARRAY_SIZE(args->in_args)) + return -ENOMEM; + + err = security_dentry_init_security(entry, mode, &entry->d_name, + &security_ctx, + &security_ctxlen); + if (err) + return err; + + if (security_ctxlen > 0) { + args->in_args[idx].size = security_ctxlen; + args->in_args[idx].value = security_ctx; + args->in_numargs++; + } + } + err = fuse_simple_request(fc, args); + kfree(security_ctx); + if (err) goto out_put_forget_req; @@ -644,7 +689,8 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, umode_t mode, args.in_args[0].value = &inarg; args.in_args[1].size = entry->d_name.len + 1; args.in_args[1].value = entry->d_name.name; - return create_new_entry(fc, &args, dir, entry, mode); + + return create_new_entry(fc, &args, dir, entry, mode, fc->init_security); } static int fuse_create(struct inode *dir, struct dentry *entry, umode_t mode, @@ -671,7 +717,9 @@ static int fuse_mkdir(struct inode *dir, struct dentry *entry, umode_t mode) args.in_args[0].value = &inarg; args.in_args[1].size = entry->d_name.len + 1; args.in_args[1].value = entry->d_name.name; - return create_new_entry(fc, &args, dir, entry, S_IFDIR); + + return create_new_entry(fc, &args, dir, entry, S_IFDIR, + fc->init_security); } static int fuse_symlink(struct inode *dir, struct dentry *entry, @@ -687,7 +735,9 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry, args.in_args[0].value = entry->d_name.name; args.in_args[1].size = len; args.in_args[1].value = link; - return create_new_entry(fc, &args, dir, entry, S_IFLNK); + + return create_new_entry(fc, &args, dir, entry, S_IFLNK, + fc->init_security); } void fuse_update_ctime(struct inode *inode) @@ -858,7 +908,7 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, args.in_args[0].value = &inarg; args.in_args[1].size = newent->d_name.len + 1; args.in_args[1].value = newent->d_name.name; - err = create_new_entry(fc, &args, newdir, newent, inode->i_mode); + err = create_new_entry(fc, &args, newdir, newent, inode->i_mode, false); /* Contrary to "normal" filesystems it can happen that link makes two "logical" inodes point to the same "physical" inode. We invalidate the attributes of the old one, so it diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index d7cde216fc871..dd7422d83da3d 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -720,6 +720,9 @@ struct fuse_conn { /* Do not show mount options */ unsigned int no_mount_options:1; + /* Initialize security xattrs when creating a new inode */ + unsigned int init_security : 1; + /** The number of requests waiting for completion */ atomic_t num_waiting; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 16aec32f7f3d7..1a311771c5555 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -951,6 +951,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_args *args, min_t(unsigned int, FUSE_MAX_MAX_PAGES, max_t(unsigned int, arg->max_pages, 1)); } + if (arg->flags & FUSE_SECURITY_CTX) + fc->init_security = 1; } else { ra_pages = fc->max_read / PAGE_SIZE; fc->no_lock = 1; @@ -988,7 +990,8 @@ void fuse_send_init(struct fuse_conn *fc) FUSE_WRITEBACK_CACHE | FUSE_NO_OPEN_SUPPORT | FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV | FUSE_POSIX_ACL | FUSE_ABORT_ERROR | FUSE_MAX_PAGES | FUSE_CACHE_SYMLINKS | - FUSE_NO_OPENDIR_SUPPORT | FUSE_EXPLICIT_INVAL_DATA; + FUSE_NO_OPENDIR_SUPPORT | FUSE_EXPLICIT_INVAL_DATA | + FUSE_SECURITY_CTX; ia->args.opcode = FUSE_INIT; ia->args.in_numargs = 1; ia->args.in_args[0].size = sizeof(ia->in);