Linux-Fsdevel Archive on lore.kernel.org
help / color / mirror / Atom feed
From: Miklos Szeredi <miklos@szeredi.hu>
To: Chirantan Ekbote <chirantan@chromium.org>
Cc: Vivek Goyal <vgoyal@redhat.com>,
Stefan Hajnoczi <stefanha@redhat.com>,
linux-fsdevel@vger.kernel.org,
virtio-fs-list <virtio-fs@redhat.com>,
Dylan Reid <dgreid@chromium.org>,
Suleiman Souhlal <suleiman@chromium.org>
Subject: Re: [PATCH v2] RFC: fuse: Call security hooks on new inodes
Date: Tue, 16 Jun 2020 11:29:23 +0200 [thread overview]
Message-ID: <CAJfpegs4Dt9gjQPQch=i_GW5EtBVaycG0_nD11xspG3x8f_W9Q@mail.gmail.com> (raw)
In-Reply-To: <20200610092744.140038-1-chirantan@chromium.org>
On Wed, Jun 10, 2020 at 11:27 AM Chirantan Ekbote
<chirantan@chromium.org> wrote:
>
> Add a new `init_security` field to `fuse_conn` that controls whether we
> initialize security when a new inode is created. Also add a
> `FUSE_SECURITY_CTX` flag that can be set in the `flags` field of the
> `fuse_init_out` struct that controls when the `init_security` field is
> set.
>
> 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. The server should use this context by
> writing it to `/proc/thread-self/attr/fscreate` before creating the
> requested inode.
This is confusing. You mean if the server is stacking on top of a
real fs, then it can force the created new inode to have the given
security attributes by writing to that proc file?
> Calling security hooks is needed for `setfscreatecon` to work since it
> is applied as part of the selinux security hook.
>
> Signed-off-by: Chirantan Ekbote <chirantan@chromium.org>
> ---
> 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 | 99 +++++++++++++++++++++++++++++++++++++--
> fs/fuse/fuse_i.h | 3 ++
> fs/fuse/inode.c | 5 +-
> include/uapi/linux/fuse.h | 8 +++-
> 4 files changed, 110 insertions(+), 5 deletions(-)
>
> diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
> index ee190119f45cc..86bc073bb4f0a 100644
> --- a/fs/fuse/dir.c
> +++ b/fs/fuse/dir.c
> @@ -16,6 +16,9 @@
> #include <linux/xattr.h>
> #include <linux/iversion.h>
> #include <linux/posix_acl.h>
> +#include <linux/security.h>
> +#include <linux/types.h>
> +#include <linux/kernel.h>
>
> 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;
> + }
> + }
> +
The above is quadruplicated, a helper is in order.
> err = fuse_simple_request(fc, &args);
> if (err)
> goto out_free_ff;
> @@ -513,6 +533,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
> return err;
>
> out_free_ff:
> + if (security_ctxlen > 0)
> + kfree(security_ctx);
Freeing NULL is okay, if that's guaranteed in case of security_ctxlen
== 0, then you need not check that condition.
> fuse_file_free(ff);
> out_put_forget_req:
> kfree(forget);
> @@ -629,6 +651,9 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, umode_t mode,
> {
> struct fuse_mknod_in inarg;
> struct fuse_conn *fc = get_fuse_conn(dir);
> + void *security_ctx = NULL;
> + u32 security_ctxlen = 0;
> + int ret;
> FUSE_ARGS(args);
>
> if (!fc->dont_mask)
> @@ -644,7 +669,27 @@ 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);
> +
> + if (fc->init_security) {
> + ret = security_dentry_init_security(entry, mode, &entry->d_name,
> + &security_ctx,
> + &security_ctxlen);
> + if (ret)
> + goto out;
> +
> + if (security_ctxlen > 0) {
> + args.in_numargs = 3;
> + args.in_args[2].size = security_ctxlen;
> + args.in_args[2].value = security_ctx;
> + }
> + }
> +
> + ret = create_new_entry(fc, &args, dir, entry, mode);
> +
> + if (security_ctxlen > 0)
> + kfree(security_ctx);
> +out:
> + return ret;
> }
>
> static int fuse_create(struct inode *dir, struct dentry *entry, umode_t mode,
> @@ -657,6 +702,9 @@ static int fuse_mkdir(struct inode *dir, struct dentry *entry, umode_t mode)
> {
> struct fuse_mkdir_in inarg;
> struct fuse_conn *fc = get_fuse_conn(dir);
> + void *security_ctx = NULL;
> + u32 security_ctxlen = 0;
> + int ret;
> FUSE_ARGS(args);
>
> if (!fc->dont_mask)
> @@ -671,7 +719,28 @@ 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);
> +
> + if (fc->init_security) {
> + ret = security_dentry_init_security(entry, S_IFDIR,
> + &entry->d_name,
> + &security_ctx,
> + &security_ctxlen);
> + if (ret)
> + goto out;
> +
> + if (security_ctxlen > 0) {
> + args.in_numargs = 3;
> + args.in_args[2].size = security_ctxlen;
> + args.in_args[2].value = security_ctx;
> + }
> + }
> +
> + ret = create_new_entry(fc, &args, dir, entry, S_IFDIR);
> +
> + if (security_ctxlen > 0)
> + kfree(security_ctx);
> +out:
> + return ret;
> }
>
> static int fuse_symlink(struct inode *dir, struct dentry *entry,
> @@ -679,6 +748,9 @@ static int fuse_symlink(struct inode *dir, struct dentry *entry,
> {
> struct fuse_conn *fc = get_fuse_conn(dir);
> unsigned len = strlen(link) + 1;
> + void *security_ctx = NULL;
> + u32 security_ctxlen = 0;
> + int ret;
> FUSE_ARGS(args);
>
> args.opcode = FUSE_SYMLINK;
> @@ -687,7 +759,28 @@ 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);
> +
> + if (fc->init_security) {
> + ret = security_dentry_init_security(entry, S_IFLNK,
> + &entry->d_name,
> + &security_ctx,
> + &security_ctxlen);
> + if (ret)
> + goto out;
> +
> + if (security_ctxlen > 0) {
> + args.in_numargs = 3;
> + args.in_args[2].size = security_ctxlen;
> + args.in_args[2].value = security_ctx;
> + }
> + }
> +
> + ret = create_new_entry(fc, &args, dir, entry, S_IFLNK);
> +
> + if (security_ctxlen > 0)
> + kfree(security_ctx);
> +out:
> + return ret;
> }
>
> void fuse_update_ctime(struct inode *inode)
> diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
> index ca344bf714045..5ea9212b0a71c 100644
> --- a/fs/fuse/fuse_i.h
> +++ b/fs/fuse/fuse_i.h
> @@ -719,6 +719,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);
> diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
> index 373cada898159..00919c214149d 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, 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
> --
> 2.27.0.278.ge193c7cf3a9-goog
>
next prev parent reply other threads:[~2020-06-16 9:29 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-06-01 5:32 [PATCH] RFC: fuse: virtiofs: " Chirantan Ekbote
2020-06-02 18:23 ` Vivek Goyal
2020-06-10 9:27 ` [PATCH v2] RFC: fuse: " Chirantan Ekbote
2020-06-15 7:37 ` Chirantan Ekbote
2020-06-16 9:29 ` Miklos Szeredi [this message]
2020-06-16 9:41 ` Chirantan Ekbote
2020-06-16 10:27 ` Miklos Szeredi
2020-07-13 9:09 ` [PATCHv3 1/2] uapi: fuse: Add FUSE_SECURITY_CTX Chirantan Ekbote
2020-07-13 9:09 ` [PATCHv3 2/2] fuse: Call security hooks on new inodes Chirantan Ekbote
2020-07-13 9:56 ` [PATCHv4 1/2] uapi: fuse: Add FUSE_SECURITY_CTX Chirantan Ekbote
2020-07-13 9:57 ` [PATCHv4 2/2] fuse: Call security hooks on new inodes Chirantan Ekbote
2020-07-21 8:07 ` Chirantan Ekbote
2020-07-21 14:23 ` Miklos Szeredi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAJfpegs4Dt9gjQPQch=i_GW5EtBVaycG0_nD11xspG3x8f_W9Q@mail.gmail.com' \
--to=miklos@szeredi.hu \
--cc=chirantan@chromium.org \
--cc=dgreid@chromium.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=stefanha@redhat.com \
--cc=suleiman@chromium.org \
--cc=vgoyal@redhat.com \
--cc=virtio-fs@redhat.com \
--subject='Re: [PATCH v2] RFC: fuse: Call security hooks on new inodes' \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).