From: Jeffrey Mahoney ReiserFS implements extended attributes by backing them with regular files. This means that selinux would create an infinite series of xattrs-on-xattrs-on-xattrs etc. However, due to the locking of xattrs, this series never happens. Instead, a locking loop occurs. This patch allows SElinux to mark inodes as "private," such that SElinux attributes aren't associated with them. Original implementation by Stephen Smalley Signed-off-by: Jeff Mahoney Signed-off-by: Andrew Morton --- 25-akpm/include/linux/security.h | 14 ++++++++++++++ 25-akpm/security/dummy.c | 6 ++++++ 25-akpm/security/selinux/hooks.c | 19 +++++++++++++++++++ 3 files changed, 39 insertions(+) diff -puN include/linux/security.h~selinux-adds-a-private-inode-operation include/linux/security.h --- 25/include/linux/security.h~selinux-adds-a-private-inode-operation 2004-12-03 20:57:08.235386832 -0800 +++ 25-akpm/include/linux/security.h 2004-12-03 20:57:08.243385616 -0800 @@ -409,6 +409,11 @@ struct swap_info_struct; * is specified by @buffer_size. @buffer may be NULL to request * the size of the buffer required. * Returns number of bytes used/required on success. + * @inode_mark_private: + * Set up the security state of @inode to reflect the fact that the inode + * is private, i.e. used internally by the filesystem for purposes such + * as xattr storage and not accessible by userspace. This property should + * then be inherited by all nodes under this node. * * Security hooks for file operations * @@ -1114,6 +1119,7 @@ struct security_operations { int (*inode_getsecurity)(struct inode *inode, const char *name, void *buffer, size_t size); int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags); int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size); + void (*inode_mark_private)(struct inode *inode); int (*file_permission) (struct file * file, int mask); int (*file_alloc_security) (struct file * file); @@ -1598,6 +1604,11 @@ static inline int security_inode_listsec return security_ops->inode_listsecurity(inode, buffer, buffer_size); } +static inline void security_inode_mark_private(struct inode *inode) +{ + security_ops->inode_mark_private(inode); +} + static inline int security_file_permission (struct file *file, int mask) { return security_ops->file_permission (file, mask); @@ -2242,6 +2253,9 @@ static inline int security_inode_listsec return 0; } +static inline void security_inode_mark_private(struct inode *inode) +{ } + static inline int security_file_permission (struct file *file, int mask) { return 0; diff -puN security/dummy.c~selinux-adds-a-private-inode-operation security/dummy.c --- 25/security/dummy.c~selinux-adds-a-private-inode-operation 2004-12-03 20:57:08.237386528 -0800 +++ 25-akpm/security/dummy.c 2004-12-03 20:57:08.244385464 -0800 @@ -477,6 +477,11 @@ static int dummy_inode_listsecurity(stru return 0; } +static void dummy_inode_mark_private(struct inode *inode) +{ + return; +} + static int dummy_file_permission (struct file *file, int mask) { return 0; @@ -964,6 +969,7 @@ void security_fixup_ops (struct security set_to_dummy_if_null(ops, inode_getsecurity); set_to_dummy_if_null(ops, inode_setsecurity); set_to_dummy_if_null(ops, inode_listsecurity); + set_to_dummy_if_null(ops, inode_mark_private); set_to_dummy_if_null(ops, file_permission); set_to_dummy_if_null(ops, file_alloc_security); set_to_dummy_if_null(ops, file_free_security); diff -puN security/selinux/hooks.c~selinux-adds-a-private-inode-operation security/selinux/hooks.c --- 25/security/selinux/hooks.c~selinux-adds-a-private-inode-operation 2004-12-03 20:57:08.238386376 -0800 +++ 25-akpm/security/selinux/hooks.c 2004-12-03 20:57:08.248384856 -0800 @@ -737,6 +737,15 @@ static int inode_doinit_with_dentry(stru if (isec->initialized) goto out; + if (opt_dentry && opt_dentry->d_parent && opt_dentry->d_parent->d_inode) { + struct inode_security_struct *pisec = opt_dentry->d_parent->d_inode->i_security; + if (pisec->inherit) { + isec->sid = pisec->sid; + isec->initialized = 1; + goto out; + } + } + down(&isec->sem); hold_sem = 1; if (isec->initialized) @@ -2366,6 +2375,15 @@ static int selinux_inode_listsecurity(st return len; } +static void selinux_inode_mark_private(struct inode *inode) +{ + struct inode_security_struct *isec = inode->i_security; + + isec->sid = SECINITSID_KERNEL; + isec->initialized = 1; + isec->inherit = 1; +} + /* file security operations */ static int selinux_file_permission(struct file *file, int mask) @@ -4259,6 +4277,7 @@ struct security_operations selinux_ops = .inode_getsecurity = selinux_inode_getsecurity, .inode_setsecurity = selinux_inode_setsecurity, .inode_listsecurity = selinux_inode_listsecurity, + .inode_mark_private = selinux_inode_mark_private, .file_permission = selinux_file_permission, .file_alloc_security = selinux_file_alloc_security, _