From: Eugene Kapun <abacabadabacaba@xxxxxxxxx> Fixes crashes when: * .reiserfs_priv exists and is not a directory * .reiserfs_priv/xattrs exists and is not a directory * .reiserfs_prix/xattrs/<something> exists and is not a directory * .reiserfs_priv/xattrs/<something>/<something> exists and is not a regular file Signed-off-by: Eugene Kapun <abacabadabacaba@xxxxxxxxx> --- This patch applies to linux-2.6.31-rc2-git4. This patch depends on patch 2/3 (reiserfs: add mount option that disables extended attributes support). This patch prevents reiserfs from crashing if certain directories are actually files or something else, and vice versa. Instead, it will refuse to mount such filesystem or abort operations on files with -EIO. fs/reiserfs/super.c | 53 ++++++++++++++++++++++-------------------- fs/reiserfs/xattr.c | 44 +++++++++++++++++++++++++++------- 2 files changed, 63 insertions(+), 34 deletions(-) diff -uprN linux-2.6.31-rc2-git3.2/fs/reiserfs/super.c linux-2.6.31-rc2-git3.3/fs/reiserfs/super.c --- linux-2.6.31-rc2-git3.2/fs/reiserfs/super.c 2009-07-09 15:03:10.000000000 +0400 +++ linux-2.6.31-rc2-git3.3/fs/reiserfs/super.c 2009-07-09 13:57:15.000000000 +0400 @@ -1762,11 +1762,8 @@ static int reiserfs_fill_super(struct su } // define and initialize hash function sbi->s_hash_function = hash_function(s); - if (sbi->s_hash_function == NULL) { - dput(s->s_root); - s->s_root = NULL; - goto error; - } + if (sbi->s_hash_function == NULL) + goto error_root; if (is_reiserfs_3_5(rs) || (is_reiserfs_jr(rs) && SB_VERSION(s) == REISERFS_VERSION_1)) @@ -1779,11 +1776,8 @@ static int reiserfs_fill_super(struct su if (!(s->s_flags & MS_RDONLY)) { errval = journal_begin(&th, s, 1); - if (errval) { - dput(s->s_root); - s->s_root = NULL; - goto error; - } + if (errval) + goto error_root; reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1); set_sb_umount_state(rs, REISERFS_ERROR_FS); @@ -1834,18 +1828,12 @@ static int reiserfs_fill_super(struct su journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s)); errval = journal_end(&th, s, 1); - if (errval) { - dput(s->s_root); - s->s_root = NULL; - goto error; - } + if (errval) + goto error_root; if ((errval = reiserfs_lookup_privroot(s)) || - (errval = reiserfs_xattr_init(s, s->s_flags))) { - dput(s->s_root); - s->s_root = NULL; - goto error; - } + (errval = reiserfs_xattr_init(s, s->s_flags))) + goto error_privroot; /* look for files which were to be removed in previous session */ finish_unfinished(s); @@ -1855,11 +1843,8 @@ static int reiserfs_fill_super(struct su } if ((errval = reiserfs_lookup_privroot(s)) || - (errval = reiserfs_xattr_init(s, s->s_flags))) { - dput(s->s_root); - s->s_root = NULL; - goto error; - } + (errval = reiserfs_xattr_init(s, s->s_flags))) + goto error_privroot; } // mark hash in super block: it could be unset. overwrite should be ok set_sb_hash_function_code(rs, function2code(sbi->s_hash_function)); @@ -1873,6 +1858,24 @@ static int reiserfs_fill_super(struct su return (0); +error_privroot: +#ifdef CONFIG_REISERFS_FS_EXTENDED + if (REISERFS_SB(s)->priv_root) { + if (REISERFS_SB(s)->xattr_root) { + d_invalidate(REISERFS_SB(s)->xattr_root); + dput(REISERFS_SB(s)->xattr_root); + REISERFS_SB(s)->xattr_root = NULL; + } + d_invalidate(REISERFS_SB(s)->priv_root); + dput(REISERFS_SB(s)->priv_root); + REISERFS_SB(s)->priv_root = NULL; + } +#endif + +error_root: + dput(s->s_root); + s->s_root = NULL; + error: if (jinit_done) { /* kill the commit thread, free journal ram */ journal_release_error(NULL, s); diff -uprN linux-2.6.31-rc2-git3.2/fs/reiserfs/xattr.c linux-2.6.31-rc2-git3.3/fs/reiserfs/xattr.c --- linux-2.6.31-rc2-git3.2/fs/reiserfs/xattr.c 2009-07-09 15:06:12.000000000 +0400 +++ linux-2.6.31-rc2-git3.3/fs/reiserfs/xattr.c 2009-07-09 13:57:15.000000000 +0400 @@ -155,10 +155,17 @@ static struct dentry *open_xa_dir(const mutex_lock_nested(&xaroot->d_inode->i_mutex, I_MUTEX_XATTR); xadir = lookup_one_len(namebuf, xaroot, strlen(namebuf)); - if (!IS_ERR(xadir) && !xadir->d_inode) { - int err = -ENODATA; - if (xattr_may_create(flags)) - err = xattr_mkdir(xaroot->d_inode, xadir, 0700); + if (!IS_ERR(xadir)) { + int err; + if (xadir->d_inode) { + err = 0; + if (!S_ISDIR(xadir->d_inode->i_mode)) + err = -EIO; + } else { + err = -ENODATA; + if (xattr_may_create(flags)) + err = xattr_mkdir(xaroot->d_inode, xadir, 0700); + } if (err) { dput(xadir); xadir = ERR_PTR(err); @@ -372,7 +379,8 @@ static struct dentry *xattr_lookup(struc if (xattr_may_create(flags)) err = xattr_create(xadir->d_inode, xafile, 0700|S_IFREG); - } + } else if (!S_ISREG(xafile->d_inode->i_mode)) + err = -EIO; if (err) dput(xafile); @@ -992,8 +1000,17 @@ int reiserfs_lookup_privroot(struct supe REISERFS_SB(s)->priv_root = dentry; if (!reiserfs_expose_privroot(s)) s->s_root->d_op = &xattr_lookup_poison_ops; - if (dentry->d_inode) - dentry->d_inode->i_flags |= S_PRIVATE; + if (dentry->d_inode) { + if (S_ISDIR(dentry->d_inode->i_mode)) { + dentry->d_inode->i_flags |= S_PRIVATE; + } else { + reiserfs_warning(s, NULL, + PRIVROOT_NAME " exists and " + "is not a directory. Remount " + "with -o noext to fix this"); + err = -EINVAL; + } + } } else err = PTR_ERR(dentry); mutex_unlock(&s->s_root->d_inode->i_mutex); @@ -1028,9 +1045,18 @@ int reiserfs_xattr_init(struct super_blo struct dentry *dentry; dentry = lookup_one_len(XAROOT_NAME, privroot, strlen(XAROOT_NAME)); - if (!IS_ERR(dentry)) + if (!IS_ERR(dentry)) { REISERFS_SB(s)->xattr_root = dentry; - else + if (dentry->d_inode && + !S_ISDIR(dentry->d_inode->i_mode)) { + reiserfs_warning(s, NULL, + PRIVROOT_NAME "/" XAROOT_NAME + " exists and is not " + "a directory. Remount with " + "-o noext to fix this"); + err = -EINVAL; + } + } else err = PTR_ERR(dentry); } mutex_unlock(&privroot->d_inode->i_mutex); -- To unsubscribe from this list: send the line "unsubscribe reiserfs-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html