On 1/9/2019 8:28 AM, Ondrej Mosnacek wrote: > This patch introduces a new security hook that is intended for > initializing the security data for newly created pseudo filesystem > objects (such as kernfs nodes) that provide a way of storing a > non-default security context, but need to operate independently from > mounts. > > The main motivation is to allow kernfs nodes to inherit the context of > the parent under SELinux, similar to the behavior of > security_inode_init_security(). Other LSMs may implement their own logic > for handling the creation of new nodes. > > Signed-off-by: Ondrej Mosnacek <omosnace@xxxxxxxxxx> > --- > include/linux/lsm_hooks.h | 30 ++++++++++++++++++++++++++++++ > include/linux/security.h | 14 ++++++++++++++ > security/security.c | 10 ++++++++++ > 3 files changed, 54 insertions(+) > > diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h > index aaeb7fa24dc4..3a2399d7721f 100644 > --- a/include/linux/lsm_hooks.h > +++ b/include/linux/lsm_hooks.h > @@ -429,6 +429,31 @@ > * 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 special file-like objects > + * > + * @object_init_security: I don't like the name. There are too many things that are "objects" for this to be meaningful. I also dislike seeing names like security_object_init_security. How about init_from_parent? If there's never a chance that it will be used anywhere but with kernfs, it could be kernfs_node_init. The existing set of hook names are sufficiently confusing without adding to the mystery. > + * Obtain the security context for a newly created filesystem object > + * based on the security context of the parent node. The purpose is > + * similar to @inode_init_security, but this hook is intended for > + * non-inode objects that need to behave like a directory tree (e.g. > + * kernfs nodes). In this case it is assumed that the LSM assigns some > + * default context to the node by default and the object internally stores > + * a copy of the security context if (and only if) it has been set to a > + * non-default value explicitly (e.g. via *setxattr(2)). > + * > + * @parent_ctx contains the security context of the parent directory > + * (must not be NULL -- if the parent has no explicit context set, > + * the child should also keep the default context and the hook should > + * not be called). > + * @parent_ctxlen contains the length of @parent_ctx data. > + * @qstr contains the last path component of the new object. > + * @mode contanis the file mode of the object. s/contanis/contains/ > + * @ctx is a pointer in which to place the allocated security context. > + * @ctxlen points to the place to put the length of @ctx. > + * > + * Returns 0 if @ctx and @ctxlen have been successfully set or > + * -ENOMEM on memory allocation failure. > + * > * Security hooks for file operations > * > * @file_permission: > @@ -1556,6 +1581,10 @@ union security_list_options { > int (*inode_copy_up)(struct dentry *src, struct cred **new); > int (*inode_copy_up_xattr)(const char *name); > > + int (*object_init_security)(void *parent_ctx, u32 parent_ctxlen, > + const struct qstr *qstr, u16 mode, > + void **ctx, u32 *ctxlen); > + > int (*file_permission)(struct file *file, int mask); > int (*file_alloc_security)(struct file *file); > void (*file_free_security)(struct file *file); > @@ -1855,6 +1884,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 object_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 d170a5b031f3..1e7971d10fe6 100644 > --- a/include/linux/security.h > +++ b/include/linux/security.h > @@ -315,6 +315,9 @@ 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_object_init_security(void *parent_ctx, u32 parent_ctxlen, > + const struct qstr *qstr, u16 mode, > + void **ctx, u32 *ctxlen); > int security_file_permission(struct file *file, int mask); > int security_file_alloc(struct file *file); > void security_file_free(struct file *file); > @@ -815,6 +818,17 @@ static inline int security_inode_copy_up_xattr(const char *name) > return -EOPNOTSUPP; > } > > +static inline int security_object_init_security(void *parent_ctx, > + u32 parent_ctxlen, > + const struct qstr *qstr, > + u16 mode, void **ctx, > + u32 *ctxlen) > +{ > + *ctx = NULL; > + *ctxlen = 0; > + return 0; > +} > + > static inline int security_file_permission(struct file *file, int mask) > { > return 0; > diff --git a/security/security.c b/security/security.c > index 04d173eb93f6..a010bfbe3fc6 100644 > --- a/security/security.c > +++ b/security/security.c > @@ -879,6 +879,16 @@ int security_inode_copy_up_xattr(const char *name) > } > EXPORT_SYMBOL(security_inode_copy_up_xattr); > > +int security_object_init_security(void *parent_ctx, u32 parent_ctxlen, > + const struct qstr *qstr, u16 mode, > + void **ctx, u32 *ctxlen) > +{ > + *ctx = NULL; > + *ctxlen = 0; > + return call_int_hook(object_init_security, 0, parent_ctx, parent_ctxlen, > + qstr, mode, ctx, ctxlen); > +} > + > int security_file_permission(struct file *file, int mask) > { > int ret;