From: Jeff Mahoney <jeffm@suse.com>
Subject: [PATCH 21/39] reiserfs: add atomic addition of selinux attributes during inode creation

 Some time ago, some changes were made to make security inode attributes
 be atomically written during inode creation. ReiserFS fell behind in this
 area, but with the reworking of the xattr code, it's now fairly easy to add.

 The following patch adds the ability for security attributes to be added
 automatically during inode creation.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>

--
 fs/reiserfs/inode.c            |   16 +++++++++++
 fs/reiserfs/namei.c            |   37 ++++++++++++++++++++++++---
 fs/reiserfs/xattr_security.c   |   55 +++++++++++++++++++++++++++++++++++++++--
 include/linux/reiserfs_fs.h    |    4 ++
 include/linux/reiserfs_xattr.h |   31 +++++++++++++++++++++++
 5 files changed, 135 insertions(+), 8 deletions(-)

--- a/fs/reiserfs/inode.c	2007-06-11 14:49:38.000000000 -0400
+++ b/fs/reiserfs/inode.c	2007-06-11 14:50:04.000000000 -0400
@@ -1758,7 +1758,8 @@ int reiserfs_new_inode(struct reiserfs_t
 		       /* 0 for regular, EMTRY_DIR_SIZE for dirs, 
 		          strlen (symname) for symlinks) */
 		       loff_t i_size, struct dentry *dentry,
-		       struct inode *inode)
+		       struct inode *inode,
+		       struct reiserfs_security_handle *security)
 {
 	struct super_block *sb;
 	INITIALIZE_PATH(path_to_key);
@@ -1936,6 +1937,19 @@ int reiserfs_new_inode(struct reiserfs_t
 		reiserfs_mark_inode_private(inode);
 	}
 
+	if (security->name) {
+		retval = reiserfs_security_write(th, inode, security);
+		if (retval) {
+			err = retval;
+			reiserfs_check_path(&path_to_key);
+			retval = journal_end(th, th->t_super,
+			                     th->t_blocks_allocated);
+			if (retval)
+				err = retval;
+			goto out_inserted_sd;
+		}
+	}
+
 	insert_inode_hash(inode);
 	reiserfs_update_sd(th, inode);
 	reiserfs_check_path(&path_to_key);
--- a/fs/reiserfs/namei.c	2007-06-11 14:49:38.000000000 -0400
+++ b/fs/reiserfs/namei.c	2007-06-11 14:50:04.000000000 -0400
@@ -606,6 +606,7 @@ static int reiserfs_create(struct inode 
 	    2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) +
 		 REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb));
 	struct reiserfs_transaction_handle th;
+	struct reiserfs_security_handle security;
 
 	if (!(inode = new_inode(dir->i_sb))) {
 		return -ENOMEM;
@@ -613,6 +614,12 @@ static int reiserfs_create(struct inode 
 	new_inode_init(inode, dir, mode);
 
 	jbegin_count += reiserfs_cache_default_acl(dir);
+	retval = reiserfs_security_init(dir, inode, &security);
+	if (retval < 0) {
+		drop_new_inode(inode);
+		return retval;
+	}
+	jbegin_count += retval;
 	reiserfs_write_lock(dir->i_sb);
 
 	retval = journal_begin(&th, dir->i_sb, jbegin_count);
@@ -623,7 +630,7 @@ static int reiserfs_create(struct inode 
 
 	retval =
 	    reiserfs_new_inode(&th, dir, mode, NULL, 0 /*i_size */ , dentry,
-			       inode);
+			       inode, &security);
 	if (retval)
 		goto out_failed;
 
@@ -661,6 +668,7 @@ static int reiserfs_mknod(struct inode *
 	int retval;
 	struct inode *inode;
 	struct reiserfs_transaction_handle th;
+	struct reiserfs_security_handle security;
 	/* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */
 	int jbegin_count =
 	    JOURNAL_PER_BALANCE_CNT * 3 +
@@ -676,6 +684,12 @@ static int reiserfs_mknod(struct inode *
 	new_inode_init(inode, dir, mode);
 
 	jbegin_count += reiserfs_cache_default_acl(dir);
+	retval = reiserfs_security_init(dir, inode, &security);
+	if (retval < 0) {
+		drop_new_inode(inode);
+		return retval;
+	}
+	jbegin_count += retval;
 	reiserfs_write_lock(dir->i_sb);
 
 	retval = journal_begin(&th, dir->i_sb, jbegin_count);
@@ -686,7 +700,7 @@ static int reiserfs_mknod(struct inode *
 
 	retval =
 	    reiserfs_new_inode(&th, dir, mode, NULL, 0 /*i_size */ , dentry,
-			       inode);
+			       inode, &security);
 	if (retval) {
 		goto out_failed;
 	}
@@ -727,6 +741,7 @@ static int reiserfs_mkdir(struct inode *
 	int retval;
 	struct inode *inode;
 	struct reiserfs_transaction_handle th;
+	struct reiserfs_security_handle security;
 	/* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */
 	int jbegin_count =
 	    JOURNAL_PER_BALANCE_CNT * 3 +
@@ -744,6 +759,12 @@ static int reiserfs_mkdir(struct inode *
 	new_inode_init(inode, dir, mode);
 
 	jbegin_count += reiserfs_cache_default_acl(dir);
+	retval = reiserfs_security_init(dir, inode, &security);
+	if (retval < 0) {
+		drop_new_inode(inode);
+		return retval;
+	}
+	jbegin_count += retval;
 	reiserfs_write_lock(dir->i_sb);
 
 	retval = journal_begin(&th, dir->i_sb, jbegin_count);
@@ -760,7 +781,7 @@ static int reiserfs_mkdir(struct inode *
 	    retval = reiserfs_new_inode(&th, dir, mode, NULL /*symlink */ ,
 					old_format_only(dir->i_sb) ?
 					EMPTY_DIR_SIZE_V1 : EMPTY_DIR_SIZE,
-					dentry, inode);
+					dentry, inode, &security);
 	if (retval) {
 		dir->i_nlink--;
 		goto out_failed;
@@ -1001,6 +1022,7 @@ static int reiserfs_symlink(struct inode
 	char *name;
 	int item_len;
 	struct reiserfs_transaction_handle th;
+	struct reiserfs_security_handle security;
 	int mode = S_IFLNK | S_IRWXUGO;
 	/* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */
 	int jbegin_count =
@@ -1013,6 +1035,13 @@ static int reiserfs_symlink(struct inode
 	}
 	new_inode_init(inode, parent_dir, mode);
 
+	retval = reiserfs_security_init(parent_dir, inode, &security);
+	if (retval < 0) {
+		drop_new_inode(inode);
+		return retval;
+	}
+	jbegin_count += retval;
+
 	reiserfs_write_lock(parent_dir->i_sb);
 	item_len = ROUND_UP(strlen(symname));
 	if (item_len > MAX_DIRECT_ITEM_LEN(parent_dir->i_sb->s_blocksize)) {
@@ -1039,7 +1068,7 @@ static int reiserfs_symlink(struct inode
 
 	retval =
 	    reiserfs_new_inode(&th, parent_dir, mode, name, strlen(symname),
-			       dentry, inode);
+			       dentry, inode, &security);
 	kfree(name);
 	if (retval) {		/* reiserfs_new_inode iputs for us */
 		goto out_failed;
--- a/fs/reiserfs/xattr_security.c	2007-06-11 14:49:37.000000000 -0400
+++ b/fs/reiserfs/xattr_security.c	2007-06-11 14:49:38.000000000 -0400
@@ -4,10 +4,9 @@
 #include <linux/pagemap.h>
 #include <linux/xattr.h>
 #include <linux/reiserfs_xattr.h>
+#include <linux/security.h>
 #include <asm/uaccess.h>
 
-#define XATTR_SECURITY_PREFIX "security."
-
 static int
 security_get(struct inode *inode, const char *name, void *buffer, size_t size)
 {
@@ -49,6 +48,58 @@ static size_t security_list(struct inode
 	return len;
 }
 
+/* Initializes the security context for a new inode and returns the number
+ * of blocks needed for the transaction. If successful, reiserfs_security
+ * must be released using reiserfs_security_free when the caller is done. */
+int reiserfs_security_init(struct inode *dir, struct inode *inode,
+                           struct reiserfs_security_handle *sec)
+{
+	int blocks = 0;
+	int error = security_inode_init_security(inode, dir, &sec->name,
+	                                         &sec->value, &sec->length);
+	if (error) {
+		if (error == -EOPNOTSUPP)
+			error = 0;
+
+		sec->name = NULL;
+		sec->value = NULL;
+		sec->length = 0;
+		return error;
+	}
+
+	if (sec->length) {
+		blocks = reiserfs_xattr_jcreate_nblocks(inode) +
+		         reiserfs_xattr_nblocks(inode, sec->length);
+		/* We don't want to count the directories twice if we have
+		 * a default ACL. */
+		REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
+	}
+	return blocks;
+}
+
+int reiserfs_security_write(struct reiserfs_transaction_handle *th,
+                            struct inode *inode,
+                            struct reiserfs_security_handle *sec)
+{
+	int error;
+	if (strlen(sec->name) < sizeof(XATTR_SECURITY_PREFIX))
+		return -EINVAL;
+
+	error = reiserfs_xattr_set_handle(th, inode, sec->name, sec->value,
+	                                  sec->length, XATTR_CREATE);
+	if (error == -ENODATA || error == -EOPNOTSUPP)
+		error = 0;
+
+	return error;
+}
+
+void reiserfs_security_free(struct reiserfs_security_handle *sec)
+{
+	kfree(sec->name);
+	kfree(sec->value);
+	sec->name = sec->value = NULL;
+}
+
 struct xattr_handler reiserfs_xattr_security_handler = {
 	.prefix = XATTR_SECURITY_PREFIX,
 	.get = security_get,
--- a/include/linux/reiserfs_fs.h	2007-06-11 14:49:38.000000000 -0400
+++ b/include/linux/reiserfs_fs.h	2007-06-11 14:50:04.000000000 -0400
@@ -1909,10 +1909,12 @@ void make_le_item_head(struct item_head 
 		       loff_t offset, int type, int length, int entry_count);
 struct inode *reiserfs_iget(struct super_block *s, const struct cpu_key *key);
 
+struct reiserfs_security_handle;
 int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
 		       struct inode *dir, int mode,
 		       const char *symname, loff_t i_size,
-		       struct dentry *dentry, struct inode *inode);
+		       struct dentry *dentry, struct inode *inode,
+		       struct reiserfs_security_handle *security);
 
 void reiserfs_update_sd_size(struct reiserfs_transaction_handle *th,
 			     struct inode *inode, loff_t size);
--- a/include/linux/reiserfs_xattr.h	2007-06-11 14:49:38.000000000 -0400
+++ b/include/linux/reiserfs_xattr.h	2007-06-11 14:49:38.000000000 -0400
@@ -15,6 +15,12 @@ struct reiserfs_xattr_header {
 	__le32 h_hash;		/* hash of the value */
 };
 
+struct reiserfs_security_handle {
+	char *name;
+	void *value;
+	size_t length;
+};
+
 #ifdef __KERNEL__
 
 #include <linux/init.h>
@@ -50,6 +56,14 @@ int reiserfs_xattr_set_handle(struct rei
 extern struct xattr_handler reiserfs_xattr_user_handler;
 extern struct xattr_handler reiserfs_xattr_trusted_handler;
 extern struct xattr_handler reiserfs_xattr_security_handler;
+#ifdef CONFIG_REISERFS_FS_SECURITY
+int reiserfs_security_init(struct inode *dir, struct inode *inode,
+                           struct reiserfs_security_handle *sec);
+int reiserfs_security_write(struct reiserfs_transaction_handle *th,
+                            struct inode *inode,
+			    struct reiserfs_security_handle *sec);
+void reiserfs_security_free(struct reiserfs_security_handle *sec);
+#endif
 
 
 static inline void reiserfs_mark_inode_private(struct inode *inode)
@@ -114,6 +128,23 @@ static inline void reiserfs_init_xattr_r
 }
 #endif  /*  CONFIG_REISERFS_FS_XATTR  */
 
+#ifndef CONFIG_REISERFS_FS_SECURITY
+static inline int reiserfs_security_init(struct inode *dir,
+                                         struct inode *inode,
+                                         struct reiserfs_security_handle *sec)
+{
+	return 0;
+}
+static inline int reiserfs_security_write(struct reiserfs_transaction_handle *th,
+                                          struct inode *inode,
+					  struct reiserfs_security_handle *sec)
+{
+	return 0;
+}
+static inline void reiserfs_security_free(struct reiserfs_security_handle *sec)
+{}
+#endif
+
 #endif  /*  __KERNEL__  */
 
 #endif  /*  _LINUX_REISERFS_XATTR_H  */
