xattr operations can race with unlink and the following assert triggers:
UBIFS assert failed in ubifs_jnl_change_xattr at 1606 (pid 6256)

Fix this by checking i_nlink before working on the host inode.

Cc: <sta...@vger.kernel.org>
Fixes: 1e51764a3c2a ("UBIFS: add new flash file system")
Signed-off-by: Richard Weinberger <rich...@nod.at>
---
 fs/ubifs/xattr.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
index 6f720fdf5020..09e37e63bddd 100644
--- a/fs/ubifs/xattr.c
+++ b/fs/ubifs/xattr.c
@@ -152,6 +152,12 @@ static int create_xattr(struct ubifs_info *c, struct inode 
*host,
        ui->data_len = size;
 
        mutex_lock(&host_ui->ui_mutex);
+
+       if (!host->i_nlink) {
+               err = -ENOENT;
+               goto out_noent;
+       }
+
        host->i_ctime = current_time(host);
        host_ui->xattr_cnt += 1;
        host_ui->xattr_size += CALC_DENT_SIZE(fname_len(nm));
@@ -184,6 +190,7 @@ static int create_xattr(struct ubifs_info *c, struct inode 
*host,
        host_ui->xattr_size -= CALC_XATTR_BYTES(size);
        host_ui->xattr_names -= fname_len(nm);
        host_ui->flags &= ~UBIFS_CRYPT_FL;
+out_noent:
        mutex_unlock(&host_ui->ui_mutex);
 out_free:
        make_bad_inode(inode);
@@ -235,6 +242,12 @@ static int change_xattr(struct ubifs_info *c, struct inode 
*host,
        mutex_unlock(&ui->ui_mutex);
 
        mutex_lock(&host_ui->ui_mutex);
+
+       if (!host->i_nlink) {
+               err = -ENOENT;
+               goto out_noent;
+       }
+
        host->i_ctime = current_time(host);
        host_ui->xattr_size -= CALC_XATTR_BYTES(old_size);
        host_ui->xattr_size += CALC_XATTR_BYTES(size);
@@ -256,6 +269,7 @@ static int change_xattr(struct ubifs_info *c, struct inode 
*host,
 out_cancel:
        host_ui->xattr_size -= CALC_XATTR_BYTES(size);
        host_ui->xattr_size += CALC_XATTR_BYTES(old_size);
+out_noent:
        mutex_unlock(&host_ui->ui_mutex);
        make_bad_inode(inode);
 out_free:
@@ -482,6 +496,12 @@ static int remove_xattr(struct ubifs_info *c, struct inode 
*host,
                return err;
 
        mutex_lock(&host_ui->ui_mutex);
+
+       if (!host->i_nlink) {
+               err = -ENOENT;
+               goto out_noent;
+       }
+
        host->i_ctime = current_time(host);
        host_ui->xattr_cnt -= 1;
        host_ui->xattr_size -= CALC_DENT_SIZE(fname_len(nm));
@@ -501,6 +521,7 @@ static int remove_xattr(struct ubifs_info *c, struct inode 
*host,
        host_ui->xattr_size += CALC_DENT_SIZE(fname_len(nm));
        host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len);
        host_ui->xattr_names += fname_len(nm);
+out_noent:
        mutex_unlock(&host_ui->ui_mutex);
        ubifs_release_budget(c, &req);
        make_bad_inode(inode);
@@ -540,6 +561,9 @@ static int ubifs_xattr_remove(struct inode *host, const 
char *name)
 
        ubifs_assert(inode_is_locked(host));
 
+       if (!host->i_nlink)
+               return -ENOENT;
+
        if (fname_len(&nm) > UBIFS_MAX_NLEN)
                return -ENAMETOOLONG;
 
-- 
2.18.0

Reply via email to