From nobody Sat Sep 26 07:15:20 2026 Received: from out30-101.freemail.mail.aliyun.com (out30-101.freemail.mail.aliyun.com [115.124.30.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 997194AA587 for ; Thu, 3 Sep 2026 13:13:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.30.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788441212; cv=none; b=kdwl3kfC16JYJzopQrmuHHYhNjtntHcNoPqMcNRZhqSf87idBa6ua5jWq3oAZflKhcoxyODXLCKEFHsOB6BgdLGTVy4oUhJVKT1tRqCBD2OsexfzynkXcOYvL0ANqjW15PHzuQpsrPtC/Vh3d4FstP9PDoRlpyLkBx5TUZt4A18= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788441212; c=relaxed/simple; bh=PW1aEYp2EBCpok59cbahHhJPmxsO3WMcbauEQwC+1uU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=O0RF14E5Ty6QPq6ZiMrwsvHVTHw3kRsWMi8PkhycGmgxW37TPkHbwc6qGDfdP+ua2BDAHFHtGPCjVLR1NeI9ywFx9HFA80gpvjBJ3sM/WA+MP03WnvKGyXNknoo6CyiQIddZgHMFZHSul1XP8gaQbEt3JTo4Y8ipEQmcpC7x8gg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com; spf=pass smtp.mailfrom=linux.alibaba.com; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b=kJecAw9C; arc=none smtp.client-ip=115.124.30.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b="kJecAw9C" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1788441196; h=From:To:Subject:Date:Message-Id:MIME-Version; bh=cqWubPGEU/FPOPqgpAtMLiOUZDsKRRTnlyUd+Vcv6eA=; b=kJecAw9CuNNbki9n+DzVfkfX2KQpvcRuMpoLamS4oW5zd9qXyiMncgQoLVlYJPgY/jhe4kBbll1rhpWSG0GtFJ5x5Y8GVmBzWWhLYoaeoTAzEaYOGELHtGV9oc2vO78gYz83gLmnYs+cDEA0A5BDzcpe9zZGrUuHXehcFy/Gk9E= X-Alimail-AntiSpam: AC=PASS;BC=-1|-1;BR=01201311R511e4;CH=green;DM=||false|;DS=||;FP=0|-1|-1|-1|0|-1|-1|-1;HT=maildocker-contentspam033045098064;MF=joseph.qi@linux.alibaba.com;NM=1;PH=DS;RN=6;SR=0;TI=SMTPD_---0XAG3g6q_1788441194; Received: from localhost(mailfrom:joseph.qi@linux.alibaba.com fp:SMTPD_---0XAG3g6q_1788441194 cluster:ay36) by smtp.aliyun-inc.com; Thu, 03 Sep 2026 21:13:15 +0800 From: Joseph Qi To: Andrew Morton , Heming Zhao Cc: Mark Fasheh , Joel Becker , ocfs2-devel@lists.linux.dev, linux-kernel@vger.kernel.org Subject: [PATCH v2 1/2] ocfs2: allow xattr bucket entries to span multiple blocks Date: Thu, 3 Sep 2026 21:13:12 +0800 Message-Id: <20260903131313.2396208-2-joseph.qi@linux.alibaba.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20260903131313.2396208-1-joseph.qi@linux.alibaba.com> References: <20260902124109.27775-1-joseph.qi@linux.alibaba.com> <20260903131313.2396208-1-joseph.qi@linux.alibaba.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" ocfs2_validate_xattr_bucket() limits the entry array to the first bucket block, but the write path stores entries across the whole OCFS2_XATTR_BUCKET_SIZE region. With 512-byte blocks a bucket spans eight blocks, and a bucket filled with small xattrs places its last entries past offset 512. Reading such a bucket back errors out: OCFS2: ERROR (device loop0): ocfs2_validate_xattr_bucket: Invalid xattr b= ucket 86072: entry count 32 exceeds maximum 31 On-disk corruption discovered. Please run fsck.ocfs2 once the filesystem = is unmounted. OCFS2: File system is now read-only. This is reproducible by setting ~33 xattrs with 100-byte values on a file on a blocksize-512 volume; fsck.ocfs2 reports the resulting image clean. Check the entry count against the full bucket region instead. The per-block bounds checks for names and values stay as they are, since ocfs2_bucket_align_free_start() keeps each name+value pair within a single block. The entry array is one contiguous region, so a bucket from a corrupted xattr tree whose first block is not aligned to OCFS2_XATTR_BUCKET_SIZE could straddle a page and make the validation loop read out of bounds. Buckets allocated within clusters are always aligned, so reject any other block number while validating. Fixes: 2cf82b46d5e4 ("ocfs2: validate external xattr entries when reading m= etadata") Signed-off-by: Joseph Qi --- fs/ocfs2/xattr.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 34f102db2a0e..c71fa7983b73 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -1153,11 +1153,30 @@ static int ocfs2_validate_xattr_bucket(struct ocfs2= _xattr_bucket *bucket, struct ocfs2_xattr_header *xh =3D bucket_xh(bucket); u16 xattr_count =3D le16_to_cpu(xh->xh_count); size_t region_size =3D (size_t)sb->s_blocksize * bucket->bu_blocks; - size_t entries_limit =3D sb->s_blocksize; + /* + * The entry array grows up from the header across the whole + * bucket region, so it may extend beyond the first bucket block + * when the blocksize is smaller than OCFS2_XATTR_BUCKET_SIZE. + * Name/value pairs, however, always live within a single block. + */ + size_t entries_limit =3D region_size; size_t nv_limit =3D sb->s_blocksize; size_t max_entries; int i, ret; =20 + /* + * The entry array is one contiguous region that may span the + * bucket's buffer_heads. Buckets are allocated within clusters, + * so their first block is always aligned to + * OCFS2_XATTR_BUCKET_SIZE and the whole bucket fits in one page. + * A corrupted xattr tree can point a bucket at blocks straddling + * a page, so reject it before touching the entry array. + */ + if (blkno & (bucket->bu_blocks - 1)) + return ocfs2_error(sb, + "Invalid xattr bucket %llu: unaligned block number\n", + (unsigned long long)blkno); + if (region_size < sizeof(*xh)) return ocfs2_error(sb, "Invalid xattr bucket %llu: region size %zu is too small\n", --=20 2.39.3 From nobody Sat Sep 26 07:15:20 2026 Received: from out30-131.freemail.mail.aliyun.com (out30-131.freemail.mail.aliyun.com [115.124.30.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B94604ACC7E for ; Thu, 3 Sep 2026 13:13:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.30.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788441218; cv=none; b=oFmaT6nQsaXb4laUcWGyut/Q7xdbl/T5Uq1JJfWAE82bJDuSL0+nAauQli1j7yYVGiMqZQMA4GpNaqseNHOO4QdvafDD5LMJIaW4jQIjXyKLv3hqQsaQ5KPGtp93Fd46HwF6eF+arxzxlBVqNpm2SSUqLrBlcveicJbu9/iI+Ew= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788441218; c=relaxed/simple; bh=ONZsj5jmua+TvKAYv3gjEVEb77OuCLqCK7sd7KWFBb8=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=j54qFn68J8vf5i2DVKzmujlj3CHBFczzWbn62BteVJBbzaA28Yg0nOJtW61yPT0wNMEwKu76PT0eXWU9520FF2pbZkpXzjlFGQinJGv7POW6L0uVLV7/4SOYHBURB+x/rXoe82dGxp/b1Sx4yXPs4WtuEJ4o74jHjdEbm30JtzY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com; spf=pass smtp.mailfrom=linux.alibaba.com; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b=x2USygux; arc=none smtp.client-ip=115.124.30.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.alibaba.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.alibaba.com header.i=@linux.alibaba.com header.b="x2USygux" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.alibaba.com; s=default; t=1788441197; h=From:To:Subject:Date:Message-Id:MIME-Version; bh=bUd52YBr6WnPR1aGhEESuPmA5WwvLiDROmDwXm5K/s4=; b=x2USyguxRWME1QcrxM+DWwVQhf2ZWuRUxMNuWFPtXFyPSo2Xf9Qajht95WA4n+oS5bfbuwRtMR5qUQUhUM/t6Uf6+b6pg5T3iLFDGHTKWAtnHpJxVo8kN+3nrfebZgWZUlIfKPdb+vFefdOiACj7RE2p5QHlXpOdwn5PrgVOxfk= X-Alimail-AntiSpam: AC=PASS;BC=-1|-1;BR=01201311R211e4;CH=green;DM=||false|;DS=||;FP=0|-1|-1|-1|0|-1|-1|-1;HT=maildocker-contentspam033037026112;MF=joseph.qi@linux.alibaba.com;NM=1;PH=DS;RN=6;SR=0;TI=SMTPD_---0XAG2x2o_1788441195; Received: from localhost(mailfrom:joseph.qi@linux.alibaba.com fp:SMTPD_---0XAG2x2o_1788441195 cluster:ay36) by smtp.aliyun-inc.com; Thu, 03 Sep 2026 21:13:16 +0800 From: Joseph Qi To: Andrew Morton , Heming Zhao Cc: Mark Fasheh , Joel Becker , ocfs2-devel@lists.linux.dev, linux-kernel@vger.kernel.org Subject: [PATCH v2 2/2] ocfs2: reject inconsistent xattr bucket during defrag Date: Thu, 3 Sep 2026 21:13:13 +0800 Message-Id: <20260903131313.2396208-3-joseph.qi@linux.alibaba.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20260903131313.2396208-1-joseph.qi@linux.alibaba.com> References: <20260902124109.27775-1-joseph.qi@linux.alibaba.com> <20260903131313.2396208-1-joseph.qi@linux.alibaba.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" ocfs2_defrag_xattr_bucket() has two mlog_bug_on_msg() checks that assume the name/value pairs in a bucket are disjoint and that xh_free_start is not below the compacted region. ocfs2_validate_xattr_bucket() only checks each entry in isolation, so a corrupt bucket holding overlapping entries, or one with an inflated xh_free_start, passes validation and then hits BUG() in defrag when a setxattr triggers it. Defrag works on a linear copy of the bucket and does not touch the real blocks before the copy back, so the checks can return an error instead of calling BUG(). Fixes: 012255961c9e ("ocfs2: Enable xattr set in index btree") Signed-off-by: Joseph Qi --- fs/ocfs2/xattr.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index c71fa7983b73..e6c49adaac8a 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -4804,16 +4804,22 @@ static int ocfs2_defrag_xattr_bucket(struct inode *= inode, memmove(bucket_buf + end - len, bucket_buf + offset, len); xe->xe_name_offset =3D cpu_to_le16(end - len); + } else if (end < offset + len) { + ret =3D ocfs2_error(inode->i_sb, + "Defrag check failed for bucket %llu\n", + (unsigned long long)blkno); + goto out; } =20 - mlog_bug_on_msg(end < offset + len, "Defrag check failed for " - "bucket %llu\n", (unsigned long long)blkno); - end -=3D len; } =20 - mlog_bug_on_msg(xh_free_start > end, "Defrag check failed for " - "bucket %llu\n", (unsigned long long)blkno); + if (xh_free_start > end) { + ret =3D ocfs2_error(inode->i_sb, + "Defrag check failed for bucket %llu\n", + (unsigned long long)blkno); + goto out; + } =20 if (xh_free_start =3D=3D end) goto out; --=20 2.39.3