Skip to content

Commit

Permalink
UBUNTU: SAUCE: overlayfs: Skip permission checking for trusted.overla…
Browse files Browse the repository at this point in the history
…yfs.* xattrs

The original mounter had CAP_SYS_ADMIN in the user namespace
where the mount happened, and the vfs has validated that the user
has permission to do the requested operation. This is sufficient
for allowing the kernel to write these specific xattrs, so we can
bypass the permission checks for these xattrs.

To support this, export __vfs_setxattr_noperm and add an similar
__vfs_removexattr_noperm which is also exported. Use these when
setting or removing trusted.overlayfs.* xattrs.

BugLink: http://bugs.launchpad.net/bugs/1531747
BugLink: http://bugs.launchpad.net/bugs/1534961
BugLink: http://bugs.launchpad.net/bugs/1535150
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
  • Loading branch information
Seth Forshee authored and Andrea Righi committed Mar 9, 2023
1 parent 4ef1832 commit 2c7ab14
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 9 deletions.
16 changes: 13 additions & 3 deletions fs/overlayfs/overlayfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,12 @@ static inline int ovl_do_setxattr(struct ovl_fs *ofs, struct dentry *dentry,
const char *name, const void *value,
size_t size, int flags)
{
int err = vfs_setxattr(ovl_upper_mnt_userns(ofs), dentry, name,
value, size, flags);
struct inode *inode = dentry->d_inode;
int err;

inode_lock(inode);
err = __vfs_setxattr_noperm(&init_user_ns, dentry, name, value, size, flags);
inode_unlock(inode);

pr_debug("setxattr(%pd2, \"%s\", \"%*pE\", %zu, %d) = %i\n",
dentry, name, min((int)size, 48), value, size, flags, err);
Expand All @@ -269,7 +273,13 @@ static inline int ovl_setxattr(struct ovl_fs *ofs, struct dentry *dentry,
static inline int ovl_do_removexattr(struct ovl_fs *ofs, struct dentry *dentry,
const char *name)
{
int err = vfs_removexattr(ovl_upper_mnt_userns(ofs), dentry, name);
struct inode *inode = dentry->d_inode;
int err;

inode_lock(inode);
err = __vfs_removexattr_noperm(&init_user_ns, dentry, name);
inode_unlock(inode);

pr_debug("removexattr(%pd2, \"%s\") = %i\n", dentry, name, err);
return err;
}
Expand Down
36 changes: 30 additions & 6 deletions fs/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ int __vfs_setxattr_noperm(struct user_namespace *mnt_userns,

return error;
}
EXPORT_SYMBOL_GPL(__vfs_setxattr_noperm);

/**
* __vfs_setxattr_locked - set an extended attribute while holding the inode
Expand Down Expand Up @@ -499,6 +500,34 @@ __vfs_removexattr(struct user_namespace *mnt_userns, struct dentry *dentry,
}
EXPORT_SYMBOL(__vfs_removexattr);

/**
* __vfs_removexattr_noperm - perform removexattr operation without
* performing permission checks.
*
* @dentry - object to perform setxattr on
* @name - xattr name to set
*
* returns the result of the internal setxattr or setsecurity operations.
*
* This function requires the caller to lock the inode's i_mutex before it
* is executed. It also assumes that the caller will make the appropriate
* permission checks.
*/
int
__vfs_removexattr_noperm(struct user_namespace *mnt_userns,
struct dentry *dentry, const char *name)
{
int error;

error =__vfs_removexattr(mnt_userns, dentry, name);
if (!error) {
fsnotify_xattr(dentry);
evm_inode_post_removexattr(dentry, name);
}
return error;
}
EXPORT_SYMBOL_GPL(__vfs_removexattr_noperm);

/**
* __vfs_removexattr_locked - set an extended attribute while holding the inode
* lock
Expand Down Expand Up @@ -529,12 +558,7 @@ __vfs_removexattr_locked(struct user_namespace *mnt_userns,
if (error)
goto out;

error = __vfs_removexattr(mnt_userns, dentry, name);

if (!error) {
fsnotify_xattr(dentry);
evm_inode_post_removexattr(dentry, name);
}
error = __vfs_removexattr_noperm(mnt_userns, dentry, name);

out:
return error;
Expand Down
1 change: 1 addition & 0 deletions include/linux/xattr.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ int __vfs_setxattr_locked(struct user_namespace *, struct dentry *,
int vfs_setxattr(struct user_namespace *, struct dentry *, const char *,
const void *, size_t, int);
int __vfs_removexattr(struct user_namespace *, struct dentry *, const char *);
int __vfs_removexattr_noperm(struct user_namespace *, struct dentry *, const char *);
int __vfs_removexattr_locked(struct user_namespace *, struct dentry *,
const char *, struct inode **);
int vfs_removexattr(struct user_namespace *, struct dentry *, const char *);
Expand Down

0 comments on commit 2c7ab14

Please sign in to comment.