public inbox for ntfs3@lists.linux.dev
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: patches@lists.linux.dev, stable@vger.kernel.org
Cc: Pedro Demarchi Gomes <pedrodemargomes@gmail.com>,
	syzbot+f4f84b57a01d6b8364ad@syzkaller.appspotmail.com,
	Konstantin Komarov <almaz.alexandrovich@paragon-software.com>,
	Sasha Levin <sashal@kernel.org>,
	ntfs3@lists.linux.dev
Subject: [PATCH AUTOSEL 6.18-6.6] ntfs: set dummy blocksize to read boot_block when mounting
Date: Mon,  8 Dec 2025 19:15:31 -0500	[thread overview]
Message-ID: <20251209001610.611575-39-sashal@kernel.org> (raw)
In-Reply-To: <20251209001610.611575-1-sashal@kernel.org>

From: Pedro Demarchi Gomes <pedrodemargomes@gmail.com>

[ Upstream commit d1693a7d5a38acf6424235a6070bcf5b186a360d ]

When mounting, sb->s_blocksize is used to read the boot_block without
being defined or validated. Set a dummy blocksize before attempting to
read the boot_block.

The issue can be triggered with the following syz reproducer:

  mkdirat(0xffffffffffffff9c, &(0x7f0000000080)='./file1\x00', 0x0)
  r4 = openat$nullb(0xffffffffffffff9c, &(0x7f0000000040), 0x121403, 0x0)
  ioctl$FS_IOC_SETFLAGS(r4, 0x40081271, &(0x7f0000000980)=0x4000)
  mount(&(0x7f0000000140)=@nullb, &(0x7f0000000040)='./cgroup\x00',
        &(0x7f0000000000)='ntfs3\x00', 0x2208004, 0x0)
  syz_clone(0x88200200, 0x0, 0x0, 0x0, 0x0, 0x0)

Here, the ioctl sets the bdev block size to 16384. During mount,
get_tree_bdev_flags() calls sb_set_blocksize(sb, block_size(bdev)),
but since block_size(bdev) > PAGE_SIZE, sb_set_blocksize() leaves
sb->s_blocksize at zero.

Later, ntfs_init_from_boot() attempts to read the boot_block while
sb->s_blocksize is still zero, which triggers the bug.

Reported-by: syzbot+f4f84b57a01d6b8364ad@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=f4f84b57a01d6b8364ad
Signed-off-by: Pedro Demarchi Gomes <pedrodemargomes@gmail.com>
[almaz.alexandrovich@paragon-software.com: changed comment style, added
return value handling]
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

Now I have a complete picture of the issue. Let me summarize my
analysis:

## Summary of Analysis

### The Bug

The commit fixes a bug in ntfs3's `ntfs_init_from_boot()` function where
`ntfs_bread()` is called to read the boot block **before**
`sb->s_blocksize` is properly set.

### Root Cause Analysis

1. **Mount Flow**: When mounting an ntfs3 filesystem:
   - `get_tree_bdev()` calls `setup_bdev_super()` which calls
     `sb_set_blocksize(sb, block_size(bdev))`
   - If `block_size(bdev) > PAGE_SIZE` (which can happen via ioctl
     `FS_IOC_SETFLAGS` setting bdev block size to 16384 as shown in the
     reproducer), and the filesystem doesn't have `FS_LBS` flag,
     `sb_set_blocksize()` returns 0 and leaves `sb->s_blocksize = 0`

2. **The Crash Path**: In `ntfs_init_from_boot()`:
  ```c
  sbi->volume.blocks = dev_size >> PAGE_SHIFT;
  // sb->s_blocksize is 0 here!
  bh = ntfs_bread(sb, boot_block);  // Uses sb->s_blocksize = 0
  ```

3. **Cascade to Infinite Loop**:
   - `ntfs_bread()` → `sb_bread_unmovable()` → `__bread_gfp()` with
     size=0
   - `bdev_getblk()` → `__getblk_slow()` → `grow_buffers()` →
     `grow_dev_folio()` → `folio_alloc_buffers()`
   - In `folio_alloc_buffers()`: `while ((offset -= size) >= 0)` with
     size=0 causes infinite loop

### The Fix

The fix adds a call to `sb_min_blocksize(sb, PAGE_SIZE)` before
attempting to read the boot block:

```c
/* Set dummy blocksize to read boot_block. */
if (!sb_min_blocksize(sb, PAGE_SIZE)) {
    return -EINVAL;
}
```

This ensures:
1. `sb->s_blocksize` is set to at least the device's logical block size,
   capped at PAGE_SIZE
2. If this fails, mount fails gracefully with `-EINVAL` instead of
   hanging

### Backport Assessment

**STRONG YES signals:**
1. ✅ **Fixes a real crash/hang** - System hangs due to infinite loop in
   `folio_alloc_buffers()`
2. ✅ **Syzbot reported** - Has syzkaller reproducer
   (`f4f84b57a01d6b8364ad`)
3. ✅ **Small, surgical fix** - Only 4 lines added
4. ✅ **Clear, obvious fix** - Sets blocksize before using it for reads
5. ✅ **Uses well-established API** - `sb_min_blocksize()` is a standard
   helper used by many filesystems
6. ✅ **Affects production users** - ntfs3 is widely used (included since
   5.15)
7. ✅ **Denial of Service potential** - A local user can trigger the hang

**Risk Assessment:**
- **Very Low Risk**: The fix adds a safety check before an I/O operation
- **No behavioral change** for normal cases - the blocksize would have
  been set to PAGE_SIZE anyway after successful boot read
- **Graceful failure** if `sb_min_blocksize()` fails (which would be
  very rare in practice)

**Stable Trees Affected:**
- All stable trees with ntfs3: 5.15.y, 6.1.y, 6.6.y, 6.10.y, 6.11.y,
  etc.
- The bug has existed since ntfs3 was introduced in v5.15
- The recent `FS_LBS` change (March 2025) made it easier to trigger but
  the underlying issue predates it

**Dependencies:**
- The fix is standalone and uses existing kernel APIs
- No other patches required for backport
- `sb_min_blocksize()` has been available since at least 2.6.x

**YES**

 fs/ntfs3/super.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c
index ddff94c091b8c..e6c0908e27c29 100644
--- a/fs/ntfs3/super.c
+++ b/fs/ntfs3/super.c
@@ -933,6 +933,11 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
 
 	sbi->volume.blocks = dev_size >> PAGE_SHIFT;
 
+	/* Set dummy blocksize to read boot_block. */
+	if (!sb_min_blocksize(sb, PAGE_SIZE)) {
+		return -EINVAL;
+	}
+
 read_boot:
 	bh = ntfs_bread(sb, boot_block);
 	if (!bh)
-- 
2.51.0


  parent reply	other threads:[~2025-12-09  0:18 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20251209001610.611575-1-sashal@kernel.org>
2025-12-09  0:14 ` [PATCH AUTOSEL 6.18-6.6] fs/ntfs3: fix KMSAN uninit-value in ni_create_attr_list Sasha Levin
2025-12-09  0:15 ` [PATCH AUTOSEL 6.18-5.15] fs/ntfs3: Support timestamps prior to epoch Sasha Levin
2025-12-09  0:15 ` Sasha Levin [this message]
     [not found] <20251206140252.645973-1-sashal@kernel.org>
2025-12-06 14:02 ` [PATCH AUTOSEL 6.18-6.6] ntfs: set dummy blocksize to read boot_block when mounting Sasha Levin

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=20251209001610.611575-39-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=almaz.alexandrovich@paragon-software.com \
    --cc=ntfs3@lists.linux.dev \
    --cc=patches@lists.linux.dev \
    --cc=pedrodemargomes@gmail.com \
    --cc=stable@vger.kernel.org \
    --cc=syzbot+f4f84b57a01d6b8364ad@syzkaller.appspotmail.com \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox