Inode security label invalidation
Subsystems (5)
Andreas Gruenbacher
maintainerv4 cover Inode security label invalidation
Here is another version of the patch queue to make gfs2 and similar file systems work with SELinux.
In this version, dentry_security() helper has been renamed to backing_inode_security() to make it more obvious that it revalidates the backing inode of its dentry argument. The file_path_has_perm and file_has_perm functions no longer revalidate inode security labels; callers that may sleep can call inode_security_revalidate() themselves instead. The revalidation functions now make use of might_sleep() when appropriate so that any remaining bugs should turn up soon.
With this version of the patch queue, the SELinux test suite passes:
https://github.com/SELinuxProject/selinux-testsuite
Could you please review?
Thanks,
Andreas
Andreas Gruenbacher (7):
selinux: Remove unused variable in selinux_inode_init_security
security: Make inode argument of inode_getsecurity non-const
security: Make inode argument of inode_getsecid non-const
selinux: Add accessor functions for inode->i_security
security: Add hook to invalidate inode security labels
selinux: Revalidate invalid inode security labels
gfs2: Invalide security labels of inodes when they go invalid
fs/gfs2/glops.c | 2 + include/linux/audit.h | 8 +- include/linux/lsm_hooks.h | 10 +- include/linux/security.h | 13 ++- kernel/audit.c | 2 +- kernel/audit.h | 2 +- kernel/auditsc.c | 6 +- security/security.c | 12 ++- security/selinux/hooks.c | 197 +++++++++++++++++++++++++++----------- security/selinux/include/objsec.h | 6 ++ security/smack/smack_lsm.c | 4 +- 11 files changed, 186 insertions(+), 76 deletions(-)
Signature · 1 line
2.5.0
Andreas Gruenbacher
maintainerPATCH v4 1/7 selinux: Remove unused variable in selinux_inode_init_security
--- security/selinux/hooks.c | 2 -- 1 file changed, 2 deletions(-)
security/selinux/hooks.c +0 -2
@@ -2756,13 +2756,11 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, void **value, size_t *len) {const struct task_security_struct *tsec =current_security (); -struct inode_security_struct *dsec;struct superblock_security_struct *sbsec;u32 sid, newsid, clen;int rc;char *context; - dsec = dir->i_security; sbsec = dir->i_sb->s_security; sid = tsec->sid;
Signature · 1 line
2.5.0
Andreas Gruenbacher
maintainerPATCH v4 2/7 security: Make inode argument of inode_getsecurity non-const
In reply to Andreas GruenbacherMake the inode argument of the inode_getsecurity hook non-const so that we can use it to revalidate invalid security labels.
--- include/linux/lsm_hooks.h | 2 +- include/linux/security.h | 4 ++-- security/security.c | 2 +- security/selinux/hooks.c | 2 +- security/smack/smack_lsm.c | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-)
include/linux/lsm_hooks.h +1 -1
@@ -1413,7 +1413,7 @@ union security_list_options {int (*inode_removexattr)(struct dentry *dentry,const char *name);int (*inode_need_killpriv)(struct dentry *dentry);int (*inode_killpriv)(struct dentry *dentry); -int (*inode_getsecurity)(const struct inode *inode,const char *name, +int (*inode_getsecurity)(struct inode *inode,const char *name,void **buffer,bool alloc); int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size,
include/linux/security.h +2 -2
@@ -270,7 +270,7 @@ int security_inode_listxattr(struct dentry *dentry);int security_inode_removexattr (struct dentry *dentry,const char *name);int security_inode_need_killpriv (struct dentry *dentry);int security_inode_killpriv (struct dentry *dentry); -int security_inode_getsecurity (const struct inode *inode,const char *name,void **buffer,bool alloc); +int security_inode_getsecurity (struct inode *inode,const char *name,void **buffer,bool alloc);int security_inode_setsecurity (struct inode *inode,const char *name,const void *value,size_t size,int flags);int security_inode_listsecurity (struct inode *inode,char *buffer,size_t buffer_size);void security_inode_getsecid (const struct inode *inode,u32 *secid);
@@ -719,7 +719,7 @@ static inline int security_inode_killpriv(struct dentry *dentry)return cap_inode_killpriv (dentry); } -static inline int security_inode_getsecurity (const struct inode *inode,const char *name,void **buffer,bool alloc) +static inline int security_inode_getsecurity (struct inode *inode,const char *name,void **buffer,bool alloc) {return -EOPNOTSUPP ; }
security/security.c +1 -1
@@ -697,7 +697,7 @@ int security_inode_killpriv(struct dentry *dentry)return call_int_hook (inode_killpriv,0 , dentry); } -int security_inode_getsecurity (const struct inode *inode,const char *name,void **buffer,bool alloc) +int security_inode_getsecurity (struct inode *inode,const char *name,void **buffer,bool alloc) {if (unlikely (IS_PRIVATE (inode)))return -EOPNOTSUPP ;
security/selinux/hooks.c +1 -1
@@ -3110,7 +3110,7 @@ static int selinux_inode_removexattr(struct dentry *dentry, const char *name)* * Permission check is handled by selinux_inode_getxattr hook. */ -static int selinux_inode_getsecurity (const struct inode *inode,const char *name,void **buffer,bool alloc) +static int selinux_inode_getsecurity (struct inode *inode,const char *name,void **buffer,bool alloc) {u32 size;int error;
security/smack/smack_lsm.c +1 -1
@@ -1435,7 +1435,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)* * Returns the size of the attribute or an error code */ -static int smack_inode_getsecurity (const struct inode *inode, +static int smack_inode_getsecurity (struct inode *inode,const char *name,void **buffer,bool alloc) {
Signature · 1 line
2.5.0
Re: [PATCH v4 2/7] security: Make inode argument of inode_getsecurity non-const
Quoted 4 lines · Andreas Gruenbacher
Make the inode argument of the
inode_getsecurityhook non-const so that we can use it to revalidate invalid security labels.Signed-off-by Andreas Gruenbacher <[email protected]>
Quoted 83 lines
--- include/linux/lsm_hooks.h | 2 +- include/linux/security.h | 4 ++-- security/security.c | 2 +- security/selinux/hooks.c | 2 +- security/smack/smack_lsm.c | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-)include/linux/lsm_hooks.h +1
-1@@ -1413,7 +1413,7 @@ union security_list_options {int (*inode_removexattr)(struct dentry *dentry,const char *name);int (*inode_need_killpriv)(struct dentry *dentry);int (*inode_killpriv)(struct dentry *dentry); -int (*inode_getsecurity)(const struct inode *inode,const char *name, +int (*inode_getsecurity)(struct inode *inode,const char *name,void **buffer,bool alloc); int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size,include/linux/security.h +2
-2@@ -270,7 +270,7 @@ int security_inode_listxattr(struct dentry *dentry);int security_inode_removexattr (struct dentry *dentry,const char *name);int security_inode_need_killpriv (struct dentry *dentry);int security_inode_killpriv (struct dentry *dentry); -int security_inode_getsecurity (const struct inode *inode,const char *name,void **buffer,bool alloc); +int security_inode_getsecurity (struct inode *inode,const char *name,void **buffer,bool alloc);int security_inode_setsecurity (struct inode *inode,const char *name,const void *value,size_t size,int flags);int security_inode_listsecurity (struct inode *inode,char *buffer,size_t buffer_size);void security_inode_getsecid (const struct inode *inode,u32 *secid);@@ -719,7 +719,7 @@ static inline int security_inode_killpriv(struct dentry *dentry)return cap_inode_killpriv (dentry); } -static inline int security_inode_getsecurity (const struct inode *inode,const char *name,void **buffer,bool alloc) +static inline int security_inode_getsecurity (struct inode *inode,const char *name,void **buffer,bool alloc) {return -EOPNOTSUPP ; }security/security.c +1
-1@@ -697,7 +697,7 @@ int security_inode_killpriv(struct dentry *dentry)return call_int_hook (inode_killpriv,0 , dentry); } -int security_inode_getsecurity (const struct inode *inode,const char *name,void **buffer,bool alloc) +int security_inode_getsecurity (struct inode *inode,const char *name,void **buffer,bool alloc) {if (unlikely (IS_PRIVATE (inode)))return -EOPNOTSUPP ;security/selinux/hooks.c +1
-1@@ -3110,7 +3110,7 @@ static int selinux_inode_removexattr(struct dentry *dentry, const char *name)* * Permission check is handled by selinux_inode_getxattr hook. */ -static int selinux_inode_getsecurity (const struct inode *inode,const char *name,void **buffer,bool alloc) +static int selinux_inode_getsecurity (struct inode *inode,const char *name,void **buffer,bool alloc) {u32 size;int error;security/smack/smack_lsm.c +1
-1@@ -1435,7 +1435,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)* * Returns the size of the attribute or an error code */ -static int smack_inode_getsecurity (const struct inode *inode, +static int smack_inode_getsecurity (struct inode *inode,const char *name,void **buffer,bool alloc) {
Andreas Gruenbacher
maintainerPATCH v4 3/7 security: Make inode argument of inode_getsecid non-const
In reply to Andreas GruenbacherMake the inode argument of the inode_getsecid hook non-const so that we can use it to revalidate invalid security labels.
--- include/linux/audit.h | 8 ++++---- include/linux/lsm_hooks.h | 2 +- include/linux/security.h | 4 ++-- kernel/audit.c | 2 +- kernel/audit.h | 2 +- kernel/auditsc.c | 6 +++--- security/security.c | 2 +- security/selinux/hooks.c | 2 +- security/smack/smack_lsm.c | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-)
include/linux/audit.h +4 -4
@@ -137,7 +137,7 @@ extern void __audit_getname(struct filename *name);extern void __audit_inode (struct filename *name,const struct dentry *dentry,unsigned int flags);extern void __audit_file (const struct file *); -extern void __audit_inode_child (const struct inode *parent, +extern void __audit_inode_child (struct inode *parent,const struct dentry *dentry,const unsigned char type);extern void __audit_seccomp (unsigned long syscall,long signr,int code);
@@ -202,7 +202,7 @@ static inline void audit_inode_parent_hidden(struct filename *name,__audit_inode (name, dentry,AUDIT_INODE_PARENT |AUDIT_INODE_HIDDEN ); } -static inline void audit_inode_child (const struct inode *parent, +static inline void audit_inode_child (struct inode *parent,const struct dentry *dentry,const unsigned char type) {if (unlikely (!audit_dummy_context ()))
@@ -359,7 +359,7 @@ static inline void __audit_inode(struct filename *name, const struct dentry *dentry, unsigned int flags) { } -static inline void __audit_inode_child (const struct inode *parent, +static inline void __audit_inode_child (struct inode *parent,const struct dentry *dentry,const unsigned char type) { }
@@ -373,7 +373,7 @@ static inline void audit_file(struct file *file)static inline void audit_inode_parent_hidden (struct filename *name,const struct dentry *dentry) { } -static inline void audit_inode_child (const struct inode *parent, +static inline void audit_inode_child (struct inode *parent,const struct dentry *dentry,const unsigned char type) { }
include/linux/lsm_hooks.h +1 -1
@@ -1420,7 +1420,7 @@ union security_list_options { int flags);int (*inode_listsecurity)(struct inode *inode,char *buffer,size_t buffer_size); -void (*inode_getsecid)(const struct inode *inode,u32 *secid); +void (*inode_getsecid)(struct inode *inode,u32 *secid);int (*file_permission)(struct file *file,int mask);int (*file_alloc_security)(struct file *file);
include/linux/security.h +2 -2
@@ -273,7 +273,7 @@ int security_inode_killpriv(struct dentry *dentry);int security_inode_getsecurity (struct inode *inode,const char *name,void **buffer,bool alloc);int security_inode_setsecurity (struct inode *inode,const char *name,const void *value,size_t size,int flags);int security_inode_listsecurity (struct inode *inode,char *buffer,size_t buffer_size); -void security_inode_getsecid (const struct inode *inode,u32 *secid); +void security_inode_getsecid (struct inode *inode,u32 *secid);int security_file_permission (struct file *file,int mask);int security_file_alloc (struct file *file);void security_file_free (struct file *file);
@@ -734,7 +734,7 @@ static inline int security_inode_listsecurity(struct inode *inode, char *buffer,return 0 ; } -static inline void security_inode_getsecid (const struct inode *inode,u32 *secid) +static inline void security_inode_getsecid (struct inode *inode,u32 *secid) { *secid =0 ; }
kernel/audit.c +1 -1
@@ -1708,7 +1708,7 @@ static inline int audit_copy_fcaps(struct audit_names *name,/* Copy inode data into an audit_names. */ void audit_copy_inode (struct audit_names *name,const struct dentry *dentry, -const struct inode *inode) +struct inode *inode) { name->ino = inode->i_ino; name->dev = inode->i_sb->s_dev;
kernel/audit.h +1 -1
@@ -207,7 +207,7 @@ extern u32 audit_ever_enabled;extern void audit_copy_inode (struct audit_names *name,const struct dentry *dentry, -const struct inode *inode); +struct inode *inode);extern void audit_log_cap (struct audit_buffer *ab,char *prefix,kernel_cap_t *cap); extern void audit_log_name(struct audit_context *context,
kernel/auditsc.c +3 -3
@@ -1754,7 +1754,7 @@ void __audit_inode(struct filename *name, const struct dentry *dentry, unsigned int flags) {struct audit_context *context = current->audit_context; -const struct inode *inode =d_backing_inode (dentry); +struct inode *inode =d_backing_inode (dentry);struct audit_names *n;bool parent = flags &AUDIT_INODE_PARENT ;
@@ -1848,12 +1848,12 @@ void __audit_file(const struct file *file)* must be hooked prior, in order to capture the target inode during * unsuccessful attempts. */ -void __audit_inode_child (const struct inode *parent, +void __audit_inode_child (struct inode *parent,const struct dentry *dentry,const unsigned char type) {struct audit_context *context = current->audit_context; -const struct inode *inode =d_backing_inode (dentry); +struct inode *inode =d_backing_inode (dentry);const char *dname = dentry->d_name.name;struct audit_names *n, *found_parent =NULL , *found_child =NULL ;
security/security.c +1 -1
@@ -721,7 +721,7 @@ int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer }EXPORT_SYMBOL (security_inode_listsecurity); -void security_inode_getsecid (const struct inode *inode,u32 *secid) +void security_inode_getsecid (struct inode *inode,u32 *secid) {call_void_hook (inode_getsecid, inode, secid); }
security/selinux/hooks.c +1 -1
@@ -3182,7 +3182,7 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_treturn len; } -static void selinux_inode_getsecid (const struct inode *inode,u32 *secid) +static void selinux_inode_getsecid (struct inode *inode,u32 *secid) {struct inode_security_struct *isec = inode->i_security; *secid = isec->sid;
security/smack/smack_lsm.c +1 -1
@@ -1508,7 +1508,7 @@ static int smack_inode_listsecurity(struct inode *inode, char *buffer,* @inode: inode to extract the info from * @secid: where result will be saved */ -static void smack_inode_getsecid (const struct inode *inode,u32 *secid) +static void smack_inode_getsecid (struct inode *inode,u32 *secid) {struct inode_smack *isp = inode->i_security;
Signature · 1 line
2.5.0
Re: [PATCH v4 3/7] security: Make inode argument of inode_getsecid non-const
Quoted 4 lines · Andreas Gruenbacher
Make the inode argument of the
inode_getsecidhook non-const so that we can use it to revalidate invalid security labels.Signed-off-by Andreas Gruenbacher <[email protected]>
Quoted 181 lines
--- include/linux/audit.h | 8 ++++---- include/linux/lsm_hooks.h | 2 +- include/linux/security.h | 4 ++-- kernel/audit.c | 2 +- kernel/audit.h | 2 +- kernel/auditsc.c | 6 +++--- security/security.c | 2 +- security/selinux/hooks.c | 2 +- security/smack/smack_lsm.c | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-)include/linux/audit.h +4
-4@@ -137,7 +137,7 @@ extern void __audit_getname(struct filename *name);extern void __audit_inode (struct filename *name,const struct dentry *dentry,unsigned int flags);extern void __audit_file (const struct file *); -extern void __audit_inode_child (const struct inode *parent, +extern void __audit_inode_child (struct inode *parent,const struct dentry *dentry,const unsigned char type);extern void __audit_seccomp (unsigned long syscall,long signr,int code);@@ -202,7 +202,7 @@ static inline void audit_inode_parent_hidden(struct filename *name,__audit_inode (name, dentry,AUDIT_INODE_PARENT |AUDIT_INODE_HIDDEN ); } -static inline void audit_inode_child (const struct inode *parent, +static inline void audit_inode_child (struct inode *parent,const struct dentry *dentry,const unsigned char type) {if (unlikely (!audit_dummy_context ()))@@ -359,7 +359,7 @@ static inline void __audit_inode(struct filename *name, const struct dentry *dentry, unsigned int flags) { } -static inline void __audit_inode_child (const struct inode *parent, +static inline void __audit_inode_child (struct inode *parent,const struct dentry *dentry,const unsigned char type) { }@@ -373,7 +373,7 @@ static inline void audit_file(struct file *file)static inline void audit_inode_parent_hidden (struct filename *name,const struct dentry *dentry) { } -static inline void audit_inode_child (const struct inode *parent, +static inline void audit_inode_child (struct inode *parent,const struct dentry *dentry,const unsigned char type) { }include/linux/lsm_hooks.h +1
-1@@ -1420,7 +1420,7 @@ union security_list_options { int flags);int (*inode_listsecurity)(struct inode *inode,char *buffer,size_t buffer_size); -void (*inode_getsecid)(const struct inode *inode,u32 *secid); +void (*inode_getsecid)(struct inode *inode,u32 *secid);int (*file_permission)(struct file *file,int mask);int (*file_alloc_security)(struct file *file);include/linux/security.h +2
-2@@ -273,7 +273,7 @@ int security_inode_killpriv(struct dentry *dentry);int security_inode_getsecurity (struct inode *inode,const char *name,void **buffer,bool alloc);int security_inode_setsecurity (struct inode *inode,const char *name,const void *value,size_t size,int flags);int security_inode_listsecurity (struct inode *inode,char *buffer,size_t buffer_size); -void security_inode_getsecid (const struct inode *inode,u32 *secid); +void security_inode_getsecid (struct inode *inode,u32 *secid);int security_file_permission (struct file *file,int mask);int security_file_alloc (struct file *file);void security_file_free (struct file *file);@@ -734,7 +734,7 @@ static inline int security_inode_listsecurity(struct inode *inode, char *buffer,return 0 ; } -static inline void security_inode_getsecid (const struct inode *inode,u32 *secid) +static inline void security_inode_getsecid (struct inode *inode,u32 *secid) { *secid =0 ; }kernel/audit.c +1
-1@@ -1708,7 +1708,7 @@ static inline int audit_copy_fcaps(struct audit_names *name,/* Copy inode data into an audit_names. */ void audit_copy_inode (struct audit_names *name,const struct dentry *dentry, -const struct inode *inode) +struct inode *inode) { name->ino = inode->i_ino; name->dev = inode->i_sb->s_dev;kernel/audit.h +1
-1@@ -207,7 +207,7 @@ extern u32 audit_ever_enabled;extern void audit_copy_inode (struct audit_names *name,const struct dentry *dentry, -const struct inode *inode); +struct inode *inode);extern void audit_log_cap (struct audit_buffer *ab,char *prefix,kernel_cap_t *cap); extern void audit_log_name(struct audit_context *context,kernel/auditsc.c +3
-3@@ -1754,7 +1754,7 @@ void __audit_inode(struct filename *name, const struct dentry *dentry, unsigned int flags) {struct audit_context *context = current->audit_context; -const struct inode *inode =d_backing_inode (dentry); +struct inode *inode =d_backing_inode (dentry);struct audit_names *n;bool parent = flags &AUDIT_INODE_PARENT ;@@ -1848,12 +1848,12 @@ void __audit_file(const struct file *file)* must be hooked prior, in order to capture the target inode during * unsuccessful attempts. */ -void __audit_inode_child (const struct inode *parent, +void __audit_inode_child (struct inode *parent,const struct dentry *dentry,const unsigned char type) {struct audit_context *context = current->audit_context; -const struct inode *inode =d_backing_inode (dentry); +struct inode *inode =d_backing_inode (dentry);const char *dname = dentry->d_name.name;struct audit_names *n, *found_parent =NULL , *found_child =NULL ;security/security.c +1
-1@@ -721,7 +721,7 @@ int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer }EXPORT_SYMBOL (security_inode_listsecurity); -void security_inode_getsecid (const struct inode *inode,u32 *secid) +void security_inode_getsecid (struct inode *inode,u32 *secid) {call_void_hook (inode_getsecid, inode, secid); }security/selinux/hooks.c +1
-1@@ -3182,7 +3182,7 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_treturn len; } -static void selinux_inode_getsecid (const struct inode *inode,u32 *secid) +static void selinux_inode_getsecid (struct inode *inode,u32 *secid) {struct inode_security_struct *isec = inode->i_security; *secid = isec->sid;security/smack/smack_lsm.c +1
-1@@ -1508,7 +1508,7 @@ static int smack_inode_listsecurity(struct inode *inode, char *buffer,* @inode: inode to extract the info from * @secid: where result will be saved */ -static void smack_inode_getsecid (const struct inode *inode,u32 *secid) +static void smack_inode_getsecid (struct inode *inode,u32 *secid) {struct inode_smack *isp = inode->i_security;
Andreas Gruenbacher
maintainerPATCH v4 4/7 selinux: Add accessor functions for inode->i_security
In reply to Andreas GruenbacherAdd functions dentry_security and inode_security for accessing inode->i_security. These functions initially don't do much, but they will later be used to revalidate the security labels when necessary.
--- security/selinux/hooks.c | 97 ++++++++++++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 41 deletions(-)
security/selinux/hooks.c +56 -41
@@ -241,6 +241,24 @@ static int inode_alloc_security(struct inode *inode)return 0 ; } +/* +* Get the security label of an inode. +*/ +static struct inode_security_struct *inode_security (struct inode *inode) +{ +return inode->i_security; +} + +/* +* Get the security label of a dentry's backing inode. +*/ +static struct inode_security_struct *backing_inode_security (struct dentry *dentry) +{ +struct inode *inode =d_backing_inode (dentry); + +return inode->i_security; +} +static void inode_free_rcu (struct rcu_head *head) {struct inode_security_struct *isec;
@@ -564,8 +582,8 @@ static int selinux_get_mnt_opts(const struct super_block *sb, opts->mnt_opts_flags[i++] =DEFCONTEXT_MNT ; }if (sbsec->flags &ROOTCONTEXT_MNT ) { -struct inode *root =d_backing_inode (sbsec->sb->s_root); -struct inode_security_struct *isec = root->i_security; +struct dentry *root = sbsec->sb->s_root; +struct inode_security_struct *isec =backing_inode_security (root); rc =security_sid_to_context (isec->sid, &context, &len);if (rc)
@@ -620,8 +638,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,int rc =0 , i;struct superblock_security_struct *sbsec = sb->s_security;const char *name = sb->s_type->name; -struct inode *inode =d_backing_inode (sbsec->sb->s_root); -struct inode_security_struct *root_isec = inode->i_security; +struct dentry *root = sbsec->sb->s_root; +struct inode_security_struct *root_isec =backing_inode_security (root);u32 fscontext_sid =0 , context_sid =0 , rootcontext_sid =0 ;u32 defcontext_sid =0 ;char **mount_options = opts->mnt_opts;
@@ -852,8 +870,8 @@ static int selinux_cmp_sb_context(const struct super_block *oldsb,if ((oldflags &DEFCONTEXT_MNT ) && old->def_sid != new->def_sid) goto mismatch;if (oldflags &ROOTCONTEXT_MNT ) { -struct inode_security_struct *oldroot =d_backing_inode (oldsb->s_root)->i_security; -struct inode_security_struct *newroot =d_backing_inode (newsb->s_root)->i_security; +struct inode_security_struct *oldroot =backing_inode_security (oldsb->s_root); +struct inode_security_struct *newroot =backing_inode_security (newsb->s_root);if (oldroot->sid != newroot->sid) goto mismatch; }
@@ -903,17 +921,14 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,if (!set_fscontext) newsbsec->sid = sid;if (!set_rootcontext) { -struct inode *newinode =d_backing_inode (newsb->s_root); -struct inode_security_struct *newisec = newinode->i_security; +struct inode_security_struct *newisec =backing_inode_security (newsb->s_root); newisec->sid = sid; } newsbsec->mntpoint_sid = sid; }if (set_rootcontext) { -const struct inode *oldinode =d_backing_inode (oldsb->s_root); -const struct inode_security_struct *oldisec = oldinode->i_security; -struct inode *newinode =d_backing_inode (newsb->s_root); -struct inode_security_struct *newisec = newinode->i_security; +const struct inode_security_struct *oldisec =backing_inode_security (oldsb->s_root); +struct inode_security_struct *newisec =backing_inode_security (newsb->s_root); newisec->sid = oldisec->sid; }
@@ -1712,13 +1727,13 @@ out:/* * Determine the label for an inode that might be unioned. */ -static int selinux_determine_inode_label (const struct inode *dir, +static int selinux_determine_inode_label (struct inode *dir,const struct qstr *name,u16 tclass,u32 *_new_isid) {const struct superblock_security_struct *sbsec = dir->i_sb->s_security; -const struct inode_security_struct *dsec = dir->i_security; +const struct inode_security_struct *dsec =inode_security (dir);const struct task_security_struct *tsec =current_security (); if ((sbsec->flags & SE_SBINITIALIZED) &&
@@ -1747,7 +1762,7 @@ static int may_create(struct inode *dir,struct common_audit_data ad;int rc; - dsec = dir->i_security; + dsec =inode_security (dir); sbsec = dir->i_sb->s_security; sid = tsec->sid;
@@ -1800,8 +1815,8 @@ static int may_link(struct inode *dir,u32 av;int rc; - dsec = dir->i_security; - isec =d_backing_inode (dentry)->i_security; + dsec =inode_security (dir); + isec =backing_inode_security (dentry); ad.type =LSM_AUDIT_DATA_DENTRY ; ad.u.dentry = dentry;
@@ -1844,10 +1859,10 @@ static inline int may_rename(struct inode *old_dir,int old_is_dir, new_is_dir;int rc; - old_dsec = old_dir->i_security; - old_isec =d_backing_inode (old_dentry)->i_security; + old_dsec =inode_security (old_dir); + old_isec =backing_inode_security (old_dentry); old_is_dir =d_is_dir (old_dentry); - new_dsec = new_dir->i_security; + new_dsec =inode_security (new_dir); ad.type =LSM_AUDIT_DATA_DENTRY ;
@@ -1875,7 +1890,7 @@ static inline int may_rename(struct inode *old_dir,if (rc)return rc;if (d_is_positive (new_dentry)) { - new_isec =d_backing_inode (new_dentry)->i_security; + new_isec =backing_inode_security (new_dentry); new_is_dir =d_is_dir (new_dentry); rc = avc_has_perm(sid, new_isec->sid, new_isec->sclass,
@@ -2011,8 +2026,8 @@ static int selinux_binder_transfer_file(struct task_struct *from, {u32 sid =task_sid (to);struct file_security_struct *fsec = file->f_security; -struct inode *inode =d_backing_inode (file->f_path.dentry); -struct inode_security_struct *isec = inode->i_security; +struct dentry *dentry = file->f_path.dentry; +struct inode_security_struct *isec =backing_inode_security (dentry);struct common_audit_data ad;int rc;
@@ -2028,7 +2043,7 @@ static int selinux_binder_transfer_file(struct task_struct *from,return rc; } -if (unlikely (IS_PRIVATE (inode))) +if (unlikely (IS_PRIVATE (d_backing_inode (dentry))))return 0 ; return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file),
@@ -2217,7 +2232,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) old_tsec =current_security (); new_tsec = bprm->cred->security; - isec = inode->i_security; + isec =inode_security (inode);/* Default to the current task SID. */ new_tsec->sid = old_tsec->sid;
@@ -2642,7 +2657,7 @@ static int selinux_sb_remount(struct super_block *sb, void *data)break ;case ROOTCONTEXT_MNT : {struct inode_security_struct *root_isec; - root_isec =d_backing_inode (sb->s_root)->i_security; + root_isec =backing_inode_security (sb->s_root);if (bad_option (sbsec,ROOTCONTEXT_MNT , root_isec->sid, sid)) goto out_bad_option;
@@ -2859,7 +2874,7 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode, ad.type =LSM_AUDIT_DATA_DENTRY ; ad.u.dentry = dentry; sid =cred_sid (cred); - isec = inode->i_security; + isec =inode_security (inode);return avc_has_perm_flags (sid, isec->sid, isec->sclass,FILE__READ , &ad, rcu ?MAY_NOT_BLOCK :0 );
@@ -2911,7 +2926,7 @@ static int selinux_inode_permission(struct inode *inode, int mask) perms =file_mask_to_av (inode->i_mode, mask); sid =cred_sid (cred); - isec = inode->i_security; + isec =inode_security (inode); rc =avc_has_perm_noaudit (sid, isec->sid, isec->sclass, perms,0 , &avd); audited = avc_audit_required(perms, &avd, rc,
@@ -2980,7 +2995,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { struct inode *inode = d_backing_inode(dentry); -struct inode_security_struct *isec = inode->i_security; +struct inode_security_struct *isec =backing_inode_security (dentry);struct superblock_security_struct *sbsec;struct common_audit_data ad;u32 newsid, sid =current_sid ();
@@ -3057,7 +3072,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, int flags) {struct inode *inode =d_backing_inode (dentry); -struct inode_security_struct *isec = inode->i_security; +struct inode_security_struct *isec =backing_inode_security (dentry);u32 newsid;int rc;
@@ -3115,7 +3130,7 @@ static int selinux_inode_getsecurity(struct inode *inode, const char *name, voidu32 size;int error;char *context =NULL ; -struct inode_security_struct *isec = inode->i_security; +struct inode_security_struct *isec =inode_security (inode);if (strcmp (name,XATTR_SELINUX_SUFFIX ))return -EOPNOTSUPP ;
@@ -3154,7 +3169,7 @@ out_nofree:static int selinux_inode_setsecurity (struct inode *inode,const char *name,const void *value,size_t size,int flags) { -struct inode_security_struct *isec = inode->i_security; +struct inode_security_struct *isec =inode_security (inode);u32 newsid;int rc;
@@ -3184,7 +3199,7 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_tstatic void selinux_inode_getsecid (struct inode *inode,u32 *secid) { -struct inode_security_struct *isec = inode->i_security; +struct inode_security_struct *isec =inode_security (inode); *secid = isec->sid; }
@@ -3207,7 +3222,7 @@ static int selinux_file_permission(struct file *file, int mask) {struct inode *inode =file_inode (file);struct file_security_struct *fsec = file->f_security; -struct inode_security_struct *isec = inode->i_security; +struct inode_security_struct *isec =inode_security (inode);u32 sid =current_sid ();if (!mask)
@@ -3242,7 +3257,7 @@ int ioctl_has_perm(const struct cred *cred, struct file *file,struct common_audit_data ad;struct file_security_struct *fsec = file->f_security;struct inode *inode =file_inode (file); -struct inode_security_struct *isec = inode->i_security; +struct inode_security_struct *isec =inode_security (inode);struct lsm_ioctlop_audit ioctl;u32 ssid =cred_sid (cred);int rc;
@@ -3506,7 +3521,7 @@ static int selinux_file_open(struct file *file, const struct cred *cred)struct inode_security_struct *isec; fsec = file->f_security; - isec =file_inode (file)->i_security; + isec =inode_security (file_inode (file));/* * Save inode label and policy sequence number * at open-time so that selinux_file_permission
@@ -3624,7 +3639,7 @@ static int selinux_kernel_act_as(struct cred *new, u32 secid)*/ static int selinux_kernel_create_files_as (struct cred *new,struct inode *inode) { -struct inode_security_struct *isec = inode->i_security; +struct inode_security_struct *isec =inode_security (inode);struct task_security_struct *tsec = new->security;u32 sid =current_sid ();int ret;
@@ -4065,7 +4080,7 @@ static int selinux_socket_post_create(struct socket *sock, int family, int type, int protocol, int kern) { const struct task_security_struct *tsec = current_security(); -struct inode_security_struct *isec =SOCK_INODE (sock)->i_security; +struct inode_security_struct *isec =inode_security (SOCK_INODE (sock));struct sk_security_struct *sksec;int err =0 ;
@@ -4265,9 +4280,9 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)if (err)return err; - newisec =SOCK_INODE (newsock)->i_security; + newisec =inode_security (SOCK_INODE (newsock)); - isec =SOCK_INODE (sock)->i_security; + isec =inode_security (SOCK_INODE (sock)); newisec->sclass = isec->sclass; newisec->sid = isec->sid; newisec->initialized =1 ;
@@ -4605,7 +4620,7 @@ static void selinux_sk_getsecid(struct sock *sk, u32 *secid)static void selinux_sock_graft (struct sock *sk,struct socket *parent) { -struct inode_security_struct *isec =SOCK_INODE (parent)->i_security; +struct inode_security_struct *isec =inode_security (SOCK_INODE (parent));struct sk_security_struct *sksec = sk->sk_security; if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
Signature · 1 line
2.5.0
Re: [PATCH v4 4/7] selinux: Add accessor functions for inode->i_security
Quoted 5 lines · Andreas Gruenbacher
Add functions
dentry_securityandinode_securityfor accessinginode->i_security. These functions initially don't do much, but they will later be used to revalidate the security labels when necessary.Signed-off-by Andreas Gruenbacher <[email protected]>
Quoted 314 lines
--- security/selinux/hooks.c | 97 ++++++++++++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 41 deletions(-)security/selinux/hooks.c +56
-41@@ -241,6 +241,24 @@ static int inode_alloc_security(struct inode *inode)return 0 ; } +/* +* Get the security label of an inode. +*/ +static struct inode_security_struct *inode_security (struct inode *inode) +{ +return inode->i_security; +} + +/* +* Get the security label of a dentry's backing inode. +*/ +static struct inode_security_struct *backing_inode_security (struct dentry *dentry) +{ +struct inode *inode =d_backing_inode (dentry); + +return inode->i_security; +} +static void inode_free_rcu (struct rcu_head *head) {struct inode_security_struct *isec;@@ -564,8 +582,8 @@ static int selinux_get_mnt_opts(const struct super_block *sb, opts->mnt_opts_flags[i++] =DEFCONTEXT_MNT ; }if (sbsec->flags &ROOTCONTEXT_MNT ) { -struct inode *root =d_backing_inode (sbsec->sb->s_root); -struct inode_security_struct *isec = root->i_security; +struct dentry *root = sbsec->sb->s_root; +struct inode_security_struct *isec =backing_inode_security (root); rc =security_sid_to_context (isec->sid, &context, &len);if (rc)@@ -620,8 +638,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,int rc =0 , i;struct superblock_security_struct *sbsec = sb->s_security;const char *name = sb->s_type->name; -struct inode *inode =d_backing_inode (sbsec->sb->s_root); -struct inode_security_struct *root_isec = inode->i_security; +struct dentry *root = sbsec->sb->s_root; +struct inode_security_struct *root_isec =backing_inode_security (root);u32 fscontext_sid =0 , context_sid =0 , rootcontext_sid =0 ;u32 defcontext_sid =0 ;char **mount_options = opts->mnt_opts;@@ -852,8 +870,8 @@ static int selinux_cmp_sb_context(const struct super_block *oldsb,if ((oldflags &DEFCONTEXT_MNT ) && old->def_sid != new->def_sid) goto mismatch;if (oldflags &ROOTCONTEXT_MNT ) { -struct inode_security_struct *oldroot =d_backing_inode (oldsb->s_root)->i_security; -struct inode_security_struct *newroot =d_backing_inode (newsb->s_root)->i_security; +struct inode_security_struct *oldroot =backing_inode_security (oldsb->s_root); +struct inode_security_struct *newroot =backing_inode_security (newsb->s_root);if (oldroot->sid != newroot->sid) goto mismatch; }@@ -903,17 +921,14 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,if (!set_fscontext) newsbsec->sid = sid;if (!set_rootcontext) { -struct inode *newinode =d_backing_inode (newsb->s_root); -struct inode_security_struct *newisec = newinode->i_security; +struct inode_security_struct *newisec =backing_inode_security (newsb->s_root); newisec->sid = sid; } newsbsec->mntpoint_sid = sid; }if (set_rootcontext) { -const struct inode *oldinode =d_backing_inode (oldsb->s_root); -const struct inode_security_struct *oldisec = oldinode->i_security; -struct inode *newinode =d_backing_inode (newsb->s_root); -struct inode_security_struct *newisec = newinode->i_security; +const struct inode_security_struct *oldisec =backing_inode_security (oldsb->s_root); +struct inode_security_struct *newisec =backing_inode_security (newsb->s_root); newisec->sid = oldisec->sid; }@@ -1712,13 +1727,13 @@ out:/* * Determine the label for an inode that might be unioned. */ -static int selinux_determine_inode_label (const struct inode *dir, +static int selinux_determine_inode_label (struct inode *dir,const struct qstr *name,u16 tclass,u32 *_new_isid) {const struct superblock_security_struct *sbsec = dir->i_sb->s_security; -const struct inode_security_struct *dsec = dir->i_security; +const struct inode_security_struct *dsec =inode_security (dir);const struct task_security_struct *tsec =current_security (); if ((sbsec->flags & SE_SBINITIALIZED) &&@@ -1747,7 +1762,7 @@ static int may_create(struct inode *dir,struct common_audit_data ad;int rc; - dsec = dir->i_security; + dsec =inode_security (dir); sbsec = dir->i_sb->s_security; sid = tsec->sid;@@ -1800,8 +1815,8 @@ static int may_link(struct inode *dir,u32 av;int rc; - dsec = dir->i_security; - isec =d_backing_inode (dentry)->i_security; + dsec =inode_security (dir); + isec =backing_inode_security (dentry); ad.type =LSM_AUDIT_DATA_DENTRY ; ad.u.dentry = dentry;@@ -1844,10 +1859,10 @@ static inline int may_rename(struct inode *old_dir,int old_is_dir, new_is_dir;int rc; - old_dsec = old_dir->i_security; - old_isec =d_backing_inode (old_dentry)->i_security; + old_dsec =inode_security (old_dir); + old_isec =backing_inode_security (old_dentry); old_is_dir =d_is_dir (old_dentry); - new_dsec = new_dir->i_security; + new_dsec =inode_security (new_dir); ad.type =LSM_AUDIT_DATA_DENTRY ;@@ -1875,7 +1890,7 @@ static inline int may_rename(struct inode *old_dir,if (rc)return rc;if (d_is_positive (new_dentry)) { - new_isec =d_backing_inode (new_dentry)->i_security; + new_isec =backing_inode_security (new_dentry); new_is_dir =d_is_dir (new_dentry); rc = avc_has_perm(sid, new_isec->sid, new_isec->sclass,@@ -2011,8 +2026,8 @@ static int selinux_binder_transfer_file(struct task_struct *from, {u32 sid =task_sid (to);struct file_security_struct *fsec = file->f_security; -struct inode *inode =d_backing_inode (file->f_path.dentry); -struct inode_security_struct *isec = inode->i_security; +struct dentry *dentry = file->f_path.dentry; +struct inode_security_struct *isec =backing_inode_security (dentry);struct common_audit_data ad;int rc;@@ -2028,7 +2043,7 @@ static int selinux_binder_transfer_file(struct task_struct *from,return rc; } -if (unlikely (IS_PRIVATE (inode))) +if (unlikely (IS_PRIVATE (d_backing_inode (dentry))))return 0 ; return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file),@@ -2217,7 +2232,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) old_tsec =current_security (); new_tsec = bprm->cred->security; - isec = inode->i_security; + isec =inode_security (inode);/* Default to the current task SID. */ new_tsec->sid = old_tsec->sid;@@ -2642,7 +2657,7 @@ static int selinux_sb_remount(struct super_block *sb, void *data)break ;case ROOTCONTEXT_MNT : {struct inode_security_struct *root_isec; - root_isec =d_backing_inode (sb->s_root)->i_security; + root_isec =backing_inode_security (sb->s_root);if (bad_option (sbsec,ROOTCONTEXT_MNT , root_isec->sid, sid)) goto out_bad_option;@@ -2859,7 +2874,7 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode, ad.type =LSM_AUDIT_DATA_DENTRY ; ad.u.dentry = dentry; sid =cred_sid (cred); - isec = inode->i_security; + isec =inode_security (inode);return avc_has_perm_flags (sid, isec->sid, isec->sclass,FILE__READ , &ad, rcu ?MAY_NOT_BLOCK :0 );@@ -2911,7 +2926,7 @@ static int selinux_inode_permission(struct inode *inode, int mask) perms =file_mask_to_av (inode->i_mode, mask); sid =cred_sid (cred); - isec = inode->i_security; + isec =inode_security (inode); rc =avc_has_perm_noaudit (sid, isec->sid, isec->sclass, perms,0 , &avd); audited = avc_audit_required(perms, &avd, rc,@@ -2980,7 +2995,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { struct inode *inode = d_backing_inode(dentry); -struct inode_security_struct *isec = inode->i_security; +struct inode_security_struct *isec =backing_inode_security (dentry);struct superblock_security_struct *sbsec;struct common_audit_data ad;u32 newsid, sid =current_sid ();@@ -3057,7 +3072,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, int flags) {struct inode *inode =d_backing_inode (dentry); -struct inode_security_struct *isec = inode->i_security; +struct inode_security_struct *isec =backing_inode_security (dentry);u32 newsid;int rc;@@ -3115,7 +3130,7 @@ static int selinux_inode_getsecurity(struct inode *inode, const char *name, voidu32 size;int error;char *context =NULL ; -struct inode_security_struct *isec = inode->i_security; +struct inode_security_struct *isec =inode_security (inode);if (strcmp (name,XATTR_SELINUX_SUFFIX ))return -EOPNOTSUPP ;@@ -3154,7 +3169,7 @@ out_nofree:static int selinux_inode_setsecurity (struct inode *inode,const char *name,const void *value,size_t size,int flags) { -struct inode_security_struct *isec = inode->i_security; +struct inode_security_struct *isec =inode_security (inode);u32 newsid;int rc;@@ -3184,7 +3199,7 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_tstatic void selinux_inode_getsecid (struct inode *inode,u32 *secid) { -struct inode_security_struct *isec = inode->i_security; +struct inode_security_struct *isec =inode_security (inode); *secid = isec->sid; }@@ -3207,7 +3222,7 @@ static int selinux_file_permission(struct file *file, int mask) {struct inode *inode =file_inode (file);struct file_security_struct *fsec = file->f_security; -struct inode_security_struct *isec = inode->i_security; +struct inode_security_struct *isec =inode_security (inode);u32 sid =current_sid ();if (!mask)@@ -3242,7 +3257,7 @@ int ioctl_has_perm(const struct cred *cred, struct file *file,struct common_audit_data ad;struct file_security_struct *fsec = file->f_security;struct inode *inode =file_inode (file); -struct inode_security_struct *isec = inode->i_security; +struct inode_security_struct *isec =inode_security (inode);struct lsm_ioctlop_audit ioctl;u32 ssid =cred_sid (cred);int rc;@@ -3506,7 +3521,7 @@ static int selinux_file_open(struct file *file, const struct cred *cred)struct inode_security_struct *isec; fsec = file->f_security; - isec =file_inode (file)->i_security; + isec =inode_security (file_inode (file));/* * Save inode label and policy sequence number * at open-time so that selinux_file_permission @@ -3624,7 +3639,7 @@ static int selinux_kernel_act_as(struct cred *new, u32 secid)*/ static int selinux_kernel_create_files_as (struct cred *new,struct inode *inode) { -struct inode_security_struct *isec = inode->i_security; +struct inode_security_struct *isec =inode_security (inode);struct task_security_struct *tsec = new->security;u32 sid =current_sid ();int ret;@@ -4065,7 +4080,7 @@ static int selinux_socket_post_create(struct socket *sock, int family, int type, int protocol, int kern) { const struct task_security_struct *tsec = current_security(); -struct inode_security_struct *isec =SOCK_INODE (sock)->i_security; +struct inode_security_struct *isec =inode_security (SOCK_INODE (sock));struct sk_security_struct *sksec;int err =0 ;@@ -4265,9 +4280,9 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)if (err)return err; - newisec =SOCK_INODE (newsock)->i_security; + newisec =inode_security (SOCK_INODE (newsock)); - isec =SOCK_INODE (sock)->i_security; + isec =inode_security (SOCK_INODE (sock)); newisec->sclass = isec->sclass; newisec->sid = isec->sid; newisec->initialized =1 ;@@ -4605,7 +4620,7 @@ static void selinux_sk_getsecid(struct sock *sk, u32 *secid)static void selinux_sock_graft (struct sock *sk,struct socket *parent) { -struct inode_security_struct *isec =SOCK_INODE (parent)->i_security; +struct inode_security_struct *isec =inode_security (SOCK_INODE (parent));struct sk_security_struct *sksec = sk->sk_security; if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
Andreas Gruenbacher
maintainerPATCH v4 5/7 security: Add hook to invalidate inode security labels
In reply to Andreas GruenbacherAdd a hook to invalidate an inode's security label when the cached information becomes invalid.
Add the new hook in selinux: set a flag when a security label becomes invalid.
--- include/linux/lsm_hooks.h | 6 ++++++ include/linux/security.h | 5 +++++ security/security.c | 8 ++++++++ security/selinux/hooks.c | 30 ++++++++++++++++++++---------- security/selinux/include/objsec.h | 6 ++++++ 5 files changed, 45 insertions(+), 10 deletions(-)
include/linux/lsm_hooks.h +6 -0
@@ -1261,6 +1261,10 @@* audit_rule_init. * @rule contains the allocated rule * +* @inode_invalidate_secctx: +* Notify the security module that it must revalidate the security context +* of an inode. +* * @inode_notifysecctx: * Notify the security module of what the security context of an inode * should be. Initializes the incore security context managed by the
@@ -1516,6 +1520,7 @@ union security_list_options {int (*secctx_to_secid)(const char *secdata,u32 seclen,u32 *secid);void (*release_secctx)(char *secdata,u32 seclen); +void (*inode_invalidate_secctx)(struct inode *inode);int (*inode_notifysecctx)(struct inode *inode,void *ctx,u32 ctxlen);int (*inode_setsecctx)(struct dentry *dentry,void *ctx,u32 ctxlen);int (*inode_getsecctx)(struct inode *inode,void **ctx,u32 *ctxlen);
@@ -1757,6 +1762,7 @@ struct security_hook_heads {struct list_head secid_to_secctx;struct list_head secctx_to_secid;struct list_head release_secctx; +struct list_head inode_invalidate_secctx;struct list_head inode_notifysecctx;struct list_head inode_setsecctx;struct list_head inode_getsecctx;
include/linux/security.h +5 -0
@@ -353,6 +353,7 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);int security_secctx_to_secid (const char *secdata,u32 seclen,u32 *secid);void security_release_secctx (char *secdata,u32 seclen); +void security_inode_invalidate_secctx (struct inode *inode);int security_inode_notifysecctx (struct inode *inode,void *ctx,u32 ctxlen);int security_inode_setsecctx (struct dentry *dentry,void *ctx,u32 ctxlen);int security_inode_getsecctx (struct inode *inode,void **ctx,u32 *ctxlen);
@@ -1093,6 +1094,10 @@ static inline void security_release_secctx(char *secdata, u32 seclen) { } +static inline void security_inode_invalidate_secctx (struct inode *inode) +{ +} +static inline int security_inode_notifysecctx (struct inode *inode,void *ctx,u32 ctxlen) {return -EOPNOTSUPP ;
security/security.c +8 -0
@@ -1161,6 +1161,12 @@ void security_release_secctx(char *secdata, u32 seclen) }EXPORT_SYMBOL (security_release_secctx); +void security_inode_invalidate_secctx (struct inode *inode) +{ +call_void_hook (inode_invalidate_secctx, inode); +} +EXPORT_SYMBOL (security_inode_invalidate_secctx); +int security_inode_notifysecctx (struct inode *inode,void *ctx,u32 ctxlen) {return call_int_hook (inode_notifysecctx,0 , inode, ctx, ctxlen);
@@ -1763,6 +1769,8 @@ struct security_hook_heads security_hook_heads = { LIST_HEAD_INIT(security_hook_heads.secctx_to_secid), .release_secctx = LIST_HEAD_INIT(security_hook_heads.release_secctx), + .inode_invalidate_secctx = + LIST_HEAD_INIT(security_hook_heads.inode_invalidate_secctx), .inode_notifysecctx = LIST_HEAD_INIT(security_hook_heads.inode_notifysecctx), .inode_setsecctx =
security/selinux/hooks.c +20 -10
@@ -820,7 +820,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, goto out; root_isec->sid = rootcontext_sid; - root_isec->initialized =1 ; + root_isec->initialized =LABEL_INITIALIZED ; }if (defcontext_sid) {
@@ -1308,11 +1308,11 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentunsigned len =0 ;int rc =0 ; -if (isec->initialized) +if (isec->initialized ==LABEL_INITIALIZED ) goto out;mutex_lock (&isec->lock); -if (isec->initialized) +if (isec->initialized ==LABEL_INITIALIZED ) goto out_unlock; sbsec = inode->i_sb->s_security;
@@ -1484,7 +1484,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentbreak ; } - isec->initialized =1 ; + isec->initialized =LABEL_INITIALIZED ; out_unlock:mutex_unlock (&isec->lock);
@@ -2793,7 +2793,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,struct inode_security_struct *isec = inode->i_security; isec->sclass =inode_mode_to_security_class (inode->i_mode); isec->sid = newsid; - isec->initialized =1 ; + isec->initialized =LABEL_INITIALIZED ; }if (!ss_initialized || !(sbsec->flags &SBLABEL_MNT ))
@@ -3091,7 +3091,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, isec->sclass =inode_mode_to_security_class (inode->i_mode); isec->sid = newsid; - isec->initialized =1 ; + isec->initialized =LABEL_INITIALIZED ;return ; }
@@ -3185,7 +3185,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name, isec->sclass =inode_mode_to_security_class (inode->i_mode); isec->sid = newsid; - isec->initialized =1 ; + isec->initialized =LABEL_INITIALIZED ;return 0 ; }
@@ -3763,7 +3763,7 @@ static void selinux_task_to_inode(struct task_struct *p,u32 sid =task_sid (p); isec->sid = sid; - isec->initialized =1 ; + isec->initialized =LABEL_INITIALIZED ; }/* Returns error only if unable to parse addresses */
@@ -4094,7 +4094,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,return err; } - isec->initialized =1 ; + isec->initialized =LABEL_INITIALIZED ;if (sock->sk) { sksec = sock->sk->sk_security;
@@ -4285,7 +4285,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock) isec =inode_security (SOCK_INODE (sock)); newisec->sclass = isec->sclass; newisec->sid = isec->sid; - newisec->initialized =1 ; + newisec->initialized =LABEL_INITIALIZED ;return 0 ; }
@@ -5775,6 +5775,15 @@ static void selinux_release_secctx(char *secdata, u32 seclen)kfree (secdata); } +static void selinux_inode_invalidate_secctx (struct inode *inode) +{ +struct inode_security_struct *isec = inode->i_security; + +mutex_lock (&isec->lock); + isec->initialized =LABEL_INVALID ; +mutex_unlock (&isec->lock); +} +/* * called with inode->i_mutex locked */
@@ -6006,6 +6015,7 @@ static struct security_hook_list selinux_hooks[] = {LSM_HOOK_INIT (secid_to_secctx, selinux_secid_to_secctx),LSM_HOOK_INIT (secctx_to_secid, selinux_secctx_to_secid),LSM_HOOK_INIT (release_secctx, selinux_release_secctx), +LSM_HOOK_INIT (inode_invalidate_secctx, selinux_inode_invalidate_secctx),LSM_HOOK_INIT (inode_notifysecctx, selinux_inode_notifysecctx),LSM_HOOK_INIT (inode_setsecctx, selinux_inode_setsecctx), LSM_HOOK_INIT(inode_getsecctx, selinux_inode_getsecctx),
security/selinux/include/objsec.h +6 -0
@@ -37,6 +37,12 @@ struct task_security_struct {u32 sockcreate_sid;/* fscreate SID */ }; +enum label_initialized { +LABEL_MISSING ,/* not initialized */ +LABEL_INITIALIZED ,/* inizialized */ +LABEL_INVALID /* invalid */ +}; +struct inode_security_struct {struct inode *inode;/* back pointer to inode object */ union {
Signature · 1 line
2.5.0
Re: [PATCH v4 5/7] security: Add hook to invalidate inode security labels
Quoted 8 lines · Andreas Gruenbacher
Add a hook to invalidate an inode's security label when the cached information becomes invalid.
Add the new hook in selinux: set a flag when a security label becomes invalid.
Signed-off-by Andreas Gruenbacher <[email protected]>Reviewed-by James Morris <[email protected]>
Quoted 220 lines
--- include/linux/lsm_hooks.h | 6 ++++++ include/linux/security.h | 5 +++++ security/security.c | 8 ++++++++ security/selinux/hooks.c | 30 ++++++++++++++++++++---------- security/selinux/include/objsec.h | 6 ++++++ 5 files changed, 45 insertions(+), 10 deletions(-)include/linux/lsm_hooks.h +6
-0@@ -1261,6 +1261,10 @@* audit_rule_init. * @rule contains the allocated rule * +* @inode_invalidate_secctx: +* Notify the security module that it must revalidate the security context +* of an inode. +* * @inode_notifysecctx: * Notify the security module of what the security context of an inode * should be. Initializes the incore security context managed by the @@ -1516,6 +1520,7 @@ union security_list_options {int (*secctx_to_secid)(const char *secdata,u32 seclen,u32 *secid);void (*release_secctx)(char *secdata,u32 seclen); +void (*inode_invalidate_secctx)(struct inode *inode);int (*inode_notifysecctx)(struct inode *inode,void *ctx,u32 ctxlen);int (*inode_setsecctx)(struct dentry *dentry,void *ctx,u32 ctxlen);int (*inode_getsecctx)(struct inode *inode,void **ctx,u32 *ctxlen);@@ -1757,6 +1762,7 @@ struct security_hook_heads {struct list_head secid_to_secctx;struct list_head secctx_to_secid;struct list_head release_secctx; +struct list_head inode_invalidate_secctx;struct list_head inode_notifysecctx;struct list_head inode_setsecctx;struct list_head inode_getsecctx;include/linux/security.h +5
-0@@ -353,6 +353,7 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);int security_secctx_to_secid (const char *secdata,u32 seclen,u32 *secid);void security_release_secctx (char *secdata,u32 seclen); +void security_inode_invalidate_secctx (struct inode *inode);int security_inode_notifysecctx (struct inode *inode,void *ctx,u32 ctxlen);int security_inode_setsecctx (struct dentry *dentry,void *ctx,u32 ctxlen);int security_inode_getsecctx (struct inode *inode,void **ctx,u32 *ctxlen);@@ -1093,6 +1094,10 @@ static inline void security_release_secctx(char *secdata, u32 seclen) { } +static inline void security_inode_invalidate_secctx (struct inode *inode) +{ +} +static inline int security_inode_notifysecctx (struct inode *inode,void *ctx,u32 ctxlen) {return -EOPNOTSUPP ;security/security.c +8
-0@@ -1161,6 +1161,12 @@ void security_release_secctx(char *secdata, u32 seclen) }EXPORT_SYMBOL (security_release_secctx); +void security_inode_invalidate_secctx (struct inode *inode) +{ +call_void_hook (inode_invalidate_secctx, inode); +} +EXPORT_SYMBOL (security_inode_invalidate_secctx); +int security_inode_notifysecctx (struct inode *inode,void *ctx,u32 ctxlen) {return call_int_hook (inode_notifysecctx,0 , inode, ctx, ctxlen);@@ -1763,6 +1769,8 @@ struct security_hook_heads security_hook_heads = { LIST_HEAD_INIT(security_hook_heads.secctx_to_secid), .release_secctx = LIST_HEAD_INIT(security_hook_heads.release_secctx), + .inode_invalidate_secctx = + LIST_HEAD_INIT(security_hook_heads.inode_invalidate_secctx), .inode_notifysecctx = LIST_HEAD_INIT(security_hook_heads.inode_notifysecctx), .inode_setsecctx =security/selinux/hooks.c +20
-10@@ -820,7 +820,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, goto out; root_isec->sid = rootcontext_sid; - root_isec->initialized =1 ; + root_isec->initialized =LABEL_INITIALIZED ; }if (defcontext_sid) {@@ -1308,11 +1308,11 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentunsigned len =0 ;int rc =0 ; -if (isec->initialized) +if (isec->initialized ==LABEL_INITIALIZED ) goto out;mutex_lock (&isec->lock); -if (isec->initialized) +if (isec->initialized ==LABEL_INITIALIZED ) goto out_unlock; sbsec = inode->i_sb->s_security;@@ -1484,7 +1484,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentbreak ; } - isec->initialized =1 ; + isec->initialized =LABEL_INITIALIZED ; out_unlock:mutex_unlock (&isec->lock);@@ -2793,7 +2793,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,struct inode_security_struct *isec = inode->i_security; isec->sclass =inode_mode_to_security_class (inode->i_mode); isec->sid = newsid; - isec->initialized =1 ; + isec->initialized =LABEL_INITIALIZED ; }if (!ss_initialized || !(sbsec->flags &SBLABEL_MNT ))@@ -3091,7 +3091,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, isec->sclass =inode_mode_to_security_class (inode->i_mode); isec->sid = newsid; - isec->initialized =1 ; + isec->initialized =LABEL_INITIALIZED ;return ; }@@ -3185,7 +3185,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name, isec->sclass =inode_mode_to_security_class (inode->i_mode); isec->sid = newsid; - isec->initialized =1 ; + isec->initialized =LABEL_INITIALIZED ;return 0 ; }@@ -3763,7 +3763,7 @@ static void selinux_task_to_inode(struct task_struct *p,u32 sid =task_sid (p); isec->sid = sid; - isec->initialized =1 ; + isec->initialized =LABEL_INITIALIZED ; }/* Returns error only if unable to parse addresses */ @@ -4094,7 +4094,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,return err; } - isec->initialized =1 ; + isec->initialized =LABEL_INITIALIZED ;if (sock->sk) { sksec = sock->sk->sk_security;@@ -4285,7 +4285,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock) isec =inode_security (SOCK_INODE (sock)); newisec->sclass = isec->sclass; newisec->sid = isec->sid; - newisec->initialized =1 ; + newisec->initialized =LABEL_INITIALIZED ;return 0 ; }@@ -5775,6 +5775,15 @@ static void selinux_release_secctx(char *secdata, u32 seclen)kfree (secdata); } +static void selinux_inode_invalidate_secctx (struct inode *inode) +{ +struct inode_security_struct *isec = inode->i_security; + +mutex_lock (&isec->lock); + isec->initialized =LABEL_INVALID ; +mutex_unlock (&isec->lock); +} +/* * called with inode->i_mutex locked */ @@ -6006,6 +6015,7 @@ static struct security_hook_list selinux_hooks[] = {LSM_HOOK_INIT (secid_to_secctx, selinux_secid_to_secctx),LSM_HOOK_INIT (secctx_to_secid, selinux_secctx_to_secid),LSM_HOOK_INIT (release_secctx, selinux_release_secctx), +LSM_HOOK_INIT (inode_invalidate_secctx, selinux_inode_invalidate_secctx),LSM_HOOK_INIT (inode_notifysecctx, selinux_inode_notifysecctx),LSM_HOOK_INIT (inode_setsecctx, selinux_inode_setsecctx), LSM_HOOK_INIT(inode_getsecctx, selinux_inode_getsecctx),security/selinux/include/objsec.h +6
-0@@ -37,6 +37,12 @@ struct task_security_struct {u32 sockcreate_sid;/* fscreate SID */ }; +enum label_initialized { +LABEL_MISSING ,/* not initialized */ +LABEL_INITIALIZED ,/* inizialized */ +LABEL_INVALID /* invalid */ +}; +struct inode_security_struct {struct inode *inode;/* back pointer to inode object */ union {
Andreas Gruenbacher
maintainerPATCH v4 6/7 selinux: Revalidate invalid inode security labels
In reply to Andreas GruenbacherWhen fetching an inode's security label, check if it is still valid, and try reloading it if it is not. Reloading will fail when we are in RCU context which doesn't allow sleeping, or when we can't find a dentry for the inode. (Reloading happens via iop->getxattr which takes a dentry parameter.) When reloading fails, continue using the old, invalid label.
--- security/selinux/hooks.c | 70 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 5 deletions(-)
security/selinux/hooks.c +65 -5
@@ -241,11 +241,63 @@ static int inode_alloc_security(struct inode *inode)return 0 ; } +static int inode_doinit_with_dentry (struct inode *inode,struct dentry *opt_dentry); + +/* +* Try reloading inode security labels that have been marked as invalid. The +* @may_sleep parameter indicates when sleeping and thus reloading labels is +* allowed; when set to false, returns ERR_PTR(-ECHILD) when the label is +* invalid. The @opt_dentry parameter should be set to a dentry of the inode; +* when no dentry is available, set it to NULL instead. +*/ +static int __inode_security_revalidate (struct inode *inode, +struct dentry *opt_dentry, +bool may_sleep) +{ +struct inode_security_struct *isec = inode->i_security; + +might_sleep_if (may_sleep); + +if (isec->initialized ==LABEL_INVALID ) { +if (!may_sleep) +return -ECHILD ; + +/* +* Try reloading the inode security label. This will fail if +* @opt_dentry is NULL and no dentry for this inode can be +* found; in that case, continue using the old label. +*/ +inode_doinit_with_dentry (inode, opt_dentry); + } +return 0 ; +} + +static void inode_security_revalidate (struct inode *inode) +{ +__inode_security_revalidate (inode,NULL , true); +} + +static struct inode_security_struct *inode_security_novalidate (struct inode *inode) +{ +return inode->i_security; +} + +static struct inode_security_struct *inode_security_rcu (struct inode *inode,bool rcu) +{ +int error; + + error =__inode_security_revalidate (inode,NULL , !rcu); +if (error) +return ERR_PTR (error); +return inode->i_security; +} +/* * Get the security label of an inode. */ static struct inode_security_struct *inode_security (struct inode *inode) { +__inode_security_revalidate (inode,NULL , true);return inode->i_security; }
@@ -256,6 +308,7 @@ static struct inode_security_struct *backing_inode_security(struct dentry *dentr {struct inode *inode =d_backing_inode (dentry); +__inode_security_revalidate (inode, dentry, true);return inode->i_security; }
@@ -362,8 +415,6 @@ static const char *labeling_behaviors[7] = { "uses native labeling", }; -static int inode_doinit_with_dentry (struct inode *inode,struct dentry *opt_dentry); -static inline int inode_doinit (struct inode *inode) {return inode_doinit_with_dentry (inode,NULL );
@@ -1655,6 +1706,7 @@ static inline int dentry_has_perm(const struct cred *cred, ad.type =LSM_AUDIT_DATA_DENTRY ; ad.u.dentry = dentry; +__inode_security_revalidate (inode, dentry, true);return inode_has_perm (cred, inode, av, &ad); }
@@ -1670,6 +1722,7 @@ static inline int path_has_perm(const struct cred *cred, ad.type =LSM_AUDIT_DATA_PATH ; ad.u.path = *path; +__inode_security_revalidate (inode, path->dentry, true);return inode_has_perm (cred, inode, av, &ad); }
@@ -2874,7 +2927,9 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode, ad.type =LSM_AUDIT_DATA_DENTRY ; ad.u.dentry = dentry; sid =cred_sid (cred); - isec =inode_security (inode); + isec =inode_security_rcu (inode, rcu); +if (IS_ERR (isec)) +return PTR_ERR (isec);return avc_has_perm_flags (sid, isec->sid, isec->sclass,FILE__READ , &ad, rcu ?MAY_NOT_BLOCK :0 );
@@ -2926,7 +2981,9 @@ static int selinux_inode_permission(struct inode *inode, int mask) perms =file_mask_to_av (inode->i_mode, mask); sid =cred_sid (cred); - isec =inode_security (inode); + isec =inode_security_rcu (inode, flags &MAY_NOT_BLOCK ); +if (IS_ERR (isec)) +return PTR_ERR (isec); rc =avc_has_perm_noaudit (sid, isec->sid, isec->sclass, perms,0 , &avd); audited = avc_audit_required(perms, &avd, rc,
@@ -3234,6 +3291,7 @@ static int selinux_file_permission(struct file *file, int mask)/* No change since file_open check. */ return 0 ; +inode_security_revalidate (inode);return selinux_revalidate_file_permission (file, mask); }
@@ -3539,6 +3597,7 @@ static int selinux_file_open(struct file *file, const struct cred *cred)* new inode label or new policy. * This check is not redundant - do not remove. */ +inode_security_revalidate (file_inode (file));return file_path_has_perm (cred, file,open_file_to_av (file)); }
@@ -4620,7 +4679,8 @@ static void selinux_sk_getsecid(struct sock *sk, u32 *secid)static void selinux_sock_graft (struct sock *sk,struct socket *parent) { -struct inode_security_struct *isec =inode_security (SOCK_INODE (parent)); +struct inode_security_struct *isec = +inode_security_novalidate (SOCK_INODE (parent));struct sk_security_struct *sksec = sk->sk_security; if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
Signature · 1 line
2.5.0
Re: [PATCH v4 6/7] selinux: Revalidate invalid inode security labels
Quoted 8 lines · Andreas Gruenbacher
When fetching an inode's security label, check if it is still valid, and try reloading it if it is not. Reloading will fail when we are in RCU context which doesn't allow sleeping, or when we can't find a dentry for the inode. (Reloading happens via
iop->getxattrwhich takes a dentry parameter.) When reloading fails, continue using the old, invalid label.Signed-off-by Andreas Gruenbacher <[email protected]>
Could probably use inode_security_novalidate() for all of the SOCK_INODE() cases, right? Otherwise,
Quoted 154 lines
--- security/selinux/hooks.c | 70 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 5 deletions(-)security/selinux/hooks.c +65
-5@@ -241,11 +241,63 @@ static int inode_alloc_security(struct inode *inode)return 0 ; } +static int inode_doinit_with_dentry (struct inode *inode,struct dentry *opt_dentry); + +/* +* Try reloading inode security labels that have been marked as invalid. The +* @may_sleep parameter indicates when sleeping and thus reloading labels is +* allowed; when set to false, returns ERR_PTR(-ECHILD) when the label is +* invalid. The @opt_dentry parameter should be set to a dentry of the inode; +* when no dentry is available, set it to NULL instead. +*/ +static int __inode_security_revalidate (struct inode *inode, +struct dentry *opt_dentry, +bool may_sleep) +{ +struct inode_security_struct *isec = inode->i_security; + +might_sleep_if (may_sleep); + +if (isec->initialized ==LABEL_INVALID ) { +if (!may_sleep) +return -ECHILD ; + +/* +* Try reloading the inode security label. This will fail if +* @opt_dentry is NULL and no dentry for this inode can be +* found; in that case, continue using the old label. +*/ +inode_doinit_with_dentry (inode, opt_dentry); + } +return 0 ; +} + +static void inode_security_revalidate (struct inode *inode) +{ +__inode_security_revalidate (inode,NULL , true); +} + +static struct inode_security_struct *inode_security_novalidate (struct inode *inode) +{ +return inode->i_security; +} + +static struct inode_security_struct *inode_security_rcu (struct inode *inode,bool rcu) +{ +int error; + + error =__inode_security_revalidate (inode,NULL , !rcu); +if (error) +return ERR_PTR (error); +return inode->i_security; +} +/* * Get the security label of an inode. */ static struct inode_security_struct *inode_security (struct inode *inode) { +__inode_security_revalidate (inode,NULL , true);return inode->i_security; }@@ -256,6 +308,7 @@ static struct inode_security_struct *backing_inode_security(struct dentry *dentr {struct inode *inode =d_backing_inode (dentry); +__inode_security_revalidate (inode, dentry, true);return inode->i_security; }@@ -362,8 +415,6 @@ static const char *labeling_behaviors[7] = { "uses native labeling", }; -static int inode_doinit_with_dentry (struct inode *inode,struct dentry *opt_dentry); -static inline int inode_doinit (struct inode *inode) {return inode_doinit_with_dentry (inode,NULL );@@ -1655,6 +1706,7 @@ static inline int dentry_has_perm(const struct cred *cred, ad.type =LSM_AUDIT_DATA_DENTRY ; ad.u.dentry = dentry; +__inode_security_revalidate (inode, dentry, true);return inode_has_perm (cred, inode, av, &ad); }@@ -1670,6 +1722,7 @@ static inline int path_has_perm(const struct cred *cred, ad.type =LSM_AUDIT_DATA_PATH ; ad.u.path = *path; +__inode_security_revalidate (inode, path->dentry, true);return inode_has_perm (cred, inode, av, &ad); }@@ -2874,7 +2927,9 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode, ad.type =LSM_AUDIT_DATA_DENTRY ; ad.u.dentry = dentry; sid =cred_sid (cred); - isec =inode_security (inode); + isec =inode_security_rcu (inode, rcu); +if (IS_ERR (isec)) +return PTR_ERR (isec);return avc_has_perm_flags (sid, isec->sid, isec->sclass,FILE__READ , &ad, rcu ?MAY_NOT_BLOCK :0 );@@ -2926,7 +2981,9 @@ static int selinux_inode_permission(struct inode *inode, int mask) perms =file_mask_to_av (inode->i_mode, mask); sid =cred_sid (cred); - isec =inode_security (inode); + isec =inode_security_rcu (inode, flags &MAY_NOT_BLOCK ); +if (IS_ERR (isec)) +return PTR_ERR (isec); rc =avc_has_perm_noaudit (sid, isec->sid, isec->sclass, perms,0 , &avd); audited = avc_audit_required(perms, &avd, rc,@@ -3234,6 +3291,7 @@ static int selinux_file_permission(struct file *file, int mask)/* No change since file_open check. */ return 0 ; +inode_security_revalidate (inode);return selinux_revalidate_file_permission (file, mask); }@@ -3539,6 +3597,7 @@ static int selinux_file_open(struct file *file, const struct cred *cred)* new inode label or new policy. * This check is not redundant - do not remove. */ +inode_security_revalidate (file_inode (file));return file_path_has_perm (cred, file,open_file_to_av (file)); }@@ -4620,7 +4679,8 @@ static void selinux_sk_getsecid(struct sock *sk, u32 *secid)static void selinux_sock_graft (struct sock *sk,struct socket *parent) { -struct inode_security_struct *isec =inode_security (SOCK_INODE (parent)); +struct inode_security_struct *isec = +inode_security_novalidate (SOCK_INODE (parent));struct sk_security_struct *sksec = sk->sk_security; if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
Andreas Gruenbacher
maintainerRe: [PATCH v4 6/7] selinux: Revalidate invalid inode security labels
Quoted 9 lines · Stephen Smalley
Quoted 8 lines · Andreas Gruenbacher
When fetching an inode's security label, check if it is still valid, and try reloading it if it is not. Reloading will fail when we are in RCU context which doesn't allow sleeping, or when we can't find a dentry for the inode. (Reloading happens via
iop->getxattrwhich takes a dentry parameter.) When reloading fails, continue using the old, invalid label.
Quoted 5 lines
Quoted 1 line
Signed-off-by Andreas Gruenbacher <[email protected]>Could probably use
inode_security_novalidate()for all of theSOCK_INODE()cases, right?
I guess, yes.
Quoted 2 lines
Otherwise,
Acked-by Stephen Smalley <[email protected]>
Thanks,
Andreas
Paul Moore
maintainerRe: [PATCH v4 6/7] selinux: Revalidate invalid inode security labels
Quoted 10 lines · Andreas Gruenbacher
Quoted 9 lines · Stephen Smalley
Quoted 8 lines · Andreas Gruenbacher
When fetching an inode's security label, check if it is still valid, and try reloading it if it is not. Reloading will fail when we are in RCU context which doesn't allow sleeping, or when we can't find a dentry for the inode. (Reloading happens via
iop->getxattrwhich takes a dentry parameter.) When reloading fails, continue using the old, invalid label.
Quoted 7 lines
Quoted 5 lines
Quoted 1 line
Signed-off-by Andreas Gruenbacher <[email protected]>Could probably use
inode_security_novalidate()for all of theSOCK_INODE()cases, right?I guess, yes.
There is no time like the present. All the patches look fine to me, but I think it would be good to add the additional inode_security_novalidate() calls. If you want, you can just post a "8/7" patch with the extra calls added and I'll apply that on top of the v4 patchset.
Signature · 2 lines
paul moore www.paul-moore.com
Andreas Gruenbacher
maintainerRe: [PATCH v4 6/7] selinux: Revalidate invalid inode security labels
Paul,
Quoted 3 lines · Paul Moore
If you want, you can just post a
"8/7" patch with the extra calls added and I'll apply that on top of the v4 patchset.
I've also added the additional Acked-by headers, it's easiest to just repost (I just did).
Thanks,
Andreas
Andreas Gruenbacher
maintainerRe: [PATCH v4 6/7] selinux: Revalidate invalid inode security labels
In reply to Andreas GruenbacherDavid,
Quoted 81 lines · Andreas Gruenbacher
When fetching an inode's security label, check if it is still valid, and try reloading it if it is not. Reloading will fail when we are in RCU context which doesn't allow sleeping, or when we can't find a dentry for the inode. (Reloading happens via
iop->getxattrwhich takes a dentry parameter.) When reloading fails, continue using the old, invalid label.Signed-off-by Andreas Gruenbacher <[email protected]>--- security/selinux/hooks.c | 70 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 5 deletions(-)security/selinux/hooks.c +52
-0@@ -241,11 +241,63 @@ static int inode_alloc_security(struct inode *inode)return 0 ; } +static int inode_doinit_with_dentry (struct inode *inode,struct dentry *opt_dentry); + +/* +* Try reloading inode security labels that have been marked as invalid. The +* @may_sleep parameter indicates when sleeping and thus reloading labels is +* allowed; when set to false, returns ERR_PTR(-ECHILD) when the label is +* invalid. The @opt_dentry parameter should be set to a dentry of the inode; +* when no dentry is available, set it to NULL instead. +*/ +static int __inode_security_revalidate (struct inode *inode, +struct dentry *opt_dentry, +bool may_sleep) +{ +struct inode_security_struct *isec = inode->i_security; + +might_sleep_if (may_sleep); + +if (isec->initialized ==LABEL_INVALID ) { +if (!may_sleep) +return -ECHILD ; + +/* +* Try reloading the inode security label. This will fail if +* @opt_dentry is NULL and no dentry for this inode can be +* found; in that case, continue using the old label. +*/ +inode_doinit_with_dentry (inode, opt_dentry); + } +return 0 ; +} + +static void inode_security_revalidate (struct inode *inode) +{ +__inode_security_revalidate (inode,NULL , true); +} + +static struct inode_security_struct *inode_security_novalidate (struct inode *inode) +{ +return inode->i_security; +} + +static struct inode_security_struct *inode_security_rcu (struct inode *inode,bool rcu) +{ +int error; + + error =__inode_security_revalidate (inode,NULL , !rcu); +if (error) +return ERR_PTR (error); +return inode->i_security; +} +/* * Get the security label of an inode. */ static struct inode_security_struct *inode_security (struct inode *inode) { +__inode_security_revalidate (inode,NULL , true);return inode->i_security; }
security/selinux/hooks.c static struct inode_security_struct *backing_inode_security(struct dentry *dentr · line 313
Quoted 6 lines
security/selinux/hooks.c +1
-0@@ -256,6 +308,7 @@ static struct inode_security_struct *backing_inode_security(struct dentry *dentr {struct inode *inode =d_backing_inode (dentry); +__inode_security_revalidate (inode, dentry, true);return inode->i_security; }
inode security labels are stored as xattrs. The xattr inode operations take dentry instead of inode arguments for filesystems like 9p and cifs. SELinux often only has an inode where it needs a dentry so it tries to find a dentry with d_find_alias(). Where it does have a dentry, it does pass that down though; see the second argument to __inode_security_revalidate. Normal filesystems then operate on the d_inode(dentry) of that dentry.
That should work as long as d_inode and d_backing_inode remain the same, I assume that the plan is to change that eventually though. Then, backing_inode_security will have to lower the dentry, right? Ho will it have to do that?
Thanks,
Andreas
Andreas Gruenbacher
maintainerPATCH v4 7/7 gfs2: Invalide security labels of inodes when they go invalid
In reply to Andreas GruenbacherWhen gfs2 releases the glock of an inode, it must invalidate all information cached for that inode, including the page cache and acls. Use the new security_inode_invalidate_secctx hook to also invalidate security labels in that case. These items will be reread from disk when needed after reacquiring the glock.
--- fs/gfs2/glops.c | 2 ++ 1 file changed, 2 insertions(+)
fs/gfs2/glops.c +2 -0
@@ -13,6 +13,7 @@#include <linux/gfs2_ondisk.h> #include <linux/bio.h> #include <linux/posix_acl.h> +#include <linux/security.h> #include "gfs2.h" #include "incore.h"
@@ -262,6 +263,7 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags)if (ip) {set_bit (GIF_INVALID , &ip->i_flags);forget_all_cached_acls (&ip->i_inode); +security_inode_invalidate_secctx (&ip->i_inode);gfs2_dir_hash_inval (ip); } }
Signature · 1 line
2.5.0
PATCH v4 7/7 gfs2: Invalide security labels of inodes when they go invalid
----- Original Message -----
Quoted 34 lines
When gfs2 releases the glock of an inode, it must invalidate all information cached for that inode, including the page cache and acls. Use the new
security_inode_invalidate_secctxhook to also invalidate security labels in that case. These items will be reread from disk when needed after reacquiring the glock.Signed-off-by Andreas Gruenbacher <[email protected]>Cc Steven Whitehouse <[email protected]>Cc Bob Peterson <[email protected]>Cc cluster-devel at redhat.com--- fs/gfs2/glops.c | 2 ++ 1 file changed, 2 insertions(+)fs/gfs2/glops.c +2
-0@@ -13,6 +13,7 @@#include <linux/gfs2_ondisk.h> #include <linux/bio.h> #include <linux/posix_acl.h> +#include <linux/security.h> #include "gfs2.h" #include "incore.h" @@ -262,6 +263,7 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags)if (ip) {set_bit (GIF_INVALID , &ip->i_flags);forget_all_cached_acls (&ip->i_inode); +security_inode_invalidate_secctx (&ip->i_inode);gfs2_dir_hash_inval (ip); }
Quoted 5 lines
}
--
2.5.0
Hi,
Bob Peterson
Red Hat File Systems
PATCH v4 7/7 gfs2: Invalide security labels of inodes when they go invalid
In reply to Andreas GruenbacherHi,
Steve.
Quoted 34 lines · Andreas Gruenbacher
When gfs2 releases the glock of an inode, it must invalidate all information cached for that inode, including the page cache and acls. Use the new
security_inode_invalidate_secctxhook to also invalidate security labels in that case. These items will be reread from disk when needed after reacquiring the glock.Signed-off-by Andreas Gruenbacher <[email protected]>Cc Steven Whitehouse <[email protected]>Cc Bob Peterson <[email protected]>Cc cluster-devel at redhat.com--- fs/gfs2/glops.c | 2 ++ 1 file changed, 2 insertions(+)fs/gfs2/glops.c +2
-0@@ -13,6 +13,7 @@#include <linux/gfs2_ondisk.h> #include <linux/bio.h> #include <linux/posix_acl.h> +#include <linux/security.h> #include "gfs2.h" #include "incore.h" @@ -262,6 +263,7 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags)if (ip) {set_bit (GIF_INVALID , &ip->i_flags);forget_all_cached_acls (&ip->i_inode); +security_inode_invalidate_secctx (&ip->i_inode);gfs2_dir_hash_inval (ip); } }