From: Jeffrey Mahoney <jeffm@novell.com>

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 <sds@epoch.ncsc.mil>

Signed-off-by: Jeff Mahoney <jeffm@novell.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 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,
_