diff options
author | Vivek Goyal <vgoyal@redhat.com> | 2020-10-09 14:15:09 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2020-11-11 17:22:33 +0100 |
commit | 3179216135ec09825d7c7875580951a6e69dc5df (patch) | |
tree | dd0b2cbe15cfddb6747a1078fbd434b3b58705fa /fs/fuse | |
parent | b866739596ae3c3c60c43f1cf04a516c5aa20fd1 (diff) |
fuse: setattr should set FATTR_KILL_SUIDGID
If fc->handle_killpriv_v2 is enabled, we expect file server to clear
suid/sgid/security.capbility upon chown/truncate/write as appropriate.
Upon truncate (ATTR_SIZE), suid/sgid are cleared only if caller does not
have CAP_FSETID. File server does not know whether caller has CAP_FSETID
or not. Hence set FATTR_KILL_SUIDGID upon truncate to let file server know
that caller does not have CAP_FSETID and it should kill suid/sgid as
appropriate.
On chown (ATTR_UID/ATTR_GID) suid/sgid need to be cleared irrespective of
capabilities of calling process, so set FATTR_KILL_SUIDGID unconditionally
in that case.
Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs/fuse')
-rw-r--r-- | fs/fuse/dir.c | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index c3e22a3dd323..28b07ae5e55f 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1648,10 +1648,20 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr, inarg.valid |= FATTR_FH; inarg.fh = ff->fh; } + + /* Kill suid/sgid for non-directory chown unconditionally */ + if (fc->handle_killpriv_v2 && !S_ISDIR(inode->i_mode) && + attr->ia_valid & (ATTR_UID | ATTR_GID)) + inarg.valid |= FATTR_KILL_SUIDGID; + if (attr->ia_valid & ATTR_SIZE) { /* For mandatory locking in truncate */ inarg.valid |= FATTR_LOCKOWNER; inarg.lock_owner = fuse_lock_owner_id(fc, current->files); + + /* Kill suid/sgid for truncate only if no CAP_FSETID */ + if (fc->handle_killpriv_v2 && !capable(CAP_FSETID)) + inarg.valid |= FATTR_KILL_SUIDGID; } fuse_setattr_fill(fc, &args, inode, &inarg, &outarg); err = fuse_simple_request(fm, &args); |