[PATCH 1/1] ubifs: fix slab-out-of-bounds in pack_inode via xattr

Ren Wei n05ec at lzu.edu.cn
Wed Jun 3 09:37:02 PDT 2026


From: Luxiao Xu <rakukuip at gmail.com>

An issue in fs/ubifs/journal.c was found where a malicious or corrupted
ubifs image could trigger a slab-out-of-bounds write in pack_inode().

When an inode with extended attributes (xattrs) is being evicted or
deleted (i.e., 'last_reference' and 'kill_xattrs' are true),
ubifs_jnl_write_inode() calculates the allocation size 'write_len'
based on 'ui->xattr_cnt' from the disk.

However, if 'ui->xattr_cnt' is maliciously tampered with or corrupted
to be smaller than the actual number of xattr entries stored in the
TNC (Tree Node Cache), kmalloc() will allocate an undersized buffer.
The subsequent 'while (1)' loop continues to iterate through all actual
xattr entries via ubifs_tnc_next_ent(), advancing the 'ino' pointer
and invoking pack_inode() for each entry. This mismatch leads to an
out-of-bounds memory write, corrupting the slab redzone and triggering
a KASAN panic.

Fix this by introducing a strict counter 'xattrs_deleted' within the
deletion loop. The loop is aborted with -EUCLEAN if the number of
processed xattrs exceeds 'ui->xattr_cnt', preventing 'ino' from
overflowing the allocated kmalloc buffer.

The bug is reachable by a non-root user via user and net namespace.

Fixes: 7959cf3a7506 ("ubifs: journal: Handle xattrs like files")
Cc: stable at kernel.org
Reported-by: Yuan Tan <yuantan098 at gmail.com>
Reported-by: Yifan Wu <yifanwucs at gmail.com>
Reported-by: Juefei Pu <tomapufckgml at gmail.com>
Reported-by: Xin Liu <bird at lzu.edu.cn>
Signed-off-by: Luxiao Xu <rakukuip at gmail.com>
Signed-off-by: Ren Wei <n05ec at lzu.edu.cn>
---
 fs/ubifs/journal.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c
index d02509920baf..78fe9d2a3178 100644
--- a/fs/ubifs/journal.c
+++ b/fs/ubifs/journal.c
@@ -880,6 +880,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
 		struct fscrypt_name nm = {0};
 		struct inode *xino;
 		struct ubifs_dent_node *xent, *pxent = NULL;
+		int xattrs_deleted = 0;
 
 		if (ui->xattr_cnt > ubifs_xattr_max_cnt(c)) {
 			err = -EPERM;
@@ -899,6 +900,14 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
 				goto out_release;
 			}
 
+			if (xattrs_deleted >= ui->xattr_cnt) {
+				kfree(pxent);
+				kfree(xent);
+				err = -EUCLEAN;
+				ubifs_err(c, "xattr count mismatch for ino %lu", inode->i_ino);
+				goto out_release;
+			}
+
 			fname_name(&nm) = xent->name;
 			fname_len(&nm) = le16_to_cpu(xent->nlen);
 
@@ -917,6 +926,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
 			clear_nlink(xino);
 			pack_inode(c, ino, xino, 0);
 			ino = (void *)ino + UBIFS_INO_NODE_SZ;
+			xattrs_deleted++;
 			iput(xino);
 
 			kfree(pxent);
-- 
2.43.0




More information about the linux-mtd mailing list