[PATCH 4.18 115/145] ubifs: xattr: Dont operate on deleted inodes

From: Greg Kroah-Hartman
Date: Fri Sep 07 2018 - 17:20:04 EST


4.18-stable review patch. If anyone has any objections, please let me know.

------------------

From: Richard Weinberger <richard@xxxxxx>

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@xxxxxxxxxxxxxxx>
Fixes: 1e51764a3c2a ("UBIFS: add new flash file system")
Signed-off-by: Richard Weinberger <richard@xxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>

---
fs/ubifs/xattr.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)

--- a/fs/ubifs/xattr.c
+++ b/fs/ubifs/xattr.c
@@ -152,6 +152,12 @@ static int create_xattr(struct ubifs_inf
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 @@ 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);
@@ -235,6 +242,12 @@ static int change_xattr(struct ubifs_inf
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_inf
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_inf
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 @@ 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);
@@ -540,6 +561,9 @@ static int ubifs_xattr_remove(struct ino

ubifs_assert(inode_is_locked(host));

+ if (!host->i_nlink)
+ return -ENOENT;
+
if (fname_len(&nm) > UBIFS_MAX_NLEN)
return -ENAMETOOLONG;