]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 3 Apr 2023 13:41:52 +0000 (15:41 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 3 Apr 2023 13:41:52 +0000 (15:41 +0200)
added patches:
ext4-fix-kernel-bug-in-ext4_write_inline_data_end.patch
gfs2-always-check-inode-size-of-inline-inodes.patch

queue-5.10/ext4-fix-kernel-bug-in-ext4_write_inline_data_end.patch [new file with mode: 0644]
queue-5.10/gfs2-always-check-inode-size-of-inline-inodes.patch [new file with mode: 0644]
queue-5.10/series

diff --git a/queue-5.10/ext4-fix-kernel-bug-in-ext4_write_inline_data_end.patch b/queue-5.10/ext4-fix-kernel-bug-in-ext4_write_inline_data_end.patch
new file mode 100644 (file)
index 0000000..41de3ea
--- /dev/null
@@ -0,0 +1,110 @@
+From 5c099c4fdc438014d5893629e70a8ba934433ee8 Mon Sep 17 00:00:00 2001
+From: Ye Bin <yebin10@huawei.com>
+Date: Tue, 6 Dec 2022 22:41:34 +0800
+Subject: ext4: fix kernel BUG in 'ext4_write_inline_data_end()'
+
+From: Ye Bin <yebin10@huawei.com>
+
+commit 5c099c4fdc438014d5893629e70a8ba934433ee8 upstream.
+
+Syzbot report follow issue:
+------------[ cut here ]------------
+kernel BUG at fs/ext4/inline.c:227!
+invalid opcode: 0000 [#1] PREEMPT SMP KASAN
+CPU: 1 PID: 3629 Comm: syz-executor212 Not tainted 6.1.0-rc5-syzkaller-00018-g59d0d52c30d4 #0
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/26/2022
+RIP: 0010:ext4_write_inline_data+0x344/0x3e0 fs/ext4/inline.c:227
+RSP: 0018:ffffc90003b3f368 EFLAGS: 00010293
+RAX: 0000000000000000 RBX: ffff8880704e16c0 RCX: 0000000000000000
+RDX: ffff888021763a80 RSI: ffffffff821e31a4 RDI: 0000000000000006
+RBP: 000000000006818e R08: 0000000000000006 R09: 0000000000068199
+R10: 0000000000000079 R11: 0000000000000000 R12: 000000000000000b
+R13: 0000000000068199 R14: ffffc90003b3f408 R15: ffff8880704e1c82
+FS:  000055555723e3c0(0000) GS:ffff8880b9b00000(0000) knlGS:0000000000000000
+CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: 00007fffe8ac9080 CR3: 0000000079f81000 CR4: 0000000000350ee0
+Call Trace:
+ <TASK>
+ ext4_write_inline_data_end+0x2a3/0x12f0 fs/ext4/inline.c:768
+ ext4_write_end+0x242/0xdd0 fs/ext4/inode.c:1313
+ ext4_da_write_end+0x3ed/0xa30 fs/ext4/inode.c:3063
+ generic_perform_write+0x316/0x570 mm/filemap.c:3764
+ ext4_buffered_write_iter+0x15b/0x460 fs/ext4/file.c:285
+ ext4_file_write_iter+0x8bc/0x16e0 fs/ext4/file.c:700
+ call_write_iter include/linux/fs.h:2191 [inline]
+ do_iter_readv_writev+0x20b/0x3b0 fs/read_write.c:735
+ do_iter_write+0x182/0x700 fs/read_write.c:861
+ vfs_iter_write+0x74/0xa0 fs/read_write.c:902
+ iter_file_splice_write+0x745/0xc90 fs/splice.c:686
+ do_splice_from fs/splice.c:764 [inline]
+ direct_splice_actor+0x114/0x180 fs/splice.c:931
+ splice_direct_to_actor+0x335/0x8a0 fs/splice.c:886
+ do_splice_direct+0x1ab/0x280 fs/splice.c:974
+ do_sendfile+0xb19/0x1270 fs/read_write.c:1255
+ __do_sys_sendfile64 fs/read_write.c:1323 [inline]
+ __se_sys_sendfile64 fs/read_write.c:1309 [inline]
+ __x64_sys_sendfile64+0x1d0/0x210 fs/read_write.c:1309
+ do_syscall_x64 arch/x86/entry/common.c:50 [inline]
+ do_syscall_64+0x39/0xb0 arch/x86/entry/common.c:80
+ entry_SYSCALL_64_after_hwframe+0x63/0xcd
+---[ end trace 0000000000000000 ]---
+
+Above issue may happens as follows:
+ext4_da_write_begin
+  ext4_da_write_inline_data_begin
+    ext4_da_convert_inline_data_to_extent
+      ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
+ext4_da_write_end
+
+ext4_run_li_request
+  ext4_mb_prefetch
+    ext4_read_block_bitmap_nowait
+      ext4_validate_block_bitmap
+        ext4_mark_group_bitmap_corrupted(sb, block_group, EXT4_GROUP_INFO_BBITMAP_CORRUPT)
+        percpu_counter_sub(&sbi->s_freeclusters_counter,grp->bb_free);
+         -> sbi->s_freeclusters_counter become zero
+ext4_da_write_begin
+  if (ext4_nonda_switch(inode->i_sb)) -> As freeclusters_counter is zero will return true
+    *fsdata = (void *)FALL_BACK_TO_NONDELALLOC;
+    ext4_write_begin
+ext4_da_write_end
+  if (write_mode == FALL_BACK_TO_NONDELALLOC)
+    ext4_write_end
+      if (inline_data)
+        ext4_write_inline_data_end
+         ext4_write_inline_data
+           BUG_ON(pos + len > EXT4_I(inode)->i_inline_size);
+           -> As inode is already convert to extent, so 'pos + len' > inline_size
+          -> then trigger BUG.
+
+To solve this issue, instead of checking ext4_has_inline_data() which
+is only cleared after data has been written back, check the
+EXT4_STATE_MAY_INLINE_DATA flag in ext4_write_end().
+
+Fixes: f19d5870cbf7 ("ext4: add normal write support for inline data")
+Reported-by: syzbot+4faa160fa96bfba639f8@syzkaller.appspotmail.com
+Reported-by: Jun Nie <jun.nie@linaro.org>
+Signed-off-by: Ye Bin <yebin10@huawei.com>
+Link: https://lore.kernel.org/r/20221206144134.1919987-1-yebin@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Cc: stable@kernel.org
+[ta: Fix conflict in if expression and use the local variable inline_data
+as it is initialized with ext4_has_inline_data(inode) anyway.]
+Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ext4/inode.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -1303,7 +1303,8 @@ static int ext4_write_end(struct file *f
+       bool verity = ext4_verity_in_progress(inode);
+       trace_ext4_write_end(inode, pos, len, copied);
+-      if (inline_data) {
++      if (inline_data &&
++          ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) {
+               ret = ext4_write_inline_data_end(inode, pos, len,
+                                                copied, page);
+               if (ret < 0) {
diff --git a/queue-5.10/gfs2-always-check-inode-size-of-inline-inodes.patch b/queue-5.10/gfs2-always-check-inode-size-of-inline-inodes.patch
new file mode 100644 (file)
index 0000000..5a16584
--- /dev/null
@@ -0,0 +1,65 @@
+From 70376c7ff31221f1d21db5611d8209e677781d3a Mon Sep 17 00:00:00 2001
+From: Andreas Gruenbacher <agruenba@redhat.com>
+Date: Sun, 4 Dec 2022 17:00:04 +0100
+Subject: gfs2: Always check inode size of inline inodes
+
+From: Andreas Gruenbacher <agruenba@redhat.com>
+
+commit 70376c7ff31221f1d21db5611d8209e677781d3a upstream.
+
+Check if the inode size of stuffed (inline) inodes is within the allowed
+range when reading inodes from disk (gfs2_dinode_in()).  This prevents
+us from on-disk corruption.
+
+The two checks in stuffed_readpage() and gfs2_unstuffer_page() that just
+truncate inline data to the maximum allowed size don't actually make
+sense, and they can be removed now as well.
+
+Reported-by: syzbot+7bb81dfa9cda07d9cd9d@syzkaller.appspotmail.com
+Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
+[pchelkin@ispras.ru: adjust the inode variable inside gfs2_dinode_in with
+the format used before upstream commit 7db354444ad8 ("gfs2: Cosmetic
+gfs2_dinode_{in,out} cleanup")]
+Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/gfs2/aops.c  |    2 --
+ fs/gfs2/bmap.c  |    3 ---
+ fs/gfs2/glops.c |    3 +++
+ 3 files changed, 3 insertions(+), 5 deletions(-)
+
+--- a/fs/gfs2/aops.c
++++ b/fs/gfs2/aops.c
+@@ -451,8 +451,6 @@ static int stuffed_readpage(struct gfs2_
+               return error;
+       kaddr = kmap_atomic(page);
+-      if (dsize > gfs2_max_stuffed_size(ip))
+-              dsize = gfs2_max_stuffed_size(ip);
+       memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode), dsize);
+       memset(kaddr + dsize, 0, PAGE_SIZE - dsize);
+       kunmap_atomic(kaddr);
+--- a/fs/gfs2/bmap.c
++++ b/fs/gfs2/bmap.c
+@@ -69,9 +69,6 @@ static int gfs2_unstuffer_page(struct gf
+               void *kaddr = kmap(page);
+               u64 dsize = i_size_read(inode);
+  
+-              if (dsize > gfs2_max_stuffed_size(ip))
+-                      dsize = gfs2_max_stuffed_size(ip);
+-
+               memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode), dsize);
+               memset(kaddr + dsize, 0, PAGE_SIZE - dsize);
+               kunmap(page);
+--- a/fs/gfs2/glops.c
++++ b/fs/gfs2/glops.c
+@@ -454,6 +454,9 @@ static int gfs2_dinode_in(struct gfs2_in
+       ip->i_depth = (u8)depth;
+       ip->i_entries = be32_to_cpu(str->di_entries);
++      if (gfs2_is_stuffed(ip) && ip->i_inode.i_size > gfs2_max_stuffed_size(ip))
++              goto corrupt;
++
+       if (S_ISREG(ip->i_inode.i_mode))
+               gfs2_set_aops(&ip->i_inode);
index 275d5a4391b09009d37552a3e2a2472a74755de7..86a44d4fdc52a3c303aef9a10e235a8f561470c4 100644 (file)
@@ -168,3 +168,5 @@ selftests-bpf-test-btf-dump-for-struct-with-padding-.patch
 libbpf-fix-btf-to-c-converter-s-padding-logic.patch
 selftests-bpf-add-few-corner-cases-to-test-padding-h.patch
 libbpf-fix-btf_dump-s-packed-struct-determination.patch
+ext4-fix-kernel-bug-in-ext4_write_inline_data_end.patch
+gfs2-always-check-inode-size-of-inline-inodes.patch