ubifs: xattr: Don't operate on deleted inodes
authorRichard Weinberger <richard@nod.at>
Sun, 8 Jul 2018 21:33:25 +0000 (23:33 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 9 Sep 2018 17:56:00 +0000 (19:56 +0200)
commit 11a6fc3dc743e22fb50f2196ec55bee5140d3c52 upstream.

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: <stable@vger.kernel.org>
Fixes: 1e51764a3c2a ("UBIFS: add new flash file system")
Signed-off-by: Richard Weinberger <richard@nod.at>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/ubifs/xattr.c

index c13eae819cbc889ffe245dc5928278b1ccc2f4c5..d47f16c0d5829bb29928be6af1889e7634115755 100644 (file)
@@ -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));
@@ -183,6 +189,7 @@ out_cancel:
        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);
@@ -234,6 +241,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);
@@ -255,6 +268,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:
@@ -483,6 +497,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));
@@ -502,6 +522,7 @@ out_cancel:
        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);
@@ -541,6 +562,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;