From 57fe60df62410f949da094d06ced1dda9575b69c Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Mon, 30 Mar 2009 14:02:41 -0400 Subject: 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 Signed-off-by: Linus Torvalds --- fs/reiserfs/inode.c | 16 ++++++++++++- fs/reiserfs/namei.c | 37 ++++++++++++++++++++++++++---- fs/reiserfs/xattr_security.c | 54 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 5 deletions(-) (limited to 'fs/reiserfs') diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 995f6975cae1..fcd302d81447 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -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); diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index d9c1c8bd2950..cb1a9e977907 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -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; diff --git a/fs/reiserfs/xattr_security.c b/fs/reiserfs/xattr_security.c index 2aacf1fe69fd..4d3c20e787c3 100644 --- a/fs/reiserfs/xattr_security.c +++ b/fs/reiserfs/xattr_security.c @@ -4,6 +4,7 @@ #include #include #include +#include #include 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, -- cgit v1.2.3