From: Greg Kroah-Hartman Date: Mon, 25 Apr 2022 11:59:34 +0000 (+0200) Subject: 5.15-stable patches X-Git-Tag: v4.9.312~26 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=76fd6546e79ca6433e3c93fbdb6749da92d17962;p=thirdparty%2Fkernel%2Fstable-queue.git 5.15-stable patches added patches: ext4-doc-fix-incorrect-h_reserved-size.patch ext4-fix-fallocate-to-use-file_modified-to-update-permissions-consistently.patch ext4-fix-overhead-calculation-to-account-for-the-reserved-gdt-blocks.patch ext4-fix-symlink-file-size-not-match-to-file-content.patch ext4-fix-use-after-free-in-ext4_search_dir.patch ext4-force-overhead-calculation-if-the-s_overhead_cluster-makes-no-sense.patch ext4-limit-length-to-bitmap_maxbytes-blocksize-in-punch_hole.patch --- diff --git a/queue-5.15/ext4-doc-fix-incorrect-h_reserved-size.patch b/queue-5.15/ext4-doc-fix-incorrect-h_reserved-size.patch new file mode 100644 index 00000000000..57555832853 --- /dev/null +++ b/queue-5.15/ext4-doc-fix-incorrect-h_reserved-size.patch @@ -0,0 +1,32 @@ +From 7102ffe4c166ca0f5e35137e9f9de83768c2d27d Mon Sep 17 00:00:00 2001 +From: "wangjianjian (C)" +Date: Fri, 1 Apr 2022 20:07:35 +0800 +Subject: ext4, doc: fix incorrect h_reserved size + +From: wangjianjian (C) + +commit 7102ffe4c166ca0f5e35137e9f9de83768c2d27d upstream. + +According to document and code, ext4_xattr_header's size is 32 bytes, so +h_reserved size should be 3. + +Signed-off-by: Wang Jianjian +Link: https://lore.kernel.org/r/92fcc3a6-7d77-8c09-4126-377fcb4c46a5@huawei.com +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + Documentation/filesystems/ext4/attributes.rst | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/Documentation/filesystems/ext4/attributes.rst ++++ b/Documentation/filesystems/ext4/attributes.rst +@@ -76,7 +76,7 @@ The beginning of an extended attribute b + - Checksum of the extended attribute block. + * - 0x14 + - \_\_u32 +- - h\_reserved[2] ++ - h\_reserved[3] + - Zero. + + The checksum is calculated against the FS UUID, the 64-bit block number diff --git a/queue-5.15/ext4-fix-fallocate-to-use-file_modified-to-update-permissions-consistently.patch b/queue-5.15/ext4-fix-fallocate-to-use-file_modified-to-update-permissions-consistently.patch new file mode 100644 index 00000000000..25e7f0da8fa --- /dev/null +++ b/queue-5.15/ext4-fix-fallocate-to-use-file_modified-to-update-permissions-consistently.patch @@ -0,0 +1,170 @@ +From ad5cd4f4ee4d5fcdb1bfb7a0c073072961e70783 Mon Sep 17 00:00:00 2001 +From: "Darrick J. Wong" +Date: Tue, 8 Mar 2022 10:50:43 -0800 +Subject: ext4: fix fallocate to use file_modified to update permissions consistently + +From: Darrick J. Wong + +commit ad5cd4f4ee4d5fcdb1bfb7a0c073072961e70783 upstream. + +Since the initial introduction of (posix) fallocate back at the turn of +the century, it has been possible to use this syscall to change the +user-visible contents of files. This can happen by extending the file +size during a preallocation, or through any of the newer modes (punch, +zero, collapse, insert range). Because the call can be used to change +file contents, we should treat it like we do any other modification to a +file -- update the mtime, and drop set[ug]id privileges/capabilities. + +The VFS function file_modified() does all this for us if pass it a +locked inode, so let's make fallocate drop permissions correctly. + +Signed-off-by: Darrick J. Wong +Link: https://lore.kernel.org/r/20220308185043.GA117678@magnolia +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/ext4.h | 2 +- + fs/ext4/extents.c | 32 +++++++++++++++++++++++++------- + fs/ext4/inode.c | 7 ++++++- + 3 files changed, 32 insertions(+), 9 deletions(-) + +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -3027,7 +3027,7 @@ extern int ext4_inode_attach_jinode(stru + extern int ext4_can_truncate(struct inode *inode); + extern int ext4_truncate(struct inode *); + extern int ext4_break_layouts(struct inode *); +-extern int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length); ++extern int ext4_punch_hole(struct file *file, loff_t offset, loff_t length); + extern void ext4_set_inode_flags(struct inode *, bool init); + extern int ext4_alloc_da_blocks(struct inode *inode); + extern void ext4_set_aops(struct inode *inode); +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -4504,9 +4504,9 @@ retry: + return ret > 0 ? ret2 : ret; + } + +-static int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len); ++static int ext4_collapse_range(struct file *file, loff_t offset, loff_t len); + +-static int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len); ++static int ext4_insert_range(struct file *file, loff_t offset, loff_t len); + + static long ext4_zero_range(struct file *file, loff_t offset, + loff_t len, int mode) +@@ -4578,6 +4578,10 @@ static long ext4_zero_range(struct file + /* Wait all existing dio workers, newcomers will block on i_mutex */ + inode_dio_wait(inode); + ++ ret = file_modified(file); ++ if (ret) ++ goto out_mutex; ++ + /* Preallocate the range including the unaligned edges */ + if (partial_begin || partial_end) { + ret = ext4_alloc_file_blocks(file, +@@ -4696,7 +4700,7 @@ long ext4_fallocate(struct file *file, i + ext4_fc_start_update(inode); + + if (mode & FALLOC_FL_PUNCH_HOLE) { +- ret = ext4_punch_hole(inode, offset, len); ++ ret = ext4_punch_hole(file, offset, len); + goto exit; + } + +@@ -4705,12 +4709,12 @@ long ext4_fallocate(struct file *file, i + goto exit; + + if (mode & FALLOC_FL_COLLAPSE_RANGE) { +- ret = ext4_collapse_range(inode, offset, len); ++ ret = ext4_collapse_range(file, offset, len); + goto exit; + } + + if (mode & FALLOC_FL_INSERT_RANGE) { +- ret = ext4_insert_range(inode, offset, len); ++ ret = ext4_insert_range(file, offset, len); + goto exit; + } + +@@ -4746,6 +4750,10 @@ long ext4_fallocate(struct file *file, i + /* Wait all existing dio workers, newcomers will block on i_mutex */ + inode_dio_wait(inode); + ++ ret = file_modified(file); ++ if (ret) ++ goto out; ++ + ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, flags); + if (ret) + goto out; +@@ -5248,8 +5256,9 @@ out: + * This implements the fallocate's collapse range functionality for ext4 + * Returns: 0 and non-zero on error. + */ +-static int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len) ++static int ext4_collapse_range(struct file *file, loff_t offset, loff_t len) + { ++ struct inode *inode = file_inode(file); + struct super_block *sb = inode->i_sb; + struct address_space *mapping = inode->i_mapping; + ext4_lblk_t punch_start, punch_stop; +@@ -5301,6 +5310,10 @@ static int ext4_collapse_range(struct in + /* Wait for existing dio to complete */ + inode_dio_wait(inode); + ++ ret = file_modified(file); ++ if (ret) ++ goto out_mutex; ++ + /* + * Prevent page faults from reinstantiating pages we have released from + * page cache. +@@ -5394,8 +5407,9 @@ out_mutex: + * by len bytes. + * Returns 0 on success, error otherwise. + */ +-static int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len) ++static int ext4_insert_range(struct file *file, loff_t offset, loff_t len) + { ++ struct inode *inode = file_inode(file); + struct super_block *sb = inode->i_sb; + struct address_space *mapping = inode->i_mapping; + handle_t *handle; +@@ -5452,6 +5466,10 @@ static int ext4_insert_range(struct inod + /* Wait for existing dio to complete */ + inode_dio_wait(inode); + ++ ret = file_modified(file); ++ if (ret) ++ goto out_mutex; ++ + /* + * Prevent page faults from reinstantiating pages we have released from + * page cache. +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -3939,8 +3939,9 @@ int ext4_break_layouts(struct inode *ino + * Returns: 0 on success or negative on failure + */ + +-int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length) ++int ext4_punch_hole(struct file *file, loff_t offset, loff_t length) + { ++ struct inode *inode = file_inode(file); + struct super_block *sb = inode->i_sb; + ext4_lblk_t first_block, stop_block; + struct address_space *mapping = inode->i_mapping; +@@ -4002,6 +4003,10 @@ int ext4_punch_hole(struct inode *inode, + /* Wait all existing dio workers, newcomers will block on i_mutex */ + inode_dio_wait(inode); + ++ ret = file_modified(file); ++ if (ret) ++ goto out_mutex; ++ + /* + * Prevent page faults from reinstantiating pages we have released from + * page cache. diff --git a/queue-5.15/ext4-fix-overhead-calculation-to-account-for-the-reserved-gdt-blocks.patch b/queue-5.15/ext4-fix-overhead-calculation-to-account-for-the-reserved-gdt-blocks.patch new file mode 100644 index 00000000000..6f82163747d --- /dev/null +++ b/queue-5.15/ext4-fix-overhead-calculation-to-account-for-the-reserved-gdt-blocks.patch @@ -0,0 +1,35 @@ +From 10b01ee92df52c8d7200afead4d5e5f55a5c58b1 Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +Date: Thu, 14 Apr 2022 21:31:27 -0400 +Subject: ext4: fix overhead calculation to account for the reserved gdt blocks + +From: Theodore Ts'o + +commit 10b01ee92df52c8d7200afead4d5e5f55a5c58b1 upstream. + +The kernel calculation was underestimating the overhead by not taking +into account the reserved gdt blocks. With this change, the overhead +calculated by the kernel matches the overhead calculation in mke2fs. + +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/super.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -3697,9 +3697,11 @@ static int count_overhead(struct super_b + ext4_fsblk_t first_block, last_block, b; + ext4_group_t i, ngroups = ext4_get_groups_count(sb); + int s, j, count = 0; ++ int has_super = ext4_bg_has_super(sb, grp); + + if (!ext4_has_feature_bigalloc(sb)) +- return (ext4_bg_has_super(sb, grp) + ext4_bg_num_gdb(sb, grp) + ++ return (has_super + ext4_bg_num_gdb(sb, grp) + ++ (has_super ? le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) : 0) + + sbi->s_itb_per_group + 2); + + first_block = le32_to_cpu(sbi->s_es->s_first_data_block) + diff --git a/queue-5.15/ext4-fix-symlink-file-size-not-match-to-file-content.patch b/queue-5.15/ext4-fix-symlink-file-size-not-match-to-file-content.patch new file mode 100644 index 00000000000..7e0fad2fad0 --- /dev/null +++ b/queue-5.15/ext4-fix-symlink-file-size-not-match-to-file-content.patch @@ -0,0 +1,51 @@ +From a2b0b205d125f27cddfb4f7280e39affdaf46686 Mon Sep 17 00:00:00 2001 +From: Ye Bin +Date: Mon, 21 Mar 2022 22:44:38 +0800 +Subject: ext4: fix symlink file size not match to file content + +From: Ye Bin + +commit a2b0b205d125f27cddfb4f7280e39affdaf46686 upstream. + +We got issue as follows: +[home]# fsck.ext4 -fn ram0yb +e2fsck 1.45.6 (20-Mar-2020) +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Symlink /p3/d14/d1a/l3d (inode #3494) is invalid. +Clear? no +Entry 'l3d' in /p3/d14/d1a (3383) has an incorrect filetype (was 7, should be 0). +Fix? no + +As the symlink file size does not match the file content. If the writeback +of the symlink data block failed, ext4_finish_bio() handles the end of IO. +However this function fails to mark the buffer with BH_write_io_error and +so when unmount does journal checkpoint it cannot detect the writeback +error and will cleanup the journal. Thus we've lost the correct data in the +journal area. To solve this issue, mark the buffer as BH_write_io_error in +ext4_finish_bio(). + +Cc: stable@kernel.org +Signed-off-by: Ye Bin +Reviewed-by: Jan Kara +Link: https://lore.kernel.org/r/20220321144438.201685-1-yebin10@huawei.com +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/page-io.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/fs/ext4/page-io.c ++++ b/fs/ext4/page-io.c +@@ -134,8 +134,10 @@ static void ext4_finish_bio(struct bio * + continue; + } + clear_buffer_async_write(bh); +- if (bio->bi_status) ++ if (bio->bi_status) { ++ set_buffer_write_io_error(bh); + buffer_io_error(bh); ++ } + } while ((bh = bh->b_this_page) != head); + spin_unlock_irqrestore(&head->b_uptodate_lock, flags); + if (!under_io) { diff --git a/queue-5.15/ext4-fix-use-after-free-in-ext4_search_dir.patch b/queue-5.15/ext4-fix-use-after-free-in-ext4_search_dir.patch new file mode 100644 index 00000000000..b45c9da2239 --- /dev/null +++ b/queue-5.15/ext4-fix-use-after-free-in-ext4_search_dir.patch @@ -0,0 +1,125 @@ +From c186f0887fe7061a35cebef024550ec33ef8fbd8 Mon Sep 17 00:00:00 2001 +From: Ye Bin +Date: Thu, 24 Mar 2022 14:48:16 +0800 +Subject: ext4: fix use-after-free in ext4_search_dir + +From: Ye Bin + +commit c186f0887fe7061a35cebef024550ec33ef8fbd8 upstream. + +We got issue as follows: +EXT4-fs (loop0): mounted filesystem without journal. Opts: ,errors=continue +================================================================== +BUG: KASAN: use-after-free in ext4_search_dir fs/ext4/namei.c:1394 [inline] +BUG: KASAN: use-after-free in search_dirblock fs/ext4/namei.c:1199 [inline] +BUG: KASAN: use-after-free in __ext4_find_entry+0xdca/0x1210 fs/ext4/namei.c:1553 +Read of size 1 at addr ffff8881317c3005 by task syz-executor117/2331 + +CPU: 1 PID: 2331 Comm: syz-executor117 Not tainted 5.10.0+ #1 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org 04/01/2014 +Call Trace: + __dump_stack lib/dump_stack.c:83 [inline] + dump_stack+0x144/0x187 lib/dump_stack.c:124 + print_address_description+0x7d/0x630 mm/kasan/report.c:387 + __kasan_report+0x132/0x190 mm/kasan/report.c:547 + kasan_report+0x47/0x60 mm/kasan/report.c:564 + ext4_search_dir fs/ext4/namei.c:1394 [inline] + search_dirblock fs/ext4/namei.c:1199 [inline] + __ext4_find_entry+0xdca/0x1210 fs/ext4/namei.c:1553 + ext4_lookup_entry fs/ext4/namei.c:1622 [inline] + ext4_lookup+0xb8/0x3a0 fs/ext4/namei.c:1690 + __lookup_hash+0xc5/0x190 fs/namei.c:1451 + do_rmdir+0x19e/0x310 fs/namei.c:3760 + do_syscall_64+0x33/0x40 arch/x86/entry/common.c:46 + entry_SYSCALL_64_after_hwframe+0x44/0xa9 +RIP: 0033:0x445e59 +Code: 4d c7 fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 1b c7 fb ff c3 66 2e 0f 1f 84 00 00 00 00 +RSP: 002b:00007fff2277fac8 EFLAGS: 00000246 ORIG_RAX: 0000000000000054 +RAX: ffffffffffffffda RBX: 0000000000400280 RCX: 0000000000445e59 +RDX: 0000000000000000 RSI: 0000000000000000 RDI: 00000000200000c0 +RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000002 +R10: 00007fff2277f990 R11: 0000000000000246 R12: 0000000000000000 +R13: 431bde82d7b634db R14: 0000000000000000 R15: 0000000000000000 + +The buggy address belongs to the page: +page:0000000048cd3304 refcount:0 mapcount:0 mapping:0000000000000000 index:0x1 pfn:0x1317c3 +flags: 0x200000000000000() +raw: 0200000000000000 ffffea0004526588 ffffea0004528088 0000000000000000 +raw: 0000000000000001 0000000000000000 00000000ffffffff 0000000000000000 +page dumped because: kasan: bad access detected + +Memory state around the buggy address: + ffff8881317c2f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + ffff8881317c2f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +>ffff8881317c3000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ^ + ffff8881317c3080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ffff8881317c3100: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff +================================================================== + +ext4_search_dir: + ... + de = (struct ext4_dir_entry_2 *)search_buf; + dlimit = search_buf + buf_size; + while ((char *) de < dlimit) { + ... + if ((char *) de + de->name_len <= dlimit && + ext4_match(dir, fname, de)) { + ... + } + ... + de_len = ext4_rec_len_from_disk(de->rec_len, dir->i_sb->s_blocksize); + if (de_len <= 0) + return -1; + offset += de_len; + de = (struct ext4_dir_entry_2 *) ((char *) de + de_len); + } + +Assume: +de=0xffff8881317c2fff +dlimit=0x0xffff8881317c3000 + +If read 'de->name_len' which address is 0xffff8881317c3005, obviously is +out of range, then will trigger use-after-free. +To solve this issue, 'dlimit' must reserve 8 bytes, as we will read +'de->name_len' to judge if '(char *) de + de->name_len' out of range. + +Signed-off-by: Ye Bin +Reviewed-by: Jan Kara +Link: https://lore.kernel.org/r/20220324064816.1209985-1-yebin10@huawei.com +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/ext4.h | 4 ++++ + fs/ext4/namei.c | 4 ++-- + 2 files changed, 6 insertions(+), 2 deletions(-) + +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -2267,6 +2267,10 @@ static inline int ext4_forced_shutdown(s + * Structure of a directory entry + */ + #define EXT4_NAME_LEN 255 ++/* ++ * Base length of the ext4 directory entry excluding the name length ++ */ ++#define EXT4_BASE_DIR_LEN (sizeof(struct ext4_dir_entry_2) - EXT4_NAME_LEN) + + struct ext4_dir_entry { + __le32 inode; /* Inode number */ +--- a/fs/ext4/namei.c ++++ b/fs/ext4/namei.c +@@ -1466,10 +1466,10 @@ int ext4_search_dir(struct buffer_head * + + de = (struct ext4_dir_entry_2 *)search_buf; + dlimit = search_buf + buf_size; +- while ((char *) de < dlimit) { ++ while ((char *) de < dlimit - EXT4_BASE_DIR_LEN) { + /* this code is executed quadratically often */ + /* do minimal checking `by hand' */ +- if ((char *) de + de->name_len <= dlimit && ++ if (de->name + de->name_len <= dlimit && + ext4_match(dir, fname, de)) { + /* found a match - just to be sure, do + * a full check */ diff --git a/queue-5.15/ext4-force-overhead-calculation-if-the-s_overhead_cluster-makes-no-sense.patch b/queue-5.15/ext4-force-overhead-calculation-if-the-s_overhead_cluster-makes-no-sense.patch new file mode 100644 index 00000000000..c143d531c76 --- /dev/null +++ b/queue-5.15/ext4-force-overhead-calculation-if-the-s_overhead_cluster-makes-no-sense.patch @@ -0,0 +1,44 @@ +From 85d825dbf4899a69407338bae462a59aa9a37326 Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +Date: Thu, 14 Apr 2022 21:57:49 -0400 +Subject: ext4: force overhead calculation if the s_overhead_cluster makes no sense + +From: Theodore Ts'o + +commit 85d825dbf4899a69407338bae462a59aa9a37326 upstream. + +If the file system does not use bigalloc, calculating the overhead is +cheap, so force the recalculation of the overhead so we don't have to +trust the precalculated overhead in the superblock. + +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/super.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -4788,9 +4788,18 @@ no_journal: + * Get the # of file system overhead blocks from the + * superblock if present. + */ +- if (es->s_overhead_clusters) +- sbi->s_overhead = le32_to_cpu(es->s_overhead_clusters); +- else { ++ sbi->s_overhead = le32_to_cpu(es->s_overhead_clusters); ++ /* ignore the precalculated value if it is ridiculous */ ++ if (sbi->s_overhead > ext4_blocks_count(es)) ++ sbi->s_overhead = 0; ++ /* ++ * If the bigalloc feature is not enabled recalculating the ++ * overhead doesn't take long, so we might as well just redo ++ * it to make sure we are using the correct value. ++ */ ++ if (!ext4_has_feature_bigalloc(sb)) ++ sbi->s_overhead = 0; ++ if (sbi->s_overhead == 0) { + err = ext4_calculate_overhead(sb); + if (err) + goto failed_mount_wq; diff --git a/queue-5.15/ext4-limit-length-to-bitmap_maxbytes-blocksize-in-punch_hole.patch b/queue-5.15/ext4-limit-length-to-bitmap_maxbytes-blocksize-in-punch_hole.patch new file mode 100644 index 00000000000..f6187d748e5 --- /dev/null +++ b/queue-5.15/ext4-limit-length-to-bitmap_maxbytes-blocksize-in-punch_hole.patch @@ -0,0 +1,60 @@ +From 2da376228a2427501feb9d15815a45dbdbdd753e Mon Sep 17 00:00:00 2001 +From: Tadeusz Struk +Date: Thu, 31 Mar 2022 13:05:15 -0700 +Subject: ext4: limit length to bitmap_maxbytes - blocksize in punch_hole + +From: Tadeusz Struk + +commit 2da376228a2427501feb9d15815a45dbdbdd753e upstream. + +Syzbot found an issue [1] in ext4_fallocate(). +The C reproducer [2] calls fallocate(), passing size 0xffeffeff000ul, +and offset 0x1000000ul, which, when added together exceed the +bitmap_maxbytes for the inode. This triggers a BUG in +ext4_ind_remove_space(). According to the comments in this function +the 'end' parameter needs to be one block after the last block to be +removed. In the case when the BUG is triggered it points to the last +block. Modify the ext4_punch_hole() function and add constraint that +caps the length to satisfy the one before laster block requirement. + +LINK: [1] https://syzkaller.appspot.com/bug?id=b80bd9cf348aac724a4f4dff251800106d721331 +LINK: [2] https://syzkaller.appspot.com/text?tag=ReproC&x=14ba0238700000 + +Fixes: a4bb6b64e39a ("ext4: enable "punch hole" functionality") +Reported-by: syzbot+7a806094edd5d07ba029@syzkaller.appspotmail.com +Signed-off-by: Tadeusz Struk +Link: https://lore.kernel.org/r/20220331200515.153214-1-tadeusz.struk@linaro.org +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + fs/ext4/inode.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -3945,7 +3945,8 @@ int ext4_punch_hole(struct file *file, l + struct super_block *sb = inode->i_sb; + ext4_lblk_t first_block, stop_block; + struct address_space *mapping = inode->i_mapping; +- loff_t first_block_offset, last_block_offset; ++ loff_t first_block_offset, last_block_offset, max_length; ++ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); + handle_t *handle; + unsigned int credits; + int ret = 0, ret2 = 0; +@@ -3988,6 +3989,14 @@ int ext4_punch_hole(struct file *file, l + offset; + } + ++ /* ++ * For punch hole the length + offset needs to be within one block ++ * before last range. Adjust the length if it goes beyond that limit. ++ */ ++ max_length = sbi->s_bitmap_maxbytes - inode->i_sb->s_blocksize; ++ if (offset + length > max_length) ++ length = max_length - offset; ++ + if (offset & (sb->s_blocksize - 1) || + (offset + length) & (sb->s_blocksize - 1)) { + /* diff --git a/queue-5.15/series b/queue-5.15/series index 0ce1777aeca..a4c6294959a 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -110,3 +110,10 @@ kvm-nvmx-defer-apicv-updates-while-l2-is-active-until-l1-is-active.patch kvm-svm-flush-when-freeing-encrypted-pages-even-on-sme_coherent-cpus.patch netfilter-conntrack-convert-to-refcount_t-api.patch netfilter-conntrack-avoid-useless-indirection-during-conntrack-destruction.patch +ext4-fix-fallocate-to-use-file_modified-to-update-permissions-consistently.patch +ext4-fix-symlink-file-size-not-match-to-file-content.patch +ext4-fix-use-after-free-in-ext4_search_dir.patch +ext4-limit-length-to-bitmap_maxbytes-blocksize-in-punch_hole.patch +ext4-doc-fix-incorrect-h_reserved-size.patch +ext4-fix-overhead-calculation-to-account-for-the-reserved-gdt-blocks.patch +ext4-force-overhead-calculation-if-the-s_overhead_cluster-makes-no-sense.patch