diff options
Diffstat (limited to 'fs/kernfs')
-rw-r--r-- | fs/kernfs/dir.c | 29 | ||||
-rw-r--r-- | fs/kernfs/inode.c | 162 | ||||
-rw-r--r-- | fs/kernfs/kernfs-internal.h | 8 | ||||
-rw-r--r-- | fs/kernfs/symlink.c | 4 |
4 files changed, 84 insertions, 119 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index b84d635567d3..016ba88f7335 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -532,9 +532,6 @@ 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); kmem_cache_free(kernfs_iattrs_cache, kn->iattr); } @@ -618,6 +615,7 @@ struct kernfs_node *kernfs_node_from_dentry(struct dentry *dentry) } static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root, + struct kernfs_node *parent, const char *name, umode_t mode, kuid_t uid, kgid_t gid, unsigned flags) @@ -650,11 +648,10 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root, kn->id.generation = gen; /* - * set ino first. This barrier is paired with atomic_inc_not_zero in + * set ino first. This RELEASE is paired with atomic_inc_not_zero in * kernfs_find_and_get_node_by_ino */ - smp_mb__before_atomic(); - atomic_set(&kn->count, 1); + atomic_set_release(&kn->count, 1); atomic_set(&kn->active, KN_DEACTIVATED_BIAS); RB_CLEAR_NODE(&kn->rb); @@ -674,6 +671,12 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root, goto err_out3; } + if (parent) { + ret = security_kernfs_init_security(parent, kn); + if (ret) + goto err_out3; + } + return kn; err_out3: @@ -692,7 +695,7 @@ struct kernfs_node *kernfs_new_node(struct kernfs_node *parent, { struct kernfs_node *kn; - kn = __kernfs_new_node(kernfs_root(parent), + kn = __kernfs_new_node(kernfs_root(parent), parent, name, mode, uid, gid, flags); if (kn) { kernfs_get(parent); @@ -795,9 +798,8 @@ int kernfs_add_one(struct kernfs_node *kn) /* Update timestamps on the parent */ ps_iattr = parent->iattr; if (ps_iattr) { - struct iattr *ps_iattrs = &ps_iattr->ia_iattr; - ktime_get_real_ts64(&ps_iattrs->ia_ctime); - ps_iattrs->ia_mtime = ps_iattrs->ia_ctime; + ktime_get_real_ts64(&ps_iattr->ia_ctime); + ps_iattr->ia_mtime = ps_iattr->ia_ctime; } mutex_unlock(&kernfs_mutex); @@ -962,7 +964,7 @@ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops, INIT_LIST_HEAD(&root->supers); root->next_generation = 1; - kn = __kernfs_new_node(root, "", S_IFDIR | S_IRUGO | S_IXUGO, + kn = __kernfs_new_node(root, NULL, "", S_IFDIR | S_IRUGO | S_IXUGO, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, KERNFS_DIR); if (!kn) { @@ -1329,9 +1331,8 @@ static void __kernfs_remove(struct kernfs_node *kn) /* update timestamps on the parent */ if (ps_iattr) { - ktime_get_real_ts64(&ps_iattr->ia_iattr.ia_ctime); - ps_iattr->ia_iattr.ia_mtime = - ps_iattr->ia_iattr.ia_ctime; + ktime_get_real_ts64(&ps_iattr->ia_ctime); + ps_iattr->ia_mtime = ps_iattr->ia_ctime; } kernfs_put(pos); diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c index 0c1fd945ce42..f89a0f13840e 100644 --- a/fs/kernfs/inode.c +++ b/fs/kernfs/inode.c @@ -31,30 +31,27 @@ static const struct inode_operations kernfs_iops = { .listxattr = kernfs_iop_listxattr, }; -static struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn) +static struct kernfs_iattrs *__kernfs_iattrs(struct kernfs_node *kn, int alloc) { static DEFINE_MUTEX(iattr_mutex); struct kernfs_iattrs *ret; - struct iattr *iattrs; mutex_lock(&iattr_mutex); - if (kn->iattr) + if (kn->iattr || !alloc) goto out_unlock; kn->iattr = kmem_cache_zalloc(kernfs_iattrs_cache, GFP_KERNEL); if (!kn->iattr) goto out_unlock; - iattrs = &kn->iattr->ia_iattr; /* assign default attributes */ - iattrs->ia_mode = kn->mode; - iattrs->ia_uid = GLOBAL_ROOT_UID; - iattrs->ia_gid = GLOBAL_ROOT_GID; + kn->iattr->ia_uid = GLOBAL_ROOT_UID; + kn->iattr->ia_gid = GLOBAL_ROOT_GID; - ktime_get_real_ts64(&iattrs->ia_atime); - iattrs->ia_mtime = iattrs->ia_atime; - iattrs->ia_ctime = iattrs->ia_atime; + ktime_get_real_ts64(&kn->iattr->ia_atime); + kn->iattr->ia_mtime = kn->iattr->ia_atime; + kn->iattr->ia_ctime = kn->iattr->ia_atime; simple_xattrs_init(&kn->iattr->xattrs); out_unlock: @@ -63,32 +60,37 @@ out_unlock: return ret; } +static struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn) +{ + return __kernfs_iattrs(kn, 1); +} + +static struct kernfs_iattrs *kernfs_iattrs_noalloc(struct kernfs_node *kn) +{ + return __kernfs_iattrs(kn, 0); +} + int __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr) { struct kernfs_iattrs *attrs; - struct iattr *iattrs; unsigned int ia_valid = iattr->ia_valid; attrs = kernfs_iattrs(kn); if (!attrs) return -ENOMEM; - iattrs = &attrs->ia_iattr; - if (ia_valid & ATTR_UID) - iattrs->ia_uid = iattr->ia_uid; + attrs->ia_uid = iattr->ia_uid; if (ia_valid & ATTR_GID) - iattrs->ia_gid = iattr->ia_gid; + attrs->ia_gid = iattr->ia_gid; if (ia_valid & ATTR_ATIME) - iattrs->ia_atime = iattr->ia_atime; + attrs->ia_atime = iattr->ia_atime; if (ia_valid & ATTR_MTIME) - iattrs->ia_mtime = iattr->ia_mtime; + attrs->ia_mtime = iattr->ia_mtime; if (ia_valid & ATTR_CTIME) - iattrs->ia_ctime = iattr->ia_ctime; - if (ia_valid & ATTR_MODE) { - umode_t mode = iattr->ia_mode; - iattrs->ia_mode = kn->mode = mode; - } + attrs->ia_ctime = iattr->ia_ctime; + if (ia_valid & ATTR_MODE) + kn->mode = iattr->ia_mode; return 0; } @@ -135,23 +137,6 @@ 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); @@ -171,14 +156,15 @@ static inline void set_default_inode_attr(struct inode *inode, umode_t mode) inode->i_ctime = current_time(inode); } -static inline void set_inode_attr(struct inode *inode, struct iattr *iattr) +static inline void set_inode_attr(struct inode *inode, + struct kernfs_iattrs *attrs) { struct super_block *sb = inode->i_sb; - inode->i_uid = iattr->ia_uid; - inode->i_gid = iattr->ia_gid; - inode->i_atime = timespec64_trunc(iattr->ia_atime, sb->s_time_gran); - inode->i_mtime = timespec64_trunc(iattr->ia_mtime, sb->s_time_gran); - inode->i_ctime = timespec64_trunc(iattr->ia_ctime, sb->s_time_gran); + inode->i_uid = attrs->ia_uid; + inode->i_gid = attrs->ia_gid; + inode->i_atime = timespec64_trunc(attrs->ia_atime, sb->s_time_gran); + inode->i_mtime = timespec64_trunc(attrs->ia_mtime, sb->s_time_gran); + inode->i_ctime = timespec64_trunc(attrs->ia_ctime, sb->s_time_gran); } static void kernfs_refresh_inode(struct kernfs_node *kn, struct inode *inode) @@ -186,15 +172,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); - } + set_inode_attr(inode, attrs); if (kernfs_type(kn) == KERNFS_DIR) set_nlink(inode, kn->dir.subdirs + 2); @@ -305,78 +288,57 @@ int kernfs_iop_permission(struct inode *inode, int mask) return generic_permission(inode, mask); } -static int kernfs_xattr_get(const struct xattr_handler *handler, - struct dentry *unused, struct inode *inode, - const char *suffix, void *value, size_t size) +int kernfs_xattr_get(struct kernfs_node *kn, const char *name, + void *value, size_t size) { - const char *name = xattr_full_name(handler, suffix); - struct kernfs_node *kn = inode->i_private; - struct kernfs_iattrs *attrs; - - attrs = kernfs_iattrs(kn); + struct kernfs_iattrs *attrs = kernfs_iattrs_noalloc(kn); if (!attrs) - return -ENOMEM; + return -ENODATA; return simple_xattr_get(&attrs->xattrs, name, value, size); } -static int kernfs_xattr_set(const struct xattr_handler *handler, - struct dentry *unused, struct inode *inode, - const char *suffix, const void *value, - size_t size, int flags) +int kernfs_xattr_set(struct kernfs_node *kn, const char *name, + 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; - - attrs = kernfs_iattrs(kn); + struct kernfs_iattrs *attrs = kernfs_iattrs(kn); if (!attrs) return -ENOMEM; return simple_xattr_set(&attrs->xattrs, name, value, size, flags); } -static const struct xattr_handler kernfs_trusted_xattr_handler = { - .prefix = XATTR_TRUSTED_PREFIX, - .get = kernfs_xattr_get, - .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) +static int kernfs_vfs_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; - 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; + return kernfs_xattr_get(kn, name, value, size); +} - mutex_lock(&kernfs_mutex); - error = kernfs_node_setsecdata(attrs, &secdata, &secdata_len); - mutex_unlock(&kernfs_mutex); +static int kernfs_vfs_xattr_set(const struct xattr_handler *handler, + struct dentry *unused, struct inode *inode, + 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; - if (secdata) - security_release_secctx(secdata, secdata_len); - return error; + return kernfs_xattr_set(kn, name, value, size, flags); } +static const struct xattr_handler kernfs_trusted_xattr_handler = { + .prefix = XATTR_TRUSTED_PREFIX, + .get = kernfs_vfs_xattr_get, + .set = kernfs_vfs_xattr_set, +}; + static const struct xattr_handler kernfs_security_xattr_handler = { .prefix = XATTR_SECURITY_PREFIX, - .get = kernfs_xattr_get, - .set = kernfs_security_xattr_set, + .get = kernfs_vfs_xattr_get, + .set = kernfs_vfs_xattr_set, }; const struct xattr_handler *kernfs_xattr_handlers[] = { diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index 0b7d197a904c..3c437990f39a 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -20,9 +20,11 @@ #include <linux/fs_context.h> struct kernfs_iattrs { - struct iattr ia_iattr; - void *ia_secdata; - u32 ia_secdata_len; + kuid_t ia_uid; + kgid_t ia_gid; + struct timespec64 ia_atime; + struct timespec64 ia_mtime; + struct timespec64 ia_ctime; struct simple_xattrs xattrs; }; diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c index 162f43b80c84..eb46c3a16e2f 100644 --- a/fs/kernfs/symlink.c +++ b/fs/kernfs/symlink.c @@ -33,8 +33,8 @@ struct kernfs_node *kernfs_create_link(struct kernfs_node *parent, kgid_t gid = GLOBAL_ROOT_GID; if (target->iattr) { - uid = target->iattr->ia_iattr.ia_uid; - gid = target->iattr->ia_iattr.ia_gid; + uid = target->iattr->ia_uid; + gid = target->iattr->ia_gid; } kn = kernfs_new_node(parent, name, S_IFLNK|S_IRWXUGO, uid, gid, |