Skip to content

Commit

Permalink
xattr: Add __vfs_{get,set,remove}xattr helpers
Browse files Browse the repository at this point in the history
Right now, various places in the kernel check for the existence of
getxattr, setxattr, and removexattr inode operations and directly call
those operations.  Switch to helper functions and test for the IOP_XATTR
flag instead.

Signed-off-by: Andreas Gruenbacher <[email protected]>
Acked-by: James Morris <[email protected]>
Signed-off-by: Al Viro <[email protected]>
  • Loading branch information
Andreas Gruenbacher authored and Al Viro committed Oct 8, 2016
1 parent f5c2443 commit 5d6c319
Show file tree
Hide file tree
Showing 14 changed files with 97 additions and 85 deletions.
4 changes: 2 additions & 2 deletions fs/cachefiles/bind.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <linux/mount.h>
#include <linux/statfs.h>
#include <linux/ctype.h>
#include <linux/xattr.h>
#include "internal.h"

static int cachefiles_daemon_add_cache(struct cachefiles_cache *caches);
Expand Down Expand Up @@ -126,8 +127,7 @@ static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache)
if (d_is_negative(root) ||
!d_backing_inode(root)->i_op->lookup ||
!d_backing_inode(root)->i_op->mkdir ||
!d_backing_inode(root)->i_op->setxattr ||
!d_backing_inode(root)->i_op->getxattr ||
!(d_backing_inode(root)->i_opflags & IOP_XATTR) ||
!root->d_sb->s_op->statfs ||
!root->d_sb->s_op->sync_fs)
goto error_unsupported;
Expand Down
4 changes: 2 additions & 2 deletions fs/cachefiles/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <linux/namei.h>
#include <linux/security.h>
#include <linux/slab.h>
#include <linux/xattr.h>
#include "internal.h"

#define CACHEFILES_KEYBUF_SIZE 512
Expand Down Expand Up @@ -799,8 +800,7 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
}

ret = -EPERM;
if (!d_backing_inode(subdir)->i_op->setxattr ||
!d_backing_inode(subdir)->i_op->getxattr ||
if (!(d_backing_inode(subdir)->i_opflags & IOP_XATTR) ||
!d_backing_inode(subdir)->i_op->lookup ||
!d_backing_inode(subdir)->i_op->mkdir ||
!d_backing_inode(subdir)->i_op->create ||
Expand Down
18 changes: 8 additions & 10 deletions fs/ecryptfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1005,15 +1005,14 @@ ecryptfs_setxattr(struct dentry *dentry, struct inode *inode,
const char *name, const void *value,
size_t size, int flags)
{
int rc = 0;
int rc;
struct dentry *lower_dentry;

lower_dentry = ecryptfs_dentry_to_lower(dentry);
if (!d_inode(lower_dentry)->i_op->setxattr) {
if (!(d_inode(lower_dentry)->i_opflags & IOP_XATTR)) {
rc = -EOPNOTSUPP;
goto out;
}

rc = vfs_setxattr(lower_dentry, name, value, size, flags);
if (!rc && inode)
fsstack_copy_attr_all(inode, d_inode(lower_dentry));
Expand All @@ -1025,15 +1024,14 @@ ssize_t
ecryptfs_getxattr_lower(struct dentry *lower_dentry, struct inode *lower_inode,
const char *name, void *value, size_t size)
{
int rc = 0;
int rc;

if (!lower_inode->i_op->getxattr) {
if (!(lower_inode->i_opflags & IOP_XATTR)) {
rc = -EOPNOTSUPP;
goto out;
}
inode_lock(lower_inode);
rc = lower_inode->i_op->getxattr(lower_dentry, lower_inode,
name, value, size);
rc = __vfs_getxattr(lower_dentry, lower_inode, name, value, size);
inode_unlock(lower_inode);
out:
return rc;
Expand Down Expand Up @@ -1069,18 +1067,18 @@ ecryptfs_listxattr(struct dentry *dentry, char *list, size_t size)
static int ecryptfs_removexattr(struct dentry *dentry, struct inode *inode,
const char *name)
{
int rc = 0;
int rc;
struct dentry *lower_dentry;
struct inode *lower_inode;

lower_dentry = ecryptfs_dentry_to_lower(dentry);
lower_inode = ecryptfs_inode_to_lower(inode);
if (!lower_inode->i_op->removexattr) {
if (!(lower_inode->i_opflags & IOP_XATTR)) {
rc = -EOPNOTSUPP;
goto out;
}
inode_lock(lower_inode);
rc = lower_inode->i_op->removexattr(lower_dentry, name);
rc = __vfs_removexattr(lower_dentry, name);
inode_unlock(lower_inode);
out:
return rc;
Expand Down
13 changes: 6 additions & 7 deletions fs/ecryptfs/mmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <linux/file.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/xattr.h>
#include <asm/unaligned.h>
#include "ecryptfs_kernel.h"

Expand Down Expand Up @@ -422,7 +423,7 @@ static int ecryptfs_write_inode_size_to_xattr(struct inode *ecryptfs_inode)
struct inode *lower_inode = d_inode(lower_dentry);
int rc;

if (!lower_inode->i_op->getxattr || !lower_inode->i_op->setxattr) {
if (!(lower_inode->i_opflags & IOP_XATTR)) {
printk(KERN_WARNING
"No support for setting xattr in lower filesystem\n");
rc = -ENOSYS;
Expand All @@ -436,15 +437,13 @@ static int ecryptfs_write_inode_size_to_xattr(struct inode *ecryptfs_inode)
goto out;
}
inode_lock(lower_inode);
size = lower_inode->i_op->getxattr(lower_dentry, lower_inode,
ECRYPTFS_XATTR_NAME,
xattr_virt, PAGE_SIZE);
size = __vfs_getxattr(lower_dentry, lower_inode, ECRYPTFS_XATTR_NAME,
xattr_virt, PAGE_SIZE);
if (size < 0)
size = 8;
put_unaligned_be64(i_size_read(ecryptfs_inode), xattr_virt);
rc = lower_inode->i_op->setxattr(lower_dentry, lower_inode,
ECRYPTFS_XATTR_NAME,
xattr_virt, size, 0);
rc = __vfs_setxattr(lower_dentry, lower_inode, ECRYPTFS_XATTR_NAME,
xattr_virt, size, 0);
inode_unlock(lower_inode);
if (rc)
printk(KERN_ERR "Error whilst attempting to write inode size "
Expand Down
4 changes: 2 additions & 2 deletions fs/overlayfs/copy_up.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new)
char *buf, *name, *value = NULL;
int uninitialized_var(error);

if (!old->d_inode->i_op->getxattr ||
!new->d_inode->i_op->getxattr)
if (!(old->d_inode->i_opflags & IOP_XATTR) ||
!(new->d_inode->i_opflags & IOP_XATTR))
return 0;

list_size = vfs_listxattr(old, NULL, 0);
Expand Down
4 changes: 2 additions & 2 deletions fs/overlayfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,10 +275,10 @@ static bool ovl_is_opaquedir(struct dentry *dentry)
char val;
struct inode *inode = dentry->d_inode;

if (!S_ISDIR(inode->i_mode) || !inode->i_op->getxattr)
if (!S_ISDIR(inode->i_mode) || !(inode->i_opflags & IOP_XATTR))
return false;

res = inode->i_op->getxattr(dentry, inode, OVL_XATTR_OPAQUE, &val, 1);
res = __vfs_getxattr(dentry, inode, OVL_XATTR_OPAQUE, &val, 1);
if (res == 1 && val == 'y')
return true;

Expand Down
44 changes: 33 additions & 11 deletions fs/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,16 @@ xattr_permission(struct inode *inode, const char *name, int mask)
return inode_permission(inode, mask);
}

int
__vfs_setxattr(struct dentry *dentry, struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
if (!inode->i_op->setxattr)
return -EOPNOTSUPP;
return inode->i_op->setxattr(dentry, inode, name, value, size, flags);
}
EXPORT_SYMBOL(__vfs_setxattr);

/**
* __vfs_setxattr_noperm - perform setxattr operation without performing
* permission checks.
Expand Down Expand Up @@ -163,7 +173,7 @@ int __vfs_setxattr_noperm(struct dentry *dentry, const char *name,
if (issec)
inode->i_flags &= ~S_NOSEC;
if (inode->i_op->setxattr) {
error = inode->i_op->setxattr(dentry, inode, name, value, size, flags);
error = __vfs_setxattr(dentry, inode, name, value, size, flags);
if (!error) {
fsnotify_xattr(dentry);
security_inode_post_setxattr(dentry, name, value,
Expand Down Expand Up @@ -274,6 +284,16 @@ vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value,
return error;
}

ssize_t
__vfs_getxattr(struct dentry *dentry, struct inode *inode, const char *name,
void *value, size_t size)
{
if (!inode->i_op->getxattr)
return -EOPNOTSUPP;
return inode->i_op->getxattr(dentry, inode, name, value, size);
}
EXPORT_SYMBOL(__vfs_getxattr);

ssize_t
vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
{
Expand Down Expand Up @@ -301,13 +321,7 @@ vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
return ret;
}
nolsm:
if (inode->i_op->getxattr)
error = inode->i_op->getxattr(dentry, inode, name, value, size);
else
error = -EOPNOTSUPP;

return error;

return __vfs_getxattr(dentry, inode, name, value, size);
}
EXPORT_SYMBOL_GPL(vfs_getxattr);

Expand All @@ -332,13 +346,21 @@ vfs_listxattr(struct dentry *d, char *list, size_t size)
EXPORT_SYMBOL_GPL(vfs_listxattr);

int
vfs_removexattr(struct dentry *dentry, const char *name)
__vfs_removexattr(struct dentry *dentry, const char *name)
{
struct inode *inode = dentry->d_inode;
int error;

if (!inode->i_op->removexattr)
return -EOPNOTSUPP;
return inode->i_op->removexattr(dentry, name);
}
EXPORT_SYMBOL(__vfs_removexattr);

int
vfs_removexattr(struct dentry *dentry, const char *name)
{
struct inode *inode = dentry->d_inode;
int error;

error = xattr_permission(inode, name, MAY_WRITE);
if (error)
Expand All @@ -349,7 +371,7 @@ vfs_removexattr(struct dentry *dentry, const char *name)
if (error)
goto out;

error = inode->i_op->removexattr(dentry, name);
error = __vfs_removexattr(dentry, name);

if (!error) {
fsnotify_xattr(dentry);
Expand Down
3 changes: 3 additions & 0 deletions include/linux/xattr.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,13 @@ struct xattr {
};

ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
ssize_t __vfs_getxattr(struct dentry *, struct inode *, const char *, void *, size_t);
ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t);
ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
int __vfs_setxattr(struct dentry *, struct inode *, const char *, const void *, size_t, int);
int __vfs_setxattr_noperm(struct dentry *, const char *, const void *, size_t, int);
int vfs_setxattr(struct dentry *, const char *, const void *, size_t, int);
int __vfs_removexattr(struct dentry *, const char *);
int vfs_removexattr(struct dentry *, const char *);

ssize_t generic_getxattr(struct dentry *dentry, struct inode *inode, const char *name, void *buffer, size_t size);
Expand Down
25 changes: 10 additions & 15 deletions security/commoncap.c
Original file line number Diff line number Diff line change
Expand Up @@ -310,13 +310,8 @@ int cap_inode_need_killpriv(struct dentry *dentry)
struct inode *inode = d_backing_inode(dentry);
int error;

if (!inode->i_op->getxattr)
return 0;

error = inode->i_op->getxattr(dentry, inode, XATTR_NAME_CAPS, NULL, 0);
if (error <= 0)
return 0;
return 1;
error = __vfs_getxattr(dentry, inode, XATTR_NAME_CAPS, NULL, 0);
return error > 0;
}

/**
Expand All @@ -329,12 +324,12 @@ int cap_inode_need_killpriv(struct dentry *dentry)
*/
int cap_inode_killpriv(struct dentry *dentry)
{
struct inode *inode = d_backing_inode(dentry);

if (!inode->i_op->removexattr)
return 0;
int error;

return inode->i_op->removexattr(dentry, XATTR_NAME_CAPS);
error = __vfs_removexattr(dentry, XATTR_NAME_CAPS);
if (error == -EOPNOTSUPP)
error = 0;
return error;
}

/*
Expand Down Expand Up @@ -394,11 +389,11 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data

memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data));

if (!inode || !inode->i_op->getxattr)
if (!inode)
return -ENODATA;

size = inode->i_op->getxattr((struct dentry *)dentry, inode,
XATTR_NAME_CAPS, &caps, XATTR_CAPS_SZ);
size = __vfs_getxattr((struct dentry *)dentry, inode,
XATTR_NAME_CAPS, &caps, XATTR_CAPS_SZ);
if (size == -ENODATA || size == -EOPNOTSUPP)
/* no data, that's ok */
return -ENODATA;
Expand Down
7 changes: 4 additions & 3 deletions security/integrity/evm/evm_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,9 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
int error;
int size;

if (!inode->i_op->getxattr)
if (!(inode->i_opflags & IOP_XATTR))
return -EOPNOTSUPP;

desc = init_desc(type);
if (IS_ERR(desc))
return PTR_ERR(desc);
Expand Down Expand Up @@ -253,8 +254,8 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM,
&xattr_data,
sizeof(xattr_data), 0);
} else if (rc == -ENODATA && inode->i_op->removexattr) {
rc = inode->i_op->removexattr(dentry, XATTR_NAME_EVM);
} else if (rc == -ENODATA && (inode->i_opflags & IOP_XATTR)) {
rc = __vfs_removexattr(dentry, XATTR_NAME_EVM);
}
return rc;
}
Expand Down
4 changes: 2 additions & 2 deletions security/integrity/evm/evm_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,11 @@ static int evm_find_protected_xattrs(struct dentry *dentry)
int error;
int count = 0;

if (!inode->i_op->getxattr)
if (!(inode->i_opflags & IOP_XATTR))
return -EOPNOTSUPP;

for (xattr = evm_config_xattrnames; *xattr != NULL; xattr++) {
error = inode->i_op->getxattr(dentry, inode, *xattr, NULL, 0);
error = __vfs_getxattr(dentry, inode, *xattr, NULL, 0);
if (error < 0) {
if (error == -ENODATA)
continue;
Expand Down
21 changes: 10 additions & 11 deletions security/integrity/ima/ima_appraise.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,13 +165,13 @@ enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value,
int ima_read_xattr(struct dentry *dentry,
struct evm_ima_xattr_data **xattr_value)
{
struct inode *inode = d_backing_inode(dentry);

if (!inode->i_op->getxattr)
return 0;
ssize_t ret;

return vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)xattr_value,
0, GFP_NOFS);
ret = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)xattr_value,
0, GFP_NOFS);
if (ret == -EOPNOTSUPP)
ret = 0;
return ret;
}

/*
Expand All @@ -195,7 +195,7 @@ int ima_appraise_measurement(enum ima_hooks func,
enum integrity_status status = INTEGRITY_UNKNOWN;
int rc = xattr_len, hash_start = 0;

if (!inode->i_op->getxattr)
if (!(inode->i_opflags & IOP_XATTR))
return INTEGRITY_UNKNOWN;

if (rc <= 0) {
Expand Down Expand Up @@ -322,10 +322,10 @@ void ima_inode_post_setattr(struct dentry *dentry)
{
struct inode *inode = d_backing_inode(dentry);
struct integrity_iint_cache *iint;
int must_appraise, rc;
int must_appraise;

if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
|| !inode->i_op->removexattr)
|| !(inode->i_opflags & IOP_XATTR))
return;

must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR);
Expand All @@ -338,8 +338,7 @@ void ima_inode_post_setattr(struct dentry *dentry)
iint->flags |= IMA_APPRAISE;
}
if (!must_appraise)
rc = inode->i_op->removexattr(dentry, XATTR_NAME_IMA);
return;
__vfs_removexattr(dentry, XATTR_NAME_IMA);
}

/*
Expand Down
Loading

0 comments on commit 5d6c319

Please sign in to comment.