]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 29 Jul 2024 10:19:17 +0000 (12:19 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 29 Jul 2024 10:19:17 +0000 (12:19 +0200)
added patches:
ext4-check-dot-and-dotdot-of-dx_root-before-making-dir-indexed.patch
ext4-make-sure-the-first-directory-block-is-not-a-hole.patch
m68k-amiga-turn-off-warp1260-interrupts-during-boot.patch

queue-4.19/ext4-check-dot-and-dotdot-of-dx_root-before-making-dir-indexed.patch [new file with mode: 0644]
queue-4.19/ext4-make-sure-the-first-directory-block-is-not-a-hole.patch [new file with mode: 0644]
queue-4.19/m68k-amiga-turn-off-warp1260-interrupts-during-boot.patch [new file with mode: 0644]
queue-4.19/series

diff --git a/queue-4.19/ext4-check-dot-and-dotdot-of-dx_root-before-making-dir-indexed.patch b/queue-4.19/ext4-check-dot-and-dotdot-of-dx_root-before-making-dir-indexed.patch
new file mode 100644 (file)
index 0000000..20fec95
--- /dev/null
@@ -0,0 +1,151 @@
+From 50ea741def587a64e08879ce6c6a30131f7111e7 Mon Sep 17 00:00:00 2001
+From: Baokun Li <libaokun1@huawei.com>
+Date: Tue, 2 Jul 2024 21:23:48 +0800
+Subject: ext4: check dot and dotdot of dx_root before making dir indexed
+
+From: Baokun Li <libaokun1@huawei.com>
+
+commit 50ea741def587a64e08879ce6c6a30131f7111e7 upstream.
+
+Syzbot reports a issue as follows:
+============================================
+BUG: unable to handle page fault for address: ffffed11022e24fe
+PGD 23ffee067 P4D 23ffee067 PUD 0
+Oops: Oops: 0000 [#1] PREEMPT SMP KASAN PTI
+CPU: 0 PID: 5079 Comm: syz-executor306 Not tainted 6.10.0-rc5-g55027e689933 #0
+Call Trace:
+ <TASK>
+ make_indexed_dir+0xdaf/0x13c0 fs/ext4/namei.c:2341
+ ext4_add_entry+0x222a/0x25d0 fs/ext4/namei.c:2451
+ ext4_rename fs/ext4/namei.c:3936 [inline]
+ ext4_rename2+0x26e5/0x4370 fs/ext4/namei.c:4214
+[...]
+============================================
+
+The immediate cause of this problem is that there is only one valid dentry
+for the block to be split during do_split, so split==0 results in out of
+bounds accesses to the map triggering the issue.
+
+    do_split
+      unsigned split
+      dx_make_map
+       count = 1
+      split = count/2 = 0;
+      continued = hash2 == map[split - 1].hash;
+       ---> map[4294967295]
+
+The maximum length of a filename is 255 and the minimum block size is 1024,
+so it is always guaranteed that the number of entries is greater than or
+equal to 2 when do_split() is called.
+
+But syzbot's crafted image has no dot and dotdot in dir, and the dentry
+distribution in dirblock is as follows:
+
+  bus     dentry1          hole           dentry2           free
+|xx--|xx-------------|...............|xx-------------|...............|
+0   12 (8+248)=256  268     256     524 (8+256)=264 788     236     1024
+
+So when renaming dentry1 increases its name_len length by 1, neither hole
+nor free is sufficient to hold the new dentry, and make_indexed_dir() is
+called.
+
+In make_indexed_dir() it is assumed that the first two entries of the
+dirblock must be dot and dotdot, so bus and dentry1 are left in dx_root
+because they are treated as dot and dotdot, and only dentry2 is moved
+to the new leaf block. That's why count is equal to 1.
+
+Therefore add the ext4_check_dx_root() helper function to add more sanity
+checks to dot and dotdot before starting the conversion to avoid the above
+issue.
+
+Reported-by: syzbot+ae688d469e36fb5138d0@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=ae688d469e36fb5138d0
+Fixes: ac27a0ec112a ("[PATCH] ext4: initial copy of files from ext3")
+Cc: stable@kernel.org
+Signed-off-by: Baokun Li <libaokun1@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://patch.msgid.link/20240702132349.2600605-2-libaokun@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ext4/namei.c |   56 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 51 insertions(+), 5 deletions(-)
+
+--- a/fs/ext4/namei.c
++++ b/fs/ext4/namei.c
+@@ -1997,6 +1997,52 @@ static int add_dirent_to_buf(handle_t *h
+       return 0;
+ }
++static bool ext4_check_dx_root(struct inode *dir, struct dx_root *root)
++{
++      struct fake_dirent *fde;
++      const char *error_msg;
++      unsigned int rlen;
++      unsigned int blocksize = dir->i_sb->s_blocksize;
++      char *blockend = (char *)root + dir->i_sb->s_blocksize;
++
++      fde = &root->dot;
++      if (unlikely(fde->name_len != 1)) {
++              error_msg = "invalid name_len for '.'";
++              goto corrupted;
++      }
++      if (unlikely(strncmp(root->dot_name, ".", fde->name_len))) {
++              error_msg = "invalid name for '.'";
++              goto corrupted;
++      }
++      rlen = ext4_rec_len_from_disk(fde->rec_len, blocksize);
++      if (unlikely((char *)fde + rlen >= blockend)) {
++              error_msg = "invalid rec_len for '.'";
++              goto corrupted;
++      }
++
++      fde = &root->dotdot;
++      if (unlikely(fde->name_len != 2)) {
++              error_msg = "invalid name_len for '..'";
++              goto corrupted;
++      }
++      if (unlikely(strncmp(root->dotdot_name, "..", fde->name_len))) {
++              error_msg = "invalid name for '..'";
++              goto corrupted;
++      }
++      rlen = ext4_rec_len_from_disk(fde->rec_len, blocksize);
++      if (unlikely((char *)fde + rlen >= blockend)) {
++              error_msg = "invalid rec_len for '..'";
++              goto corrupted;
++      }
++
++      return true;
++
++corrupted:
++      EXT4_ERROR_INODE(dir, "Corrupt dir, %s, running e2fsck is recommended",
++                       error_msg);
++      return false;
++}
++
+ /*
+  * This converts a one block unindexed directory to a 3 block indexed
+  * directory, and adds the dentry to the indexed directory.
+@@ -2031,17 +2077,17 @@ static int make_indexed_dir(handle_t *ha
+               brelse(bh);
+               return retval;
+       }
++
+       root = (struct dx_root *) bh->b_data;
++      if (!ext4_check_dx_root(dir, root)) {
++              brelse(bh);
++              return -EFSCORRUPTED;
++      }
+       /* The 0th block becomes the root, move the dirents out */
+       fde = &root->dotdot;
+       de = (struct ext4_dir_entry_2 *)((char *)fde +
+               ext4_rec_len_from_disk(fde->rec_len, blocksize));
+-      if ((char *) de >= (((char *) root) + blocksize)) {
+-              EXT4_ERROR_INODE(dir, "invalid rec_len for '..'");
+-              brelse(bh);
+-              return -EFSCORRUPTED;
+-      }
+       len = ((char *) root) + (blocksize - csum_size) - (char *) de;
+       /* Allocate new block for the 0th block's dirents */
diff --git a/queue-4.19/ext4-make-sure-the-first-directory-block-is-not-a-hole.patch b/queue-4.19/ext4-make-sure-the-first-directory-block-is-not-a-hole.patch
new file mode 100644 (file)
index 0000000..0aa692f
--- /dev/null
@@ -0,0 +1,85 @@
+From f9ca51596bbfd0f9c386dd1c613c394c78d9e5e6 Mon Sep 17 00:00:00 2001
+From: Baokun Li <libaokun1@huawei.com>
+Date: Tue, 2 Jul 2024 21:23:49 +0800
+Subject: ext4: make sure the first directory block is not a hole
+
+From: Baokun Li <libaokun1@huawei.com>
+
+commit f9ca51596bbfd0f9c386dd1c613c394c78d9e5e6 upstream.
+
+The syzbot constructs a directory that has no dirblock but is non-inline,
+i.e. the first directory block is a hole. And no errors are reported when
+creating files in this directory in the following flow.
+
+    ext4_mknod
+     ...
+      ext4_add_entry
+        // Read block 0
+        ext4_read_dirblock(dir, block, DIRENT)
+          bh = ext4_bread(NULL, inode, block, 0)
+          if (!bh && (type == INDEX || type == DIRENT_HTREE))
+          // The first directory block is a hole
+          // But type == DIRENT, so no error is reported.
+
+After that, we get a directory block without '.' and '..' but with a valid
+dentry. This may cause some code that relies on dot or dotdot (such as
+make_indexed_dir()) to crash.
+
+Therefore when ext4_read_dirblock() finds that the first directory block
+is a hole report that the filesystem is corrupted and return an error to
+avoid loading corrupted data from disk causing something bad.
+
+Reported-by: syzbot+ae688d469e36fb5138d0@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=ae688d469e36fb5138d0
+Fixes: 4e19d6b65fb4 ("ext4: allow directory holes")
+Cc: stable@kernel.org
+Signed-off-by: Baokun Li <libaokun1@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://patch.msgid.link/20240702132349.2600605-3-libaokun@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ext4/namei.c |   17 ++++++-----------
+ 1 file changed, 6 insertions(+), 11 deletions(-)
+
+--- a/fs/ext4/namei.c
++++ b/fs/ext4/namei.c
+@@ -134,10 +134,11 @@ static struct buffer_head *__ext4_read_d
+               return bh;
+       }
+-      if (!bh && (type == INDEX || type == DIRENT_HTREE)) {
++      /* The first directory block must not be a hole. */
++      if (!bh && (type == INDEX || type == DIRENT_HTREE || block == 0)) {
+               ext4_error_inode(inode, func, line, block,
+-                               "Directory hole found for htree %s block",
+-                               (type == INDEX) ? "index" : "leaf");
++                               "Directory hole found for htree %s block %u",
++                               (type == INDEX) ? "index" : "leaf", block);
+               return ERR_PTR(-EFSCORRUPTED);
+       }
+       if (!bh)
+@@ -2850,10 +2851,7 @@ bool ext4_empty_dir(struct inode *inode)
+               EXT4_ERROR_INODE(inode, "invalid size");
+               return true;
+       }
+-      /* The first directory block must not be a hole,
+-       * so treat it as DIRENT_HTREE
+-       */
+-      bh = ext4_read_dirblock(inode, 0, DIRENT_HTREE);
++      bh = ext4_read_dirblock(inode, 0, EITHER);
+       if (IS_ERR(bh))
+               return true;
+@@ -3425,10 +3423,7 @@ static struct buffer_head *ext4_get_firs
+               struct ext4_dir_entry_2 *de;
+               unsigned int offset;
+-              /* The first directory block must not be a hole, so
+-               * treat it as DIRENT_HTREE
+-               */
+-              bh = ext4_read_dirblock(inode, 0, DIRENT_HTREE);
++              bh = ext4_read_dirblock(inode, 0, EITHER);
+               if (IS_ERR(bh)) {
+                       *retval = PTR_ERR(bh);
+                       return NULL;
diff --git a/queue-4.19/m68k-amiga-turn-off-warp1260-interrupts-during-boot.patch b/queue-4.19/m68k-amiga-turn-off-warp1260-interrupts-during-boot.patch
new file mode 100644 (file)
index 0000000..b28fe48
--- /dev/null
@@ -0,0 +1,57 @@
+From 1d8491d3e726984343dd8c3cdbe2f2b47cfdd928 Mon Sep 17 00:00:00 2001
+From: Paolo Pisati <p.pisati@gmail.com>
+Date: Sat, 1 Jun 2024 17:32:54 +0200
+Subject: m68k: amiga: Turn off Warp1260 interrupts during boot
+
+From: Paolo Pisati <p.pisati@gmail.com>
+
+commit 1d8491d3e726984343dd8c3cdbe2f2b47cfdd928 upstream.
+
+On an Amiga 1200 equipped with a Warp1260 accelerator, an interrupt
+storm coming from the accelerator board causes the machine to crash in
+local_irq_enable() or auto_irq_enable().  Disabling interrupts for the
+Warp1260 in amiga_parse_bootinfo() fixes the problem.
+
+Link: https://lore.kernel.org/r/ZkjwzVwYeQtyAPrL@amaterasu.local
+Cc: stable <stable@kernel.org>
+Signed-off-by: Paolo Pisati <p.pisati@gmail.com>
+Reviewed-by: Michael Schmitz <schmitzmic@gmail.com>
+Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org>
+Link: https://lore.kernel.org/r/20240601153254.186225-1-p.pisati@gmail.com
+Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/m68k/amiga/config.c       |    9 +++++++++
+ include/uapi/linux/zorro_ids.h |    3 +++
+ 2 files changed, 12 insertions(+)
+
+--- a/arch/m68k/amiga/config.c
++++ b/arch/m68k/amiga/config.c
+@@ -181,6 +181,15 @@ int __init amiga_parse_bootinfo(const st
+                       dev->slotsize = be16_to_cpu(cd->cd_SlotSize);
+                       dev->boardaddr = be32_to_cpu(cd->cd_BoardAddr);
+                       dev->boardsize = be32_to_cpu(cd->cd_BoardSize);
++
++                      /* CS-LAB Warp 1260 workaround */
++                      if (be16_to_cpu(dev->rom.er_Manufacturer) == ZORRO_MANUF(ZORRO_PROD_CSLAB_WARP_1260) &&
++                          dev->rom.er_Product == ZORRO_PROD(ZORRO_PROD_CSLAB_WARP_1260)) {
++
++                              /* turn off all interrupts */
++                              pr_info("Warp 1260 card detected: applying interrupt storm workaround\n");
++                              *(uint32_t *)(dev->boardaddr + 0x1000) = 0xfff;
++                      }
+               } else
+                       pr_warn("amiga_parse_bootinfo: too many AutoConfig devices\n");
+ #endif /* CONFIG_ZORRO */
+--- a/include/uapi/linux/zorro_ids.h
++++ b/include/uapi/linux/zorro_ids.h
+@@ -449,6 +449,9 @@
+ #define  ZORRO_PROD_VMC_ISDN_BLASTER_Z2                               ZORRO_ID(VMC, 0x01, 0)
+ #define  ZORRO_PROD_VMC_HYPERCOM_4                            ZORRO_ID(VMC, 0x02, 0)
++#define ZORRO_MANUF_CSLAB                                     0x1400
++#define  ZORRO_PROD_CSLAB_WARP_1260                           ZORRO_ID(CSLAB, 0x65, 0)
++
+ #define ZORRO_MANUF_INFORMATION                                       0x157C
+ #define  ZORRO_PROD_INFORMATION_ISDN_ENGINE_I                 ZORRO_ID(INFORMATION, 0x64, 0)
index 0a413f3a6c8811d835eee3512cdd7e58a93f1a5c..8de79130e2ae27f89942a6d67c018ade3fa3110d 100644 (file)
@@ -68,3 +68,6 @@ media-venus-fix-use-after-free-in-vdec_close.patch
 hfs-fix-to-initialize-fields-of-hfs_inode_info-after-hfs_alloc_inode.patch
 drm-gma500-fix-null-pointer-dereference-in-cdv_intel_lvds_get_modes.patch
 drm-gma500-fix-null-pointer-dereference-in-psb_intel_lvds_get_modes.patch
+m68k-amiga-turn-off-warp1260-interrupts-during-boot.patch
+ext4-check-dot-and-dotdot-of-dx_root-before-making-dir-indexed.patch
+ext4-make-sure-the-first-directory-block-is-not-a-hole.patch