Skip to content

badblocks: fix infinite loop due to incorrect rounding and overflow#1032

Open
blktests-ci[bot] wants to merge 1 commit into
linus-master_basefrom
series/1121577=>linus-master
Open

badblocks: fix infinite loop due to incorrect rounding and overflow#1032
blktests-ci[bot] wants to merge 1 commit into
linus-master_basefrom
series/1121577=>linus-master

Conversation

@blktests-ci

@blktests-ci blktests-ci Bot commented Jul 4, 2026

Copy link
Copy Markdown

Pull request for series with
subject: badblocks: fix infinite loop due to incorrect rounding and overflow
version: 5
url: https://patchwork.kernel.org/project/linux-block/list/?series=1121577

The roundup() and rounddown() macros return the rounded value but
do not modify their input in place. In _badblocks_set(),
_badblocks_clear(), and badblocks_check(), the return values were
being discarded, so s and target/next remained unrounded. Sectors
were then calculated from these unrounded values, which could make
sectors way too large (or zero), causing infinite loops in the
re_insert/re_clear/re_check loops.

This was confirmed with local syzkaller fuzzing against the nvdimm
ioctl path (ND_IOCTL_CLEAR_ERROR -> nvdimm_clear_badblocks_region()
-> badblocks_clear()), which reliably produces RCU stalls with the
looping task caught mid-loop:

  rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:
  rcu: rcu_preempt kthread starved for 21001 jiffies! g40229 f0x0 RCU_GP_WAIT_FQS(5)
  ...
  Call Trace:
   badblocks_clear+0x259/0xb10
   nvdimm_clear_badblocks_region+0x165/0x1e0 [libnvdimm]
   device_for_each_child+0x11e/0x1a0
   nd_ioctl+0x1413/0x1750 [libnvdimm]
   __x64_sys_ioctl+0x18e/0x210
   do_syscall_64+0x102/0x5a0

Fix this by properly capturing the return values of round_up()/
round_down() (the power-of-two variants, since 1 << bb->shift is
always a power of two -- roundup()/rounddown() use a division/
modulo internally, which is undesirable here). Also add overflow
checks (s > ULLONG_MAX - sectors) before the s + sectors addition
in all three functions, and handle the case where sectors becomes
zero after rounding.

The overflow check is done unconditionally, before the bb->shift
rounding block, rather than inside it. bb->shift == 0 is not just
an initial state -- __badblocks_init() sets it to 0 by default, and
drivers/md/md.c explicitly sets rdev->badblocks.shift back to 0 in
several paths -- so s + sectors needs the same overflow guard
whether or not rounding happens.

Signed-off-by: Ramesh Adhikari <adhikari.resume@gmail.com>
@blktests-ci

blktests-ci Bot commented Jul 4, 2026

Copy link
Copy Markdown
Author

Upstream branch: 87320be
series: https://patchwork.kernel.org/project/linux-block/list/?series=1121577
version: 5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant