Commit 2b88fc21 authored by Andreas Gruenbacher's avatar Andreas Gruenbacher Committed by Al Viro

ubifs: Switch to generic xattr handlers

Ubifs internally uses special inodes for storing xattrs. Those inodes
had NULL {get,set,remove}xattr inode operations before this change, so
xattr operations on them would fail. The super block's s_xattr field
would also apply to those special inodes. However, the inodes are not
visible outside of ubifs, and so no xattr operations will ever be
carried out on them anyway.
Signed-off-by: default avatarAndreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: default avatarRichard Weinberger <richard@nod.at>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent c8b6056a
...@@ -1182,10 +1182,10 @@ const struct inode_operations ubifs_dir_inode_operations = { ...@@ -1182,10 +1182,10 @@ const struct inode_operations ubifs_dir_inode_operations = {
.rename = ubifs_rename, .rename = ubifs_rename,
.setattr = ubifs_setattr, .setattr = ubifs_setattr,
.getattr = ubifs_getattr, .getattr = ubifs_getattr,
.setxattr = ubifs_setxattr, .setxattr = generic_setxattr,
.getxattr = ubifs_getxattr, .getxattr = generic_getxattr,
.listxattr = ubifs_listxattr, .listxattr = ubifs_listxattr,
.removexattr = ubifs_removexattr, .removexattr = generic_removexattr,
#ifdef CONFIG_UBIFS_ATIME_SUPPORT #ifdef CONFIG_UBIFS_ATIME_SUPPORT
.update_time = ubifs_update_time, .update_time = ubifs_update_time,
#endif #endif
......
...@@ -1597,10 +1597,10 @@ const struct address_space_operations ubifs_file_address_operations = { ...@@ -1597,10 +1597,10 @@ const struct address_space_operations ubifs_file_address_operations = {
const struct inode_operations ubifs_file_inode_operations = { const struct inode_operations ubifs_file_inode_operations = {
.setattr = ubifs_setattr, .setattr = ubifs_setattr,
.getattr = ubifs_getattr, .getattr = ubifs_getattr,
.setxattr = ubifs_setxattr, .setxattr = generic_setxattr,
.getxattr = ubifs_getxattr, .getxattr = generic_getxattr,
.listxattr = ubifs_listxattr, .listxattr = ubifs_listxattr,
.removexattr = ubifs_removexattr, .removexattr = generic_removexattr,
#ifdef CONFIG_UBIFS_ATIME_SUPPORT #ifdef CONFIG_UBIFS_ATIME_SUPPORT
.update_time = ubifs_update_time, .update_time = ubifs_update_time,
#endif #endif
...@@ -1611,10 +1611,10 @@ const struct inode_operations ubifs_symlink_inode_operations = { ...@@ -1611,10 +1611,10 @@ const struct inode_operations ubifs_symlink_inode_operations = {
.get_link = simple_get_link, .get_link = simple_get_link,
.setattr = ubifs_setattr, .setattr = ubifs_setattr,
.getattr = ubifs_getattr, .getattr = ubifs_getattr,
.setxattr = ubifs_setxattr, .setxattr = generic_setxattr,
.getxattr = ubifs_getxattr, .getxattr = generic_getxattr,
.listxattr = ubifs_listxattr, .listxattr = ubifs_listxattr,
.removexattr = ubifs_removexattr, .removexattr = generic_removexattr,
#ifdef CONFIG_UBIFS_ATIME_SUPPORT #ifdef CONFIG_UBIFS_ATIME_SUPPORT
.update_time = ubifs_update_time, .update_time = ubifs_update_time,
#endif #endif
......
...@@ -2040,6 +2040,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -2040,6 +2040,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
if (c->max_inode_sz > MAX_LFS_FILESIZE) if (c->max_inode_sz > MAX_LFS_FILESIZE)
sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE; sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE;
sb->s_op = &ubifs_super_operations; sb->s_op = &ubifs_super_operations;
sb->s_xattr = ubifs_xattr_handlers;
mutex_lock(&c->umount_mutex); mutex_lock(&c->umount_mutex);
err = mount_ubifs(c); err = mount_ubifs(c);
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/xattr.h>
#include "ubifs-media.h" #include "ubifs-media.h"
/* Version of this UBIFS implementation */ /* Version of this UBIFS implementation */
...@@ -1732,12 +1733,8 @@ int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry, ...@@ -1732,12 +1733,8 @@ int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat); struct kstat *stat);
/* xattr.c */ /* xattr.c */
int ubifs_setxattr(struct dentry *dentry, const char *name, extern const struct xattr_handler *ubifs_xattr_handlers[];
const void *value, size_t size, int flags);
ssize_t ubifs_getxattr(struct dentry *dentry, struct inode *host,
const char *name, void *buf, size_t size);
ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size); ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size);
int ubifs_removexattr(struct dentry *dentry, const char *name);
int ubifs_init_security(struct inode *dentry, struct inode *inode, int ubifs_init_security(struct inode *dentry, struct inode *inode,
const struct qstr *qstr); const struct qstr *qstr);
......
...@@ -249,42 +249,6 @@ static int change_xattr(struct ubifs_info *c, struct inode *host, ...@@ -249,42 +249,6 @@ static int change_xattr(struct ubifs_info *c, struct inode *host,
return err; return err;
} }
/**
* check_namespace - check extended attribute name-space.
* @nm: extended attribute name
*
* This function makes sure the extended attribute name belongs to one of the
* supported extended attribute name-spaces. Returns name-space index in case
* of success and a negative error code in case of failure.
*/
static int check_namespace(const struct qstr *nm)
{
int type;
if (nm->len > UBIFS_MAX_NLEN)
return -ENAMETOOLONG;
if (!strncmp(nm->name, XATTR_TRUSTED_PREFIX,
XATTR_TRUSTED_PREFIX_LEN)) {
if (nm->name[XATTR_TRUSTED_PREFIX_LEN] == '\0')
return -EINVAL;
type = TRUSTED_XATTR;
} else if (!strncmp(nm->name, XATTR_USER_PREFIX,
XATTR_USER_PREFIX_LEN)) {
if (nm->name[XATTR_USER_PREFIX_LEN] == '\0')
return -EINVAL;
type = USER_XATTR;
} else if (!strncmp(nm->name, XATTR_SECURITY_PREFIX,
XATTR_SECURITY_PREFIX_LEN)) {
if (nm->name[XATTR_SECURITY_PREFIX_LEN] == '\0')
return -EINVAL;
type = SECURITY_XATTR;
} else
return -EOPNOTSUPP;
return type;
}
static struct inode *iget_xattr(struct ubifs_info *c, ino_t inum) static struct inode *iget_xattr(struct ubifs_info *c, ino_t inum)
{ {
struct inode *inode; struct inode *inode;
...@@ -302,24 +266,23 @@ static struct inode *iget_xattr(struct ubifs_info *c, ino_t inum) ...@@ -302,24 +266,23 @@ static struct inode *iget_xattr(struct ubifs_info *c, ino_t inum)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
static int setxattr(struct inode *host, const char *name, const void *value, static int __ubifs_setxattr(struct inode *host, const char *name,
size_t size, int flags) const void *value, size_t size, int flags)
{ {
struct inode *inode; struct inode *inode;
struct ubifs_info *c = host->i_sb->s_fs_info; struct ubifs_info *c = host->i_sb->s_fs_info;
struct qstr nm = QSTR_INIT(name, strlen(name)); struct qstr nm = QSTR_INIT(name, strlen(name));
struct ubifs_dent_node *xent; struct ubifs_dent_node *xent;
union ubifs_key key; union ubifs_key key;
int err, type; int err;
ubifs_assert(inode_is_locked(host)); ubifs_assert(inode_is_locked(host));
if (size > UBIFS_MAX_INO_DATA) if (size > UBIFS_MAX_INO_DATA)
return -ERANGE; return -ERANGE;
type = check_namespace(&nm); if (nm.len > UBIFS_MAX_NLEN)
if (type < 0) return -ENAMETOOLONG;
return type;
xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS); xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
if (!xent) if (!xent)
...@@ -363,17 +326,8 @@ static int setxattr(struct inode *host, const char *name, const void *value, ...@@ -363,17 +326,8 @@ static int setxattr(struct inode *host, const char *name, const void *value,
return err; return err;
} }
int ubifs_setxattr(struct dentry *dentry, const char *name, static ssize_t __ubifs_getxattr(struct inode *host, const char *name,
const void *value, size_t size, int flags) void *buf, size_t size)
{
dbg_gen("xattr '%s', host ino %lu ('%pd'), size %zd",
name, d_inode(dentry)->i_ino, dentry, size);
return setxattr(d_inode(dentry), name, value, size, flags);
}
ssize_t ubifs_getxattr(struct dentry *dentry, struct inode *host,
const char *name, void *buf, size_t size)
{ {
struct inode *inode; struct inode *inode;
struct ubifs_info *c = host->i_sb->s_fs_info; struct ubifs_info *c = host->i_sb->s_fs_info;
...@@ -383,12 +337,8 @@ ssize_t ubifs_getxattr(struct dentry *dentry, struct inode *host, ...@@ -383,12 +337,8 @@ ssize_t ubifs_getxattr(struct dentry *dentry, struct inode *host,
union ubifs_key key; union ubifs_key key;
int err; int err;
dbg_gen("xattr '%s', ino %lu ('%pd'), buf size %zd", name, if (nm.len > UBIFS_MAX_NLEN)
host->i_ino, dentry, size); return -ENAMETOOLONG;
err = check_namespace(&nm);
if (err < 0)
return err;
xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS); xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
if (!xent) if (!xent)
...@@ -460,8 +410,6 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size) ...@@ -460,8 +410,6 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
lowest_xent_key(c, &key, host->i_ino); lowest_xent_key(c, &key, host->i_ino);
while (1) { while (1) {
int type;
xent = ubifs_tnc_next_ent(c, &key, &nm); xent = ubifs_tnc_next_ent(c, &key, &nm);
if (IS_ERR(xent)) { if (IS_ERR(xent)) {
err = PTR_ERR(xent); err = PTR_ERR(xent);
...@@ -471,14 +419,10 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size) ...@@ -471,14 +419,10 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
nm.name = xent->name; nm.name = xent->name;
nm.len = le16_to_cpu(xent->nlen); nm.len = le16_to_cpu(xent->nlen);
type = check_namespace(&nm);
if (unlikely(type < 0)) {
err = type;
break;
}
/* Show trusted namespace only for "power" users */ /* Show trusted namespace only for "power" users */
if (type != TRUSTED_XATTR || capable(CAP_SYS_ADMIN)) { if (strncmp(xent->name, XATTR_TRUSTED_PREFIX,
XATTR_TRUSTED_PREFIX_LEN) ||
capable(CAP_SYS_ADMIN)) {
memcpy(buffer + written, nm.name, nm.len + 1); memcpy(buffer + written, nm.name, nm.len + 1);
written += nm.len + 1; written += nm.len + 1;
} }
...@@ -538,22 +482,19 @@ static int remove_xattr(struct ubifs_info *c, struct inode *host, ...@@ -538,22 +482,19 @@ static int remove_xattr(struct ubifs_info *c, struct inode *host,
return err; return err;
} }
int ubifs_removexattr(struct dentry *dentry, const char *name) static int __ubifs_removexattr(struct inode *host, const char *name)
{ {
struct inode *inode, *host = d_inode(dentry); struct inode *inode;
struct ubifs_info *c = host->i_sb->s_fs_info; struct ubifs_info *c = host->i_sb->s_fs_info;
struct qstr nm = QSTR_INIT(name, strlen(name)); struct qstr nm = QSTR_INIT(name, strlen(name));
struct ubifs_dent_node *xent; struct ubifs_dent_node *xent;
union ubifs_key key; union ubifs_key key;
int err; int err;
dbg_gen("xattr '%s', ino %lu ('%pd')", name,
host->i_ino, dentry);
ubifs_assert(inode_is_locked(host)); ubifs_assert(inode_is_locked(host));
err = check_namespace(&nm); if (nm.len > UBIFS_MAX_NLEN)
if (err < 0) return -ENAMETOOLONG;
return err;
xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS); xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
if (!xent) if (!xent)
...@@ -603,7 +544,7 @@ static int init_xattrs(struct inode *inode, const struct xattr *xattr_array, ...@@ -603,7 +544,7 @@ static int init_xattrs(struct inode *inode, const struct xattr *xattr_array,
} }
strcpy(name, XATTR_SECURITY_PREFIX); strcpy(name, XATTR_SECURITY_PREFIX);
strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name); strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name);
err = setxattr(inode, name, xattr->value, xattr->value_len, 0); err = __ubifs_setxattr(inode, name, xattr->value, xattr->value_len, 0);
kfree(name); kfree(name);
if (err < 0) if (err < 0)
break; break;
...@@ -626,3 +567,53 @@ int ubifs_init_security(struct inode *dentry, struct inode *inode, ...@@ -626,3 +567,53 @@ int ubifs_init_security(struct inode *dentry, struct inode *inode,
} }
return err; return err;
} }
static int ubifs_xattr_get(const struct xattr_handler *handler,
struct dentry *dentry, struct inode *inode,
const char *name, void *buffer, size_t size)
{
dbg_gen("xattr '%s', ino %lu ('%pd'), buf size %zd", name,
inode->i_ino, dentry, size);
return __ubifs_getxattr(inode, name, buffer, size);
}
static int ubifs_xattr_set(const struct xattr_handler *handler,
struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
struct inode *inode = d_inode(dentry);
dbg_gen("xattr '%s', host ino %lu ('%pd'), size %zd",
name, inode->i_ino, dentry, size);
if (value)
return __ubifs_setxattr(inode, name, value, size, flags);
else
return __ubifs_removexattr(inode, name);
}
const struct xattr_handler ubifs_user_xattr_handler = {
.prefix = XATTR_USER_PREFIX,
.get = ubifs_xattr_get,
.set = ubifs_xattr_set,
};
const struct xattr_handler ubifs_trusted_xattr_handler = {
.prefix = XATTR_TRUSTED_PREFIX,
.get = ubifs_xattr_get,
.set = ubifs_xattr_set,
};
const struct xattr_handler ubifs_security_xattr_handler = {
.prefix = XATTR_SECURITY_PREFIX,
.get = ubifs_xattr_get,
.set = ubifs_xattr_set,
};
const struct xattr_handler *ubifs_xattr_handlers[] = {
&ubifs_user_xattr_handler,
&ubifs_trusted_xattr_handler,
&ubifs_security_xattr_handler,
NULL
};
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