[OE-core] [PATCH] grub: CVE-2017-9763

Zhixiong Chi zhixiong.chi at windriver.com
Thu Jul 6 08:40:51 UTC 2017


Issue: LIN9-4520

The grub_ext2_read_block function in fs/ext2.c in GNU GRUB before
2013-11-12, allows remote attackers to cause a denial of service
(excessive stack use and application crash) via a crafted binary
file, related to use of a variable-size stack array.

patch from http://git.savannah.gnu.org/cgit/grub.git commit
f797ec85a02c0137a739fba7ee3f40d063bb7ade
ac8cac1dac50daaf1c390d701cca3b55e16ee768

CVE: CVE-2017-9763

Signed-off-by: Zhixiong Chi <zhixiong.chi at windriver.com>
---
 meta/recipes-bsp/grub/files/CVE-2017-9763.patch    | 252 +++++++++++++++++++++
 .../grub-core-fs-ext2-use-shifts-rather-than.patch | 105 +++++++++
 meta/recipes-bsp/grub/grub2.inc                    |   2 +
 3 files changed, 359 insertions(+)
 create mode 100644 meta/recipes-bsp/grub/files/CVE-2017-9763.patch
 create mode 100644 meta/recipes-bsp/grub/files/grub-core-fs-ext2-use-shifts-rather-than.patch

diff --git a/meta/recipes-bsp/grub/files/CVE-2017-9763.patch b/meta/recipes-bsp/grub/files/CVE-2017-9763.patch
new file mode 100644
index 0000000..4286730
--- /dev/null
+++ b/meta/recipes-bsp/grub/files/CVE-2017-9763.patch
@@ -0,0 +1,252 @@
+From ac8cac1dac50daaf1c390d701cca3b55e16ee768 Mon Sep 17 00:00:00 2001
+From: Vladimir Serbinenko <phcoder at gmail.com>
+Date: Tue, 12 Nov 2013 03:04:19 +0100
+Subject: 	* grub-core/fs/ext2.c: Remove variable length arrays.
+
+Upstream-Status: Backport
+
+CVE: CVE-2017-9763
+
+Signed-off-by: Zhixiong Chi <zhixiong.chi at windriver.com>
+
+---
+ ChangeLog           |  4 +++
+ grub-core/fs/ext2.c | 79 +++++++++++++++++++++++++++++++++--------------------
+ 2 files changed, 53 insertions(+), 30 deletions(-)
+
+diff --git a/ChangeLog b/ChangeLog
+index 269a841..75034e0 100644
+--- a/ChangeLog
++++ b/ChangeLog
+@@ -1,3 +1,7 @@
++2013-11-12  Vladimir Serbinenko  <phcoder at gmail.com>
++
++	* grub-core/fs/ext2.c: Remove variable length arrays.
++
+ 2013-01-05  Vladimir Serbinenko  <phcoder at gmail.com>
+ 
+ 	* grub-core/fs/ext2.c (grub_ext2_read_block): Use shifts rather than 
+diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c
+index 6941ef2..aba5cb1 100644
+--- a/grub-core/fs/ext2.c
++++ b/grub-core/fs/ext2.c
+@@ -247,6 +247,7 @@ struct ext2_dirent
+ {
+   grub_uint32_t inode;
+   grub_uint16_t direntlen;
++#define MAX_NAMELEN 255
+   grub_uint8_t namelen;
+   grub_uint8_t filetype;
+ };
+@@ -344,11 +345,12 @@ grub_ext2_blockgroup (struct grub_ext2_data *data, int group,
+ }
+ 
+ static struct grub_ext4_extent_header *
+-grub_ext4_find_leaf (struct grub_ext2_data *data, grub_properly_aligned_t *buf,
++grub_ext4_find_leaf (struct grub_ext2_data *data,
+                      struct grub_ext4_extent_header *ext_block,
+                      grub_uint32_t fileblock)
+ {
+   struct grub_ext4_extent_idx *index;
++  void *buf = NULL;
+ 
+   while (1)
+     {
+@@ -357,8 +359,8 @@ grub_ext4_find_leaf (struct grub_ext2_data *data, grub_properly_aligned_t *buf,
+ 
+       index = (struct grub_ext4_extent_idx *) (ext_block + 1);
+ 
+-      if (grub_le_to_cpu16(ext_block->magic) != EXT4_EXT_MAGIC)
+-        return 0;
++      if (ext_block->magic != grub_cpu_to_le16_compile_time (EXT4_EXT_MAGIC))
++	goto fail;
+ 
+       if (ext_block->depth == 0)
+         return ext_block;
+@@ -370,17 +372,24 @@ grub_ext4_find_leaf (struct grub_ext2_data *data, grub_properly_aligned_t *buf,
+         }
+ 
+       if (--i < 0)
+-        return 0;
++	goto fail;
+ 
+       block = grub_le_to_cpu16 (index[i].leaf_hi);
+       block = (block << 32) + grub_le_to_cpu32 (index[i].leaf);
++      if (!buf)
++	buf = grub_malloc (EXT2_BLOCK_SIZE(data));
++      if (!buf)
++	goto fail;
+       if (grub_disk_read (data->disk,
+                           block << LOG2_EXT2_BLOCK_SIZE (data),
+                           0, EXT2_BLOCK_SIZE(data), buf))
+-        return 0;
++	goto fail;
+ 
+-      ext_block = (struct grub_ext4_extent_header *) buf;
++      ext_block = buf;
+     }
++ fail:
++  grub_free (buf);
++  return 0;
+ }
+ 
+ static grub_disk_addr_t
+@@ -394,14 +403,12 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
+ 
+   if (inode->flags & grub_cpu_to_le32_compile_time (EXT4_EXTENTS_FLAG))
+     {
+-      GRUB_PROPERLY_ALIGNED_ARRAY (buf, EXT2_BLOCK_SIZE(data));
+       struct grub_ext4_extent_header *leaf;
+       struct grub_ext4_extent *ext;
+       int i;
++      grub_disk_addr_t ret;
+ 
+-      leaf = grub_ext4_find_leaf (data, buf,
+-                                  (struct grub_ext4_extent_header *) inode->blocks.dir_blocks,
+-                                  fileblock);
++      leaf = grub_ext4_find_leaf (data, (struct grub_ext4_extent_header *) inode->blocks.dir_blocks, fileblock);
+       if (! leaf)
+         {
+           grub_error (GRUB_ERR_BAD_FS, "invalid extent");
+@@ -419,7 +426,7 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
+         {
+           fileblock -= grub_le_to_cpu32 (ext[i].block);
+           if (fileblock >= grub_le_to_cpu16 (ext[i].len))
+-            return 0;
++	    ret = 0;
+           else
+             {
+               grub_disk_addr_t start;
+@@ -427,14 +434,19 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
+               start = grub_le_to_cpu16 (ext[i].start_hi);
+               start = (start << 32) + grub_le_to_cpu32 (ext[i].start);
+ 
+-              return fileblock + start;
++              ret = fileblock + start;
+             }
+         }
+       else
+         {
+           grub_error (GRUB_ERR_BAD_FS, "something wrong with extent");
+-          return -1;
++	  ret = -1;
+         }
++
++      if (leaf != (struct grub_ext4_extent_header *) inode->blocks.dir_blocks)
++	grub_free (leaf);
++
++      return ret;
+     }
+   /* Direct blocks.  */
+   if (fileblock < INDIRECT_BLOCKS)
+@@ -442,16 +454,17 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
+   /* Indirect.  */
+   else if (fileblock < INDIRECT_BLOCKS + blksz / 4)
+     {
+-      grub_uint32_t indir[blksz / 4];
++      grub_uint32_t indir;
+ 
+       if (grub_disk_read (data->disk,
+ 			  ((grub_disk_addr_t)
+ 			   grub_le_to_cpu32 (inode->blocks.indir_block))
+ 			  << log2_blksz,
+-			  0, blksz, indir))
++			  (fileblock - INDIRECT_BLOCKS) * sizeof (indir),
++			  sizeof (indir), &indir))
+ 	return grub_errno;
+ 
+-      blknr = grub_le_to_cpu32 (indir[fileblock - INDIRECT_BLOCKS]);
++      blknr = grub_le_to_cpu32 (indir);
+     }
+   /* Double indirect.  */
+   else if (fileblock < INDIRECT_BLOCKS
+@@ -460,24 +473,26 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
+       int log_perblock = log2_blksz + 9 - 2;
+       grub_disk_addr_t rblock = fileblock - (INDIRECT_BLOCKS
+ 					     + blksz / 4);
+-      grub_uint32_t indir[blksz / 4];
++      grub_uint32_t indir;
+ 
+       if (grub_disk_read (data->disk,
+ 			  ((grub_disk_addr_t)
+ 			   grub_le_to_cpu32 (inode->blocks.double_indir_block))
+ 			  << log2_blksz,
+-			  0, blksz, indir))
++			  (rblock >> log_perblock) * sizeof (indir),
++			  sizeof (indir), &indir))
+ 	return grub_errno;
+ 
+       if (grub_disk_read (data->disk,
+ 			  ((grub_disk_addr_t)
+-			   grub_le_to_cpu32 (indir[rblock >> log_perblock]))
++			   grub_le_to_cpu32 (indir))
+ 			  << log2_blksz,
+-			  0, blksz, indir))
++			  (rblock & ((1 << log_perblock) - 1)) * sizeof (indir),
++			  sizeof (indir), &indir))
+ 	return grub_errno;
+ 
+ 
+-      blknr = grub_le_to_cpu32 (indir[rblock & ((1 << log_perblock) - 1)]);
++      blknr = grub_le_to_cpu32 (indir);
+     }
+   /* triple indirect.  */
+   else if (fileblock < INDIRECT_BLOCKS + blksz / 4 * ((grub_disk_addr_t) blksz / 4 + 1)
+@@ -487,34 +502,38 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
+       int log_perblock = log2_blksz + 9 - 2;
+       grub_disk_addr_t rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4
+ 					     * (blksz / 4 + 1));
+-      grub_uint32_t indir[blksz / 4];
++      grub_uint32_t indir;
+ 
+       if (grub_disk_read (data->disk,
+ 			  ((grub_disk_addr_t)
+ 			   grub_le_to_cpu32 (inode->blocks.triple_indir_block))
+ 			  << log2_blksz,
+-			  0, blksz, indir))
++			  ((rblock >> log_perblock) >> log_perblock)
++			  * sizeof (indir), sizeof (indir), &indir))
+ 	return grub_errno;
+ 
+       if (grub_disk_read (data->disk,
+ 			  ((grub_disk_addr_t)
+-			   grub_le_to_cpu32 (indir[(rblock >> log_perblock) >> log_perblock]))
++			   grub_le_to_cpu32 (indir))
+ 			  << log2_blksz,
+-			  0, blksz, indir))
++			  ((rblock >> log_perblock)
++			   & ((1 << log_perblock) - 1)) * sizeof (indir),
++			  sizeof (indir), &indir))
+ 	return grub_errno;
+ 
+       if (grub_disk_read (data->disk,
+ 			  ((grub_disk_addr_t)
+-			   grub_le_to_cpu32 (indir[(rblock >> log_perblock) & ((1 << log_perblock) - 1)]))
++			   grub_le_to_cpu32 (indir))
+ 			  << log2_blksz,
+-			  0, blksz, indir))
++			  (rblock  & ((1 << log_perblock) - 1))
++			  * sizeof (indir), sizeof (indir), &indir))
+ 	return grub_errno;
+ 
+-      blknr = grub_le_to_cpu32 (indir[rblock  & ((1 << log_perblock) - 1)]);
++      blknr = grub_le_to_cpu32 (indir);
+     }
+   else
+     {
+-      grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
++      grub_error (GRUB_ERR_BAD_FS,
+ 		  "ext2fs doesn't support quadruple indirect blocks");
+     }
+ 
+@@ -719,7 +738,7 @@ grub_ext2_iterate_dir (grub_fshelp_node_t dir,
+ 
+       if (dirent.inode != 0 && dirent.namelen != 0)
+ 	{
+-	  char filename[dirent.namelen + 1];
++	  char filename[MAX_NAMELEN + 1];
+ 	  struct grub_fshelp_node *fdiro;
+ 	  enum grub_fshelp_filetype type = GRUB_FSHELP_UNKNOWN;
+ 
+-- 
+cgit v1.0-41-gc330
diff --git a/meta/recipes-bsp/grub/files/grub-core-fs-ext2-use-shifts-rather-than.patch b/meta/recipes-bsp/grub/files/grub-core-fs-ext2-use-shifts-rather-than.patch
new file mode 100644
index 0000000..d7fca89
--- /dev/null
+++ b/meta/recipes-bsp/grub/files/grub-core-fs-ext2-use-shifts-rather-than.patch
@@ -0,0 +1,105 @@
+From f797ec85a02c0137a739fba7ee3f40d063bb7ade Mon Sep 17 00:00:00 2001
+From: Vladimir 'phcoder' Serbinenko <phcoder at gmail.com>
+Date: Sat, 5 Jan 2013 18:37:34 +0100
+Subject: 	* grub-core/fs/ext2.c (grub_ext2_read_block): Use shifts
+ rather than 	divisions.
+
+Upstream-Status: Backport
+
+This patch is for CVE-2017-9763 patch.
+
+Signed-off-by: Zhixiong Chi <zhixiong.chi at windriver.com>
+---
+ ChangeLog           |  5 +++++
+ grub-core/fs/ext2.c | 30 ++++++++++++++++--------------
+ 2 files changed, 21 insertions(+), 14 deletions(-)
+
+diff --git a/ChangeLog b/ChangeLog
+index 88fd763..af29161 100644
+--- a/ChangeLog
++++ b/ChangeLog
+@@ -1,3 +1,8 @@
++2013-01-05  Vladimir Serbinenko  <phcoder at gmail.com>
++
++	* grub-core/fs/ext2.c (grub_ext2_read_block): Use shifts rather than
++	divisions.
++
+ 2013-01-20  Colin Watson  <cjwatson at ubuntu.com>
+
+        * grub-core/loader/i386/linux.c (grub_cmd_initrd): Don't add the
+diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c
+index bd1ab24..cf2e2f4 100644
+--- a/grub-core/fs/ext2.c
++++ b/grub-core/fs/ext2.c
+@@ -454,11 +454,12 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
+       blknr = grub_le_to_cpu32 (indir[fileblock - INDIRECT_BLOCKS]);
+     }
+   /* Double indirect.  */
+-  else if (fileblock < INDIRECT_BLOCKS + blksz / 4 * (blksz / 4 + 1))
++  else if (fileblock < INDIRECT_BLOCKS
++	   + blksz / 4 * ((grub_disk_addr_t) blksz / 4 + 1))
+     {
+-      unsigned int perblock = blksz / 4;
+-      unsigned int rblock = fileblock - (INDIRECT_BLOCKS
+-					 + blksz / 4);
++      int log_perblock = log2_blksz + 9 - 2;
++      grub_disk_addr_t rblock = fileblock - (INDIRECT_BLOCKS
++					     + blksz / 4);
+       grub_uint32_t indir[blksz / 4];
+ 
+       if (grub_disk_read (data->disk,
+@@ -470,21 +471,22 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
+ 
+       if (grub_disk_read (data->disk,
+ 			  ((grub_disk_addr_t)
+-			   grub_le_to_cpu32 (indir[rblock / perblock]))
++			   grub_le_to_cpu32 (indir[rblock >> log_perblock]))
+ 			  << log2_blksz,
+ 			  0, blksz, indir))
+ 	return grub_errno;
+ 
+ 
+-      blknr = grub_le_to_cpu32 (indir[rblock % perblock]);
++      blknr = grub_le_to_cpu32 (indir[rblock & ((1 << log_perblock) - 1)]);
+     }
+   /* triple indirect.  */
+-  else if (fileblock < INDIRECT_BLOCKS + blksz / 4 * (blksz / 4 + 1)
+-	   + (blksz / 4) * (blksz / 4) * (blksz / 4 + 1))
++  else if (fileblock < INDIRECT_BLOCKS + blksz / 4 * ((grub_disk_addr_t) blksz / 4 + 1)
++	   + ((grub_disk_addr_t) blksz / 4) * ((grub_disk_addr_t) blksz / 4)
++	   * ((grub_disk_addr_t) blksz / 4 + 1))
+     {
+-      unsigned int perblock = blksz / 4;
+-      unsigned int rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4
+-					 * (blksz / 4 + 1));
++      int log_perblock = log2_blksz + 9 - 2;
++      grub_disk_addr_t rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4
++					     * (blksz / 4 + 1));
+       grub_uint32_t indir[blksz / 4];
+ 
+       if (grub_disk_read (data->disk,
+@@ -496,19 +498,19 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
+ 
+       if (grub_disk_read (data->disk,
+ 			  ((grub_disk_addr_t)
+-			   grub_le_to_cpu32 (indir[(rblock / perblock) / perblock]))
++			   grub_le_to_cpu32 (indir[(rblock >> log_perblock) >> log_perblock]))
+ 			  << log2_blksz,
+ 			  0, blksz, indir))
+ 	return grub_errno;
+ 
+       if (grub_disk_read (data->disk,
+ 			  ((grub_disk_addr_t)
+-			   grub_le_to_cpu32 (indir[(rblock / perblock) % perblock]))
++			   grub_le_to_cpu32 (indir[(rblock >> log_perblock) & ((1 << log_perblock) - 1)]))
+ 			  << log2_blksz,
+ 			  0, blksz, indir))
+ 	return grub_errno;
+ 
+-      blknr = grub_le_to_cpu32 (indir[rblock % perblock]);
++      blknr = grub_le_to_cpu32 (indir[rblock  & ((1 << log_perblock) - 1)]);
+     }
+   else
+     {
+-- 
+cgit v1.0-41-gc330
diff --git a/meta/recipes-bsp/grub/grub2.inc b/meta/recipes-bsp/grub/grub2.inc
index ef893b3..a51c5ac 100644
--- a/meta/recipes-bsp/grub/grub2.inc
+++ b/meta/recipes-bsp/grub/grub2.inc
@@ -36,6 +36,8 @@ SRC_URI = "ftp://ftp.gnu.org/gnu/grub/grub-${PV}.tar.gz \
            file://0001-grub-core-kern-efi-mm.c-grub_efi_finish_boot_service.patch \
            file://0002-grub-core-kern-efi-mm.c-grub_efi_get_memory_map-Neve.patch \
            file://0001-build-Use-AC_HEADER_MAJOR-to-find-device-macros.patch \
+           file://grub-core-fs-ext2-use-shifts-rather-than.patch \
+           file://CVE-2017-9763.patch \
             "
 
 DEPENDS = "flex-native bison-native autogen-native"
-- 
1.9.1




More information about the Openembedded-core mailing list