diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c index a365088caa3c..673ef598d97d 100644 --- a/fs/kernfs/inode.c +++ b/fs/kernfs/inode.c @@ -288,12 +288,11 @@ 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) +static int kernfs_node_xattr_get(const struct xattr_handler *handler, + struct kernfs_node *kn, 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; attrs = kernfs_iattrs_noalloc(kn); @@ -303,13 +302,11 @@ static int kernfs_xattr_get(const struct xattr_handler *handler, 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) +static int kernfs_node_xattr_set(const struct xattr_handler *handler, + struct kernfs_node *kn, 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; attrs = kernfs_iattrs(kn); @@ -319,6 +316,25 @@ static int kernfs_xattr_set(const struct xattr_handler *handler, return simple_xattr_set(&attrs->xattrs, name, value, size, flags); } +static int kernfs_xattr_get(const struct xattr_handler *handler, + struct dentry *unused, struct inode *inode, + const char *suffix, void *value, size_t size) +{ + struct kernfs_node *kn = inode->i_private; + + return kernfs_node_xattr_get(handler, kn, suffix, 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) +{ + struct kernfs_node *kn = inode->i_private; + + return kernfs_node_xattr_set(handler, kn, suffix, value, size, flags); +} + static const struct xattr_handler kernfs_trusted_xattr_handler = { .prefix = XATTR_TRUSTED_PREFIX, .get = kernfs_xattr_get, @@ -336,3 +352,17 @@ const struct xattr_handler *kernfs_xattr_handlers[] = { &kernfs_security_xattr_handler, NULL }; + +int kernfs_security_xattr_get(struct kernfs_node *kn, const char *suffix, + void *value, size_t size) +{ + return kernfs_node_xattr_get(&kernfs_security_xattr_handler, + kn, suffix, value, size); +} + +int kernfs_security_xattr_set(struct kernfs_node *kn, const char *suffix, + void *value, size_t size, int flags) +{ + return kernfs_node_xattr_set(&kernfs_security_xattr_handler, + kn, suffix, value, size, flags); +} diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index c8893f663470..39eea07c2900 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -371,6 +371,11 @@ __poll_t kernfs_generic_poll(struct kernfs_open_file *of, struct poll_table_struct *pt); void kernfs_notify(struct kernfs_node *kn); +int kernfs_security_xattr_get(struct kernfs_node *kn, const char *suffix, + void *value, size_t size); +int kernfs_security_xattr_set(struct kernfs_node *kn, const char *suffix, + void *value, size_t size, int flags); + const void *kernfs_super_ns(struct super_block *sb); int kernfs_get_tree(struct fs_context *fc); void kernfs_free_fs_context(struct fs_context *fc); @@ -473,6 +478,16 @@ static inline int kernfs_setattr(struct kernfs_node *kn, static inline void kernfs_notify(struct kernfs_node *kn) { } +static inline int kernfs_security_xattr_get(struct kernfs_node *kn, + const char *suffix, void *value, + size_t size) +{ return -ENOSYS; } + +static inline int kernfs_security_xattr_set(struct kernfs_node *kn, + const char *suffix, void *value, + size_t size, int flags) +{ return -ENOSYS; } + static inline const void *kernfs_super_ns(struct super_block *sb) { return NULL; } diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index a9b8ff578b6b..0dd5bda719e6 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -445,6 +445,15 @@ * to abort the copy up. Note that the caller is responsible for reading * and writing the xattrs as this hook is merely a filter. * + * Security hooks for kernfs node operations + * + * @kernfs_init_security + * Initialize the security context of a newly created kernfs node based + * on its own and its parent's attributes. + * + * @kn_dir the parent kernfs node + * @kn the new child kernfs node + * * Security hooks for file operations * * @file_permission: @@ -1578,6 +1587,9 @@ union security_list_options { int (*inode_copy_up)(struct dentry *src, struct cred **new); int (*inode_copy_up_xattr)(const char *name); + int (*kernfs_init_security)(struct kernfs_node *kn_dir, + struct kernfs_node *kn); + int (*file_permission)(struct file *file, int mask); int (*file_alloc_security)(struct file *file); void (*file_free_security)(struct file *file); @@ -1879,6 +1891,7 @@ struct security_hook_heads { struct hlist_head inode_getsecid; struct hlist_head inode_copy_up; struct hlist_head inode_copy_up_xattr; + struct hlist_head kernfs_init_security; struct hlist_head file_permission; struct hlist_head file_alloc_security; struct hlist_head file_free_security; diff --git a/include/linux/security.h b/include/linux/security.h index 49f2685324b0..d543293216b9 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -51,6 +51,7 @@ struct fown_struct; struct file_operations; struct msg_msg; struct xattr; +struct kernfs_node; struct xfrm_sec_ctx; struct mm_struct; struct fs_context; @@ -299,6 +300,8 @@ int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer void security_inode_getsecid(struct inode *inode, u32 *secid); int security_inode_copy_up(struct dentry *src, struct cred **new); int security_inode_copy_up_xattr(const char *name); +int security_kernfs_init_security(struct kernfs_node *kn_dir, + struct kernfs_node *kn); int security_file_permission(struct file *file, int mask); int security_file_alloc(struct file *file); void security_file_free(struct file *file); @@ -801,6 +804,12 @@ static inline int security_inode_copy_up(struct dentry *src, struct cred **new) return 0; } +static inline int security_kernfs_init_security(struct kernfs_node *kn_dir, + struct kernfs_node *kn) +{ + return 0; +} + static inline int security_inode_copy_up_xattr(const char *name) { return -EOPNOTSUPP; diff --git a/security/security.c b/security/security.c index 23cbb1a295a3..8d6ef9da94eb 100644 --- a/security/security.c +++ b/security/security.c @@ -1318,6 +1318,12 @@ int security_inode_copy_up_xattr(const char *name) } EXPORT_SYMBOL(security_inode_copy_up_xattr); +int security_kernfs_init_security(struct kernfs_node *kn_dir, + struct kernfs_node *kn) +{ + return call_int_hook(kernfs_init_security, 0, kn_dir, kn); +} + int security_file_permission(struct file *file, int mask) { int ret;