All of lore.kernel.org
 help / color / mirror / Atom feed
From: 이상호 <kudo3228@gmail.com>
To: Kees Cook <kees@kernel.org>, Al Viro <viro@zeniv.linux.org.uk>
Cc: 이상호 <kudo3228@gmail.com>,
	linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH] ufs: reject malformed cylinder summary geometry
Date: Thu,  2 Jul 2026 06:57:00 +0900	[thread overview]
Message-ID: <20260701215700.822003-1-kudo3228@gmail.com> (raw)

ufs_read_cylinder_structures() allocates uspi->s_cssize bytes for the
cylinder summary area, but it calculates the number of fragments to copy
using the on-disk fs_fshift value and then copies a full s_fsize bytes for
every fragment:

	size = uspi->s_cssize;
	blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift;
	base = space = kmalloc(size, GFP_NOFS);
	...
	memcpy(space, bh->b_data, uspi->s_fsize);

ufs_fill_super() validates fs_fsize, but not the sibling fs_fshift and
fs_cssize fields. A crafted writable UFS/FFS image can therefore set an
inconsistent fs_fshift, or set fs_cssize to a value that does not match the
number of cylinder groups, causing the loop to copy past the end of the
allocated cylinder summary buffer.

Reject inconsistent cylinder summary geometry before writable mount. This
preserves the existing read/write paths for valid filesystems and fails
malformed superblocks before ufs_read_cylinder_structures() can overrun the
kmalloc(s_cssize) buffer.

This matches normal producer output: UFS/FFS tools derive fs_fshift from
fs_fsize and round the cylinder summary table size up to a fragment
boundary.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: 이상호 <kudo3228@gmail.com>
---
Notes:
- Public third-party writeup for the same issue:
  https://psn.af/k/17/
- Unpatched CONFIG_UFS_FS_WRITE=y KASAN replay reproduces the
  ufs_read_cylinder_structures slab-out-of-bounds write.
- Patched replay rejects the malformed image with EINVAL before the
  vulnerable copy loop; no UFS KASAN signature appears.
- The same patch applies cleanly with git apply --check to checked
  mainline/stable refs: origin/master, linux-6.18.y, linux-6.12.y,
  linux-6.6.y, linux-6.1.y, linux-5.15.y, and linux-5.10.y.
- A latest-master raw-source patchcheck also reports vulnerable_shape=present
  and patch_status=applies for fs/ufs/super.c.
- Full logs and reproducer image are available privately on request.

 fs/ufs/super.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index c4831a8b9b3f..c295b637920a 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -725,6 +725,7 @@ static int ufs_fill_super(struct super_block *sb, struct fs_context *fc)
 	struct ufs_buffer_head * ubh;	
 	struct inode *inode;
 	unsigned block_size, super_block_size;
+	u64 expected_cssize;
 	unsigned flags;
 	unsigned super_block_offset;
 	unsigned maxsymlen;
@@ -1139,6 +1140,19 @@ static int ufs_fill_super(struct super_block *sb, struct fs_context *fc)
 		uspi->s_csaddr = fs32_to_cpu(sb, usb1->fs_csaddr);
 
 	uspi->s_cssize = fs32_to_cpu(sb, usb1->fs_cssize);
+	if (uspi->s_fshift != ilog2(uspi->s_fsize)) {
+		pr_err("%s(): fragment size/shift mismatch (%u/%u)\n",
+		       __func__, uspi->s_fsize, uspi->s_fshift);
+		goto failed;
+	}
+	expected_cssize = (u64)uspi->s_ncg * sizeof(struct ufs_csum);
+	expected_cssize = (expected_cssize + uspi->s_fsize - 1) &
+		~((u64)uspi->s_fsize - 1);
+	if (!uspi->s_cssize || uspi->s_cssize != expected_cssize) {
+		pr_err("%s(): invalid cylinder summary size %u (expected %llu)\n",
+		       __func__, uspi->s_cssize, expected_cssize);
+		goto failed;
+	}
 	uspi->s_cgsize = fs32_to_cpu(sb, usb1->fs_cgsize);
 	uspi->s_ntrak = fs32_to_cpu(sb, usb1->fs_ntrak);
 	uspi->s_nsect = fs32_to_cpu(sb, usb1->fs_nsect);
-- 
2.43.0

                 reply	other threads:[~2026-07-01 21:57 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260701215700.822003-1-kudo3228@gmail.com \
    --to=kudo3228@gmail.com \
    --cc=kees@kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=viro@zeniv.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.