Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 11a6fc3d authored by Richard Weinberger's avatar Richard Weinberger
Browse files

ubifs: xattr: Don't operate on deleted inodes



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: 1e51764a ("UBIFS: add new flash file system")
Signed-off-by: default avatarRichard Weinberger <richard@nod.at>
parent 312c39bd
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -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;