reiserfs: add atomic addition of selinux attributes during inode creation
authorJeff Mahoney <jeffm@suse.com>
Mon, 30 Mar 2009 18:02:41 +0000 (14:02 -0400)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 30 Mar 2009 19:16:39 +0000 (12:16 -0700)
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>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
fs/reiserfs/inode.c
fs/reiserfs/namei.c
fs/reiserfs/xattr_security.c
include/linux/reiserfs_fs.h
include/linux/reiserfs_xattr.h

index 995f6975cae184f720131ad648ce640a4315fa02..fcd302d814470f2db723c97f748aa79f396f3fcf 100644 (file)
@@ -1747,7 +1747,8 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
                       /* 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;
        struct reiserfs_iget_args args;
@@ -1929,6 +1930,19 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
        } else if (IS_PRIVATE(dir))
                inode->i_flags |= S_PRIVATE;
 
+       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;
+               }
+       }
+
        reiserfs_update_sd(th, inode);
        reiserfs_check_path(&path_to_key);
 
index d9c1c8bd2950c6bbc9cc1385af2a9da463808651..cb1a9e97790712863c00b9a1c72a6d00ee6f192d 100644 (file)
@@ -598,6 +598,7 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode,
            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;
@@ -605,6 +606,12 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode,
        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);
@@ -615,7 +622,7 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode,
 
        retval =
            reiserfs_new_inode(&th, dir, mode, NULL, 0 /*i_size */ , dentry,
-                              inode);
+                              inode, &security);
        if (retval)
                goto out_failed;
 
@@ -655,6 +662,7 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
        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 +
@@ -670,6 +678,12 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
        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);
@@ -680,7 +694,7 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
 
        retval =
            reiserfs_new_inode(&th, dir, mode, NULL, 0 /*i_size */ , dentry,
-                              inode);
+                              inode, &security);
        if (retval) {
                goto out_failed;
        }
@@ -723,6 +737,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        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 +
@@ -740,6 +755,12 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        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);
@@ -756,7 +777,7 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
            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;
@@ -999,6 +1020,7 @@ static int reiserfs_symlink(struct inode *parent_dir,
        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 =
@@ -1011,6 +1033,13 @@ static int reiserfs_symlink(struct inode *parent_dir,
        }
        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)) {
@@ -1037,7 +1066,7 @@ static int reiserfs_symlink(struct inode *parent_dir,
 
        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;
index 2aacf1fe69fd29cb8614297f2a17d11ba9ff021f..4d3c20e787c39040badef94770ffdfdf1a77f70d 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/pagemap.h>
 #include <linux/xattr.h>
 #include <linux/reiserfs_xattr.h>
+#include <linux/security.h>
 #include <asm/uaccess.h>
 
 static int
@@ -47,6 +48,59 @@ static size_t security_list(struct inode *inode, char *list, size_t list_len,
        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 = NULL;
+       sec->value = NULL;
+}
+
 struct xattr_handler reiserfs_xattr_security_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
        .get = security_get,
index c0365e07fce6154798f634849eb7f1ff3cc9e8dd..eb4e912e6bd349ae2775e7b75c66bbe3e3d89be2 100644 (file)
@@ -1915,10 +1915,12 @@ void make_le_item_head(struct item_head *ih, const struct cpu_key *key,
                       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);
index 20eca09729a294f2ed44d0df879938411f0887e4..dcae01e63e4080636d76955c813c38047b980991 100644 (file)
@@ -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>
@@ -54,6 +60,14 @@ int reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *,
 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
 
 #define xattr_size(size) ((size) + sizeof(struct reiserfs_xattr_header))
 static inline loff_t reiserfs_xattr_nblocks(struct inode *inode, loff_t size)
@@ -109,6 +123,24 @@ static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
 }
 #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  */