Skip to content

Commit

Permalink
tmpfs: security xattr setting on inode creation
Browse files Browse the repository at this point in the history
Adds to generic xattr support introduced in Linux 3.0 by implementing
initxattrs callback.  This enables consulting of security attributes from
LSM and EVM when inode is created.

[[email protected]: moved under CONFIG_TMPFS_XATTR, with memcpy in shmem_xattr_alloc]
Signed-off-by: Jarkko Sakkinen <[email protected]>
Reviewed-by: James Morris <[email protected]>
Signed-off-by: Hugh Dickins <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Jarkko Sakkinen authored and torvalds committed Mar 22, 2012
1 parent 08ab9b1 commit 6d9d88d
Showing 1 changed file with 72 additions and 16 deletions.
88 changes: 72 additions & 16 deletions mm/shmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -1178,6 +1178,12 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
static const struct inode_operations shmem_symlink_inode_operations;
static const struct inode_operations shmem_short_symlink_operations;

#ifdef CONFIG_TMPFS_XATTR
static int shmem_initxattrs(struct inode *, const struct xattr *, void *);
#else
#define shmem_initxattrs NULL
#endif

static int
shmem_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
Expand Down Expand Up @@ -1490,7 +1496,7 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
if (inode) {
error = security_inode_init_security(inode, dir,
&dentry->d_name,
NULL, NULL);
shmem_initxattrs, NULL);
if (error) {
if (error != -EOPNOTSUPP) {
iput(inode);
Expand Down Expand Up @@ -1630,7 +1636,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
return -ENOSPC;

error = security_inode_init_security(inode, dir, &dentry->d_name,
NULL, NULL);
shmem_initxattrs, NULL);
if (error) {
if (error != -EOPNOTSUPP) {
iput(inode);
Expand Down Expand Up @@ -1704,6 +1710,66 @@ static void shmem_put_link(struct dentry *dentry, struct nameidata *nd, void *co
* filesystem level, though.
*/

/*
* Allocate new xattr and copy in the value; but leave the name to callers.
*/
static struct shmem_xattr *shmem_xattr_alloc(const void *value, size_t size)
{
struct shmem_xattr *new_xattr;
size_t len;

/* wrap around? */
len = sizeof(*new_xattr) + size;
if (len <= sizeof(*new_xattr))
return NULL;

new_xattr = kmalloc(len, GFP_KERNEL);
if (!new_xattr)
return NULL;

new_xattr->size = size;
memcpy(new_xattr->value, value, size);
return new_xattr;
}

/*
* Callback for security_inode_init_security() for acquiring xattrs.
*/
static int shmem_initxattrs(struct inode *inode,
const struct xattr *xattr_array,
void *fs_info)
{
struct shmem_inode_info *info = SHMEM_I(inode);
const struct xattr *xattr;
struct shmem_xattr *new_xattr;
size_t len;

for (xattr = xattr_array; xattr->name != NULL; xattr++) {
new_xattr = shmem_xattr_alloc(xattr->value, xattr->value_len);
if (!new_xattr)
return -ENOMEM;

len = strlen(xattr->name) + 1;
new_xattr->name = kmalloc(XATTR_SECURITY_PREFIX_LEN + len,
GFP_KERNEL);
if (!new_xattr->name) {
kfree(new_xattr);
return -ENOMEM;
}

memcpy(new_xattr->name, XATTR_SECURITY_PREFIX,
XATTR_SECURITY_PREFIX_LEN);
memcpy(new_xattr->name + XATTR_SECURITY_PREFIX_LEN,
xattr->name, len);

spin_lock(&info->lock);
list_add(&new_xattr->list, &info->xattr_list);
spin_unlock(&info->lock);
}

return 0;
}

static int shmem_xattr_get(struct dentry *dentry, const char *name,
void *buffer, size_t size)
{
Expand Down Expand Up @@ -1731,24 +1797,17 @@ static int shmem_xattr_get(struct dentry *dentry, const char *name,
return ret;
}

static int shmem_xattr_set(struct dentry *dentry, const char *name,
static int shmem_xattr_set(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
struct inode *inode = dentry->d_inode;
struct shmem_inode_info *info = SHMEM_I(inode);
struct shmem_xattr *xattr;
struct shmem_xattr *new_xattr = NULL;
size_t len;
int err = 0;

/* value == NULL means remove */
if (value) {
/* wrap around? */
len = sizeof(*new_xattr) + size;
if (len <= sizeof(*new_xattr))
return -ENOMEM;

new_xattr = kmalloc(len, GFP_KERNEL);
new_xattr = shmem_xattr_alloc(value, size);
if (!new_xattr)
return -ENOMEM;

Expand All @@ -1757,9 +1816,6 @@ static int shmem_xattr_set(struct dentry *dentry, const char *name,
kfree(new_xattr);
return -ENOMEM;
}

new_xattr->size = size;
memcpy(new_xattr->value, value, size);
}

spin_lock(&info->lock);
Expand Down Expand Up @@ -1858,7 +1914,7 @@ static int shmem_setxattr(struct dentry *dentry, const char *name,
if (size == 0)
value = ""; /* empty EA, do not remove */

return shmem_xattr_set(dentry, name, value, size, flags);
return shmem_xattr_set(dentry->d_inode, name, value, size, flags);

}

Expand All @@ -1878,7 +1934,7 @@ static int shmem_removexattr(struct dentry *dentry, const char *name)
if (err)
return err;

return shmem_xattr_set(dentry, name, NULL, 0, XATTR_REPLACE);
return shmem_xattr_set(dentry->d_inode, name, NULL, 0, XATTR_REPLACE);
}

static bool xattr_is_trusted(const char *name)
Expand Down

0 comments on commit 6d9d88d

Please sign in to comment.