Skip to content

Commit 6121258

Browse files
LiBaokun96tytso
authored andcommitted
ext4: fix off by one issue in alloc_flex_gd()
Wesley reported an issue: ================================================================== EXT4-fs (dm-5): resizing filesystem from 7168 to 786432 blocks ------------[ cut here ]------------ kernel BUG at fs/ext4/resize.c:324! CPU: 9 UID: 0 PID: 3576 Comm: resize2fs Not tainted 6.11.0+ #27 RIP: 0010:ext4_resize_fs+0x1212/0x12d0 Call Trace: __ext4_ioctl+0x4e0/0x1800 ext4_ioctl+0x12/0x20 __x64_sys_ioctl+0x99/0xd0 x64_sys_call+0x1206/0x20d0 do_syscall_64+0x72/0x110 entry_SYSCALL_64_after_hwframe+0x76/0x7e ================================================================== While reviewing the patch, Honza found that when adjusting resize_bg in alloc_flex_gd(), it was possible for flex_gd->resize_bg to be bigger than flexbg_size. The reproduction of the problem requires the following: o_group = flexbg_size * 2 * n; o_size = (o_group + 1) * group_size; n_group: [o_group + flexbg_size, o_group + flexbg_size * 2) o_size = (n_group + 1) * group_size; Take n=0,flexbg_size=16 as an example: last:15 |o---------------|--------------n-| o_group:0 resize to n_group:30 The corresponding reproducer is: img=test.img rm -f $img truncate -s 600M $img mkfs.ext4 -F $img -b 1024 -G 16 8M dev=`losetup -f --show $img` mkdir -p /tmp/test mount $dev /tmp/test resize2fs $dev 248M Delete the problematic plus 1 to fix the issue, and add a WARN_ON_ONCE() to prevent the issue from happening again. [ Note: another reproucer which this commit fixes is: img=test.img rm -f $img truncate -s 25MiB $img mkfs.ext4 -b 4096 -E nodiscard,lazy_itable_init=0,lazy_journal_init=0 $img truncate -s 3GiB $img dev=`losetup -f --show $img` mkdir -p /tmp/test mount $dev /tmp/test resize2fs $dev 3G umount $dev losetup -d $dev -- TYT ] Reported-by: Wesley Hershberger <[email protected]> Closes: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/2081231 Reported-by: Stéphane Graber <[email protected]> Closes: https://lore.kernel.org/all/[email protected]/ Tested-by: Alexander Mikhalitsyn <[email protected]> Tested-by: Eric Sandeen <[email protected]> Fixes: 665d3e0 ("ext4: reduce unnecessary memory allocation in alloc_flex_gd()") Cc: [email protected] Signed-off-by: Baokun Li <[email protected]> Reviewed-by: Jan Kara <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Theodore Ts'o <[email protected]>
1 parent 04e6ce8 commit 6121258

File tree

1 file changed

+10
-8
lines changed

1 file changed

+10
-8
lines changed

fs/ext4/resize.c

+10-8
Original file line numberDiff line numberDiff line change
@@ -230,34 +230,36 @@ struct ext4_new_flex_group_data {
230230
#define MAX_RESIZE_BG 16384
231231

232232
/*
233-
* alloc_flex_gd() allocates a ext4_new_flex_group_data with size of
234-
* @flexbg_size.
233+
* alloc_flex_gd() allocates an ext4_new_flex_group_data that satisfies the
234+
* resizing from @o_group to @n_group, its size is typically @flexbg_size.
235235
*
236236
* Returns NULL on failure otherwise address of the allocated structure.
237237
*/
238238
static struct ext4_new_flex_group_data *alloc_flex_gd(unsigned int flexbg_size,
239239
ext4_group_t o_group, ext4_group_t n_group)
240240
{
241241
ext4_group_t last_group;
242+
unsigned int max_resize_bg;
242243
struct ext4_new_flex_group_data *flex_gd;
243244

244245
flex_gd = kmalloc(sizeof(*flex_gd), GFP_NOFS);
245246
if (flex_gd == NULL)
246247
goto out3;
247248

248-
if (unlikely(flexbg_size > MAX_RESIZE_BG))
249-
flex_gd->resize_bg = MAX_RESIZE_BG;
250-
else
251-
flex_gd->resize_bg = flexbg_size;
249+
max_resize_bg = umin(flexbg_size, MAX_RESIZE_BG);
250+
flex_gd->resize_bg = max_resize_bg;
252251

253252
/* Avoid allocating large 'groups' array if not needed */
254253
last_group = o_group | (flex_gd->resize_bg - 1);
255254
if (n_group <= last_group)
256-
flex_gd->resize_bg = 1 << fls(n_group - o_group + 1);
255+
flex_gd->resize_bg = 1 << fls(n_group - o_group);
257256
else if (n_group - last_group < flex_gd->resize_bg)
258-
flex_gd->resize_bg = 1 << max(fls(last_group - o_group + 1),
257+
flex_gd->resize_bg = 1 << max(fls(last_group - o_group),
259258
fls(n_group - last_group));
260259

260+
if (WARN_ON_ONCE(flex_gd->resize_bg > max_resize_bg))
261+
flex_gd->resize_bg = max_resize_bg;
262+
261263
flex_gd->groups = kmalloc_array(flex_gd->resize_bg,
262264
sizeof(struct ext4_new_group_data),
263265
GFP_NOFS);

0 commit comments

Comments
 (0)