Commit 6d9d88d0 authored by Jarkko Sakkinen's avatar Jarkko Sakkinen Committed by Linus Torvalds

tmpfs: security xattr setting on inode creation

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.

[hughd@google.com: moved under CONFIG_TMPFS_XATTR, with memcpy in shmem_xattr_alloc]
Signed-off-by: default avatarJarkko Sakkinen <jarkko.sakkinen@intel.com>
Reviewed-by: default avatarJames Morris <james.l.morris@oracle.com>
Signed-off-by: default avatarHugh Dickins <hughd@google.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 08ab9b10
...@@ -1178,6 +1178,12 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode ...@@ -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_symlink_inode_operations;
static const struct inode_operations shmem_short_symlink_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 static int
shmem_write_begin(struct file *file, struct address_space *mapping, shmem_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags, loff_t pos, unsigned len, unsigned flags,
...@@ -1490,7 +1496,7 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) ...@@ -1490,7 +1496,7 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
if (inode) { if (inode) {
error = security_inode_init_security(inode, dir, error = security_inode_init_security(inode, dir,
&dentry->d_name, &dentry->d_name,
NULL, NULL); shmem_initxattrs, NULL);
if (error) { if (error) {
if (error != -EOPNOTSUPP) { if (error != -EOPNOTSUPP) {
iput(inode); iput(inode);
...@@ -1630,7 +1636,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s ...@@ -1630,7 +1636,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
return -ENOSPC; return -ENOSPC;
error = security_inode_init_security(inode, dir, &dentry->d_name, error = security_inode_init_security(inode, dir, &dentry->d_name,
NULL, NULL); shmem_initxattrs, NULL);
if (error) { if (error) {
if (error != -EOPNOTSUPP) { if (error != -EOPNOTSUPP) {
iput(inode); iput(inode);
...@@ -1704,6 +1710,66 @@ static void shmem_put_link(struct dentry *dentry, struct nameidata *nd, void *co ...@@ -1704,6 +1710,66 @@ static void shmem_put_link(struct dentry *dentry, struct nameidata *nd, void *co
* filesystem level, though. * 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, static int shmem_xattr_get(struct dentry *dentry, const char *name,
void *buffer, size_t size) void *buffer, size_t size)
{ {
...@@ -1731,24 +1797,17 @@ static int shmem_xattr_get(struct dentry *dentry, const char *name, ...@@ -1731,24 +1797,17 @@ static int shmem_xattr_get(struct dentry *dentry, const char *name,
return ret; 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) const void *value, size_t size, int flags)
{ {
struct inode *inode = dentry->d_inode;
struct shmem_inode_info *info = SHMEM_I(inode); struct shmem_inode_info *info = SHMEM_I(inode);
struct shmem_xattr *xattr; struct shmem_xattr *xattr;
struct shmem_xattr *new_xattr = NULL; struct shmem_xattr *new_xattr = NULL;
size_t len;
int err = 0; int err = 0;
/* value == NULL means remove */ /* value == NULL means remove */
if (value) { if (value) {
/* wrap around? */ new_xattr = shmem_xattr_alloc(value, size);
len = sizeof(*new_xattr) + size;
if (len <= sizeof(*new_xattr))
return -ENOMEM;
new_xattr = kmalloc(len, GFP_KERNEL);
if (!new_xattr) if (!new_xattr)
return -ENOMEM; return -ENOMEM;
...@@ -1757,9 +1816,6 @@ static int shmem_xattr_set(struct dentry *dentry, const char *name, ...@@ -1757,9 +1816,6 @@ static int shmem_xattr_set(struct dentry *dentry, const char *name,
kfree(new_xattr); kfree(new_xattr);
return -ENOMEM; return -ENOMEM;
} }
new_xattr->size = size;
memcpy(new_xattr->value, value, size);
} }
spin_lock(&info->lock); spin_lock(&info->lock);
...@@ -1858,7 +1914,7 @@ static int shmem_setxattr(struct dentry *dentry, const char *name, ...@@ -1858,7 +1914,7 @@ static int shmem_setxattr(struct dentry *dentry, const char *name,
if (size == 0) if (size == 0)
value = ""; /* empty EA, do not remove */ 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);
} }
...@@ -1878,7 +1934,7 @@ static int shmem_removexattr(struct dentry *dentry, const char *name) ...@@ -1878,7 +1934,7 @@ static int shmem_removexattr(struct dentry *dentry, const char *name)
if (err) if (err)
return 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) static bool xattr_is_trusted(const char *name)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment