@@ -532,11 +532,10 @@ void kernfs_put(struct kernfs_node *kn)
kfree_const(kn->name);
if (kn->iattr) {
- if (kn->iattr->ia_secdata)
- security_release_secctx(kn->iattr->ia_secdata,
- kn->iattr->ia_secdata_len);
- simple_xattrs_free(&kn->iattr->xattrs);
+ simple_xattrs_free(&kn->iattr->xattrs_trusted);
+ simple_xattrs_free(&kn->iattr->xattrs_security);
}
+
kfree(kn->iattr);
spin_lock(&kernfs_idr_lock);
idr_remove(&root->ino_idr, kn->id.ino);
@@ -56,7 +56,8 @@ static struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn)
iattrs->ia_mtime = iattrs->ia_atime;
iattrs->ia_ctime = iattrs->ia_atime;
- simple_xattrs_init(&kn->iattr->xattrs);
+ simple_xattrs_init(&kn->iattr->xattrs_trusted);
+ simple_xattrs_init(&kn->iattr->xattrs_security);
out_unlock:
ret = kn->iattr;
mutex_unlock(&iattr_mutex);
@@ -135,33 +136,31 @@ out:
return error;
}
-static int kernfs_node_setsecdata(struct kernfs_iattrs *attrs, void **secdata,
- u32 *secdata_len)
-{
- void *old_secdata;
- size_t old_secdata_len;
-
- old_secdata = attrs->ia_secdata;
- old_secdata_len = attrs->ia_secdata_len;
-
- attrs->ia_secdata = *secdata;
- attrs->ia_secdata_len = *secdata_len;
-
- *secdata = old_secdata;
- *secdata_len = old_secdata_len;
- return 0;
-}
-
ssize_t kernfs_iop_listxattr(struct dentry *dentry, char *buf, size_t size)
{
struct kernfs_node *kn = kernfs_dentry_node(dentry);
+ struct inode *inode = d_inode(dentry);
struct kernfs_iattrs *attrs;
+ ssize_t ret, length = 0;
attrs = kernfs_iattrs(kn);
if (!attrs)
return -ENOMEM;
- return simple_xattr_list(d_inode(dentry), &attrs->xattrs, buf, size);
+ ret = simple_xattr_list(inode, &attrs->xattrs_trusted, buf, size);
+ if (ret < 0)
+ return ret;
+ length += ret;
+
+ buf += ret;
+ size -= ret;
+
+ ret = simple_xattr_list(inode, &attrs->xattrs_security, buf, size);
+ if (ret < 0)
+ return ret;
+ length += ret;
+
+ return length;
}
static inline void set_default_inode_attr(struct inode *inode, umode_t mode)
@@ -186,15 +185,12 @@ static void kernfs_refresh_inode(struct kernfs_node *kn, struct inode *inode)
struct kernfs_iattrs *attrs = kn->iattr;
inode->i_mode = kn->mode;
- if (attrs) {
+ if (attrs)
/*
* kernfs_node has non-default attributes get them from
* persistent copy in kernfs_node.
*/
set_inode_attr(inode, &attrs->ia_iattr);
- security_inode_notifysecctx(inode, attrs->ia_secdata,
- attrs->ia_secdata_len);
- }
if (kernfs_type(kn) == KERNFS_DIR)
set_nlink(inode, kn->dir.subdirs + 2);
@@ -305,19 +301,29 @@ int kernfs_iop_permission(struct inode *inode, int mask)
return generic_permission(inode, mask);
}
+static const struct xattr_handler kernfs_trusted_xattr_handler;
+static const struct xattr_handler kernfs_security_xattr_handler;
+
static int kernfs_xattr_get(const struct xattr_handler *handler,
struct dentry *unused, struct inode *inode,
const char *suffix, void *value, size_t size)
{
- const char *name = xattr_full_name(handler, suffix);
struct kernfs_node *kn = inode->i_private;
struct kernfs_iattrs *attrs;
+ struct simple_xattrs *xattrs;
attrs = kernfs_iattrs(kn);
if (!attrs)
return -ENOMEM;
- return simple_xattr_get(&attrs->xattrs, name, value, size);
+ if (handler == &kernfs_trusted_xattr_handler)
+ xattrs = &attrs->xattrs_trusted;
+ else if (handler == &kernfs_security_xattr_handler)
+ xattrs = &attrs->xattrs_security;
+ else
+ return -EINVAL;
+
+ return simple_xattr_get(xattrs, suffix, value, size);
}
static int kernfs_xattr_set(const struct xattr_handler *handler,
@@ -325,15 +331,22 @@ static int kernfs_xattr_set(const struct xattr_handler *handler,
const char *suffix, const void *value,
size_t size, int flags)
{
- const char *name = xattr_full_name(handler, suffix);
struct kernfs_node *kn = inode->i_private;
struct kernfs_iattrs *attrs;
+ struct simple_xattrs *xattrs;
attrs = kernfs_iattrs(kn);
if (!attrs)
return -ENOMEM;
- return simple_xattr_set(&attrs->xattrs, name, value, size, flags);
+ if (handler == &kernfs_trusted_xattr_handler)
+ xattrs = &attrs->xattrs_trusted;
+ else if (handler == &kernfs_security_xattr_handler)
+ xattrs = &attrs->xattrs_security;
+ else
+ return -EINVAL;
+
+ return simple_xattr_set(xattrs, suffix, value, size, flags);
}
static const struct xattr_handler kernfs_trusted_xattr_handler = {
@@ -342,41 +355,10 @@ static const struct xattr_handler kernfs_trusted_xattr_handler = {
.set = kernfs_xattr_set,
};
-static int kernfs_security_xattr_set(const struct xattr_handler *handler,
- struct dentry *unused, struct inode *inode,
- const char *suffix, const void *value,
- size_t size, int flags)
-{
- struct kernfs_node *kn = inode->i_private;
- struct kernfs_iattrs *attrs;
- void *secdata;
- u32 secdata_len = 0;
- int error;
-
- attrs = kernfs_iattrs(kn);
- if (!attrs)
- return -ENOMEM;
-
- error = security_inode_setsecurity(inode, suffix, value, size, flags);
- if (error)
- return error;
- error = security_inode_getsecctx(inode, &secdata, &secdata_len);
- if (error)
- return error;
-
- mutex_lock(&kernfs_mutex);
- error = kernfs_node_setsecdata(attrs, &secdata, &secdata_len);
- mutex_unlock(&kernfs_mutex);
-
- if (secdata)
- security_release_secctx(secdata, secdata_len);
- return error;
-}
-
static const struct xattr_handler kernfs_security_xattr_handler = {
.prefix = XATTR_SECURITY_PREFIX,
.get = kernfs_xattr_get,
- .set = kernfs_security_xattr_set,
+ .set = kernfs_xattr_set,
};
const struct xattr_handler *kernfs_xattr_handlers[] = {
@@ -20,10 +20,9 @@
struct kernfs_iattrs {
struct iattr ia_iattr;
- void *ia_secdata;
- u32 ia_secdata_len;
- struct simple_xattrs xattrs;
+ struct simple_xattrs xattrs_trusted;
+ struct simple_xattrs xattrs_security;
};
/* +1 to avoid triggering overflow warning when negating it */
Replace the special handling of security xattrs with simple_xattrs, as is already done for the trusted xattrs. This simplifies the code and allows LSMs to use more than just a single xattr to do their business. Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com> --- fs/kernfs/dir.c | 7 ++- fs/kernfs/inode.c | 100 +++++++++++++++--------------------- fs/kernfs/kernfs-internal.h | 5 +- 3 files changed, 46 insertions(+), 66 deletions(-)