Setting file permissions with POSIX ACLs (setxattr) isn't clearing the setgid bit. This seems to be CVE-2016-7097, detected by running fstest generic/375 in virtiofs. Unfortunately, when the fix for this CVE landed in the kernel with commit 073931017b49 ("posix_acl: Clear SGID bit when setting file permissions"), FUSE didn't had ACLs support yet. Signed-off-by: Luis Henriques <lhenriques@xxxxxxx> --- fs/fuse/acl.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/fs/fuse/acl.c b/fs/fuse/acl.c index f529075a2ce8..1b273277c1c9 100644 --- a/fs/fuse/acl.c +++ b/fs/fuse/acl.c @@ -54,7 +54,9 @@ int fuse_set_acl(struct inode *inode, struct posix_acl *acl, int type) { struct fuse_conn *fc = get_fuse_conn(inode); const char *name; + umode_t mode = inode->i_mode; int ret; + bool update_mode = false; if (fuse_is_bad(inode)) return -EIO; @@ -62,11 +64,18 @@ int fuse_set_acl(struct inode *inode, struct posix_acl *acl, int type) if (!fc->posix_acl || fc->no_setxattr) return -EOPNOTSUPP; - if (type == ACL_TYPE_ACCESS) + if (type == ACL_TYPE_ACCESS) { name = XATTR_NAME_POSIX_ACL_ACCESS; - else if (type == ACL_TYPE_DEFAULT) + if (acl) { + ret = posix_acl_update_mode(inode, &mode, &acl); + if (ret) + return ret; + if (inode->i_mode != mode) + update_mode = true; + } + } else if (type == ACL_TYPE_DEFAULT) { name = XATTR_NAME_POSIX_ACL_DEFAULT; - else + } else return -EINVAL; if (acl) { @@ -98,6 +107,20 @@ int fuse_set_acl(struct inode *inode, struct posix_acl *acl, int type) } else { ret = fuse_removexattr(inode, name); } + if (!ret && update_mode) { + struct dentry *entry; + struct iattr attr; + + entry = d_find_alias(inode); + if (entry) { + memset(&attr, 0, sizeof(attr)); + attr.ia_valid = ATTR_MODE | ATTR_CTIME; + attr.ia_mode = mode; + attr.ia_ctime = current_time(inode); + ret = fuse_do_setattr(entry, &attr, NULL); + dput(entry); + } + } forget_all_cached_acls(inode); fuse_invalidate_attr(inode);