Skip to content

Commit

Permalink
fuse: Add support for FUSE_SETXATTR_V2 and FUSE_POSIX_ACL_UPDATE_MODE
Browse files Browse the repository at this point in the history
File server can clear SGID when access acl is set and if caller does not
have CAP_FSETID as well as none of caller's group are same as file owning
group.

This requires sending info to file server whether caller has CAP_FSETID or
during setxattr(system.posix_acl_access). We don't have extra space in
"struct fuse_setxattr_in" to send this extra information. Hence, add
infrastructure so that client and server can agree on using setxattr_v2
which has space for additional flags.

Also add new flag FUSE_POSIX_ACL_UPDATE_MODE so that file server knows it
that client will send CAP_FSETID information when setxattr(system.posix_acl_access) happens. And file server can switch to callers uid/gid and drop
CAP_FSETID. And this should lead to host kernel clearing SGID if need be.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
  • Loading branch information
rhvgoyal committed Mar 16, 2021
1 parent 1e28eed commit 681cf5b
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 6 deletions.
6 changes: 6 additions & 0 deletions fs/fuse/fuse_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,9 @@ struct fuse_conn {
/** Is setxattr not implemented by fs? */
unsigned no_setxattr:1;

/** Does file server support setxattr_v2 */
unsigned setxattr_v2:1;

/** Is getxattr not implemented by fs? */
unsigned no_getxattr:1;

Expand Down Expand Up @@ -731,6 +734,9 @@ struct fuse_conn {
/** Does the filesystem support posix acls? */
unsigned posix_acl:1;

/** Is file server responsible for updating mode and clearing SGID */
unsigned posix_acl_update_mode:1;

/** Check permissions based on the file mode or not? */
unsigned default_permissions:1;

Expand Down
11 changes: 10 additions & 1 deletion fs/fuse/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,14 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
fc->handle_killpriv_v2 = 1;
fm->sb->s_flags |= SB_NOSEC;
}
if (arg->flags & FUSE_SETXATTR_V2)
fc->setxattr_v2 = 1;
if (arg->flags & FUSE_POSIX_ACL_UPDATE_MODE) {
if (!fc->setxattr_v2)
ok = false;
else
fc->posix_acl_update_mode = 1;
}
} else {
ra_pages = fc->max_read / PAGE_SIZE;
fc->no_lock = 1;
Expand Down Expand Up @@ -1095,7 +1103,8 @@ void fuse_send_init(struct fuse_mount *fm)
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_HANDLE_KILLPRIV_V2;
FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_V2 |
FUSE_POSIX_ACL_UPDATE_MODE;
#ifdef CONFIG_FUSE_DAX
if (fm->fc->dax)
ia->in.flags |= FUSE_MAP_ALIGNMENT;
Expand Down
18 changes: 14 additions & 4 deletions fs/fuse/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,29 @@ int fuse_setxattr(struct inode *inode, const char *name, const void *value,
struct fuse_mount *fm = get_fuse_mount(inode);
FUSE_ARGS(args);
struct fuse_setxattr_in inarg;
struct fuse_setxattr_in_v2 inarg_v2;
bool setxattr_v2 = fm->fc->setxattr_v2;
int err;

if (fm->fc->no_setxattr)
return -EOPNOTSUPP;

memset(&inarg, 0, sizeof(inarg));
inarg.size = size;
inarg.flags = flags;
memset(&inarg_v2, 0, sizeof(inarg_v2));
if (setxattr_v2) {
inarg_v2.size = size;
inarg_v2.flags = flags;
if (capable(CAP_FSETID))
inarg_v2.setxattr_flags |= FUSE_SETXATTR_CAP_FSETID;
} else {
inarg.size = size;
inarg.flags = flags;
}
args.opcode = FUSE_SETXATTR;
args.nodeid = get_node_id(inode);
args.in_numargs = 3;
args.in_args[0].size = sizeof(inarg);
args.in_args[0].value = &inarg;
args.in_args[0].size = setxattr_v2 ? sizeof(inarg_v2) : sizeof(inarg);
args.in_args[0].value = setxattr_v2 ? &inarg_v2 : (void *)&inarg;
args.in_args[1].size = strlen(name) + 1;
args.in_args[1].value = name;
args.in_args[2].size = size;
Expand Down
27 changes: 26 additions & 1 deletion include/uapi/linux/fuse.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@
* 7.33
* - add FUSE_HANDLE_KILLPRIV_V2, FUSE_WRITE_KILL_SUIDGID, FATTR_KILL_SUIDGID
* - add FUSE_OPEN_KILL_SUIDGID
* 7.34
* - add FUSE_SETXATTR_V2
* - add FUSE_SETXATTR_FLAG_CAP_FSETID
* - add FUSE_POSIX_ACL_UPDATE_MODE
*/

#ifndef _LINUX_FUSE_H
Expand Down Expand Up @@ -214,7 +218,7 @@
#define FUSE_KERNEL_VERSION 7

/** Minor version number of this interface */
#define FUSE_KERNEL_MINOR_VERSION 33
#define FUSE_KERNEL_MINOR_VERSION 34

/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
Expand Down Expand Up @@ -330,6 +334,12 @@ struct fuse_file_lock {
* does not have CAP_FSETID. Additionally upon
* write/truncate sgid is killed only if file has group
* execute permission. (Same as Linux VFS behavior).
* FUSE_SETXATTR_V2: Does file server support V2 of struct fuse_setxattr_in
* FUSE_POSIX_ACL_UPDATE_MODE: File server is responsible for updating file
* inode mode (if any) due to acl. This includes clearing
* SGID if caller membership group does not match inode
* owner group and caller does not have CAP_FSETID. Check
* posix_acl_update_mode().
*/
#define FUSE_ASYNC_READ (1 << 0)
#define FUSE_POSIX_LOCKS (1 << 1)
Expand Down Expand Up @@ -360,6 +370,8 @@ struct fuse_file_lock {
#define FUSE_MAP_ALIGNMENT (1 << 26)
#define FUSE_SUBMOUNTS (1 << 27)
#define FUSE_HANDLE_KILLPRIV_V2 (1 << 28)
#define FUSE_SETXATTR_V2 (1 << 29)
#define FUSE_POSIX_ACL_UPDATE_MODE (1 << 30)

/**
* CUSE INIT request/reply flags
Expand Down Expand Up @@ -451,6 +463,12 @@ struct fuse_file_lock {
*/
#define FUSE_OPEN_KILL_SUIDGID (1 << 0)

/**
* setxattr flags
* FUSE_SETXATTR_CAP_FSETID: Set if caller has CAP_FSETID
*/
#define FUSE_SETXATTR_CAP_FSETID (1 << 0)

enum fuse_opcode {
FUSE_LOOKUP = 1,
FUSE_FORGET = 2, /* no reply */
Expand Down Expand Up @@ -686,6 +704,13 @@ struct fuse_setxattr_in {
uint32_t flags;
};

struct fuse_setxattr_in_v2 {
uint32_t size;
uint32_t flags;
uint32_t setxattr_flags;
uint32_t padding;
};

struct fuse_getxattr_in {
uint32_t size;
uint32_t padding;
Expand Down

0 comments on commit 681cf5b

Please sign in to comment.