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....@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 <phco...@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....@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 <phco...@gmail.com> ++ ++ * grub-core/fs/ext2.c: Remove variable length arrays. ++ + 2013-01-05 Vladimir Serbinenko <phco...@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 <phco...@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....@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 <phco...@gmail.com> ++ ++ * grub-core/fs/ext2.c (grub_ext2_read_block): Use shifts rather than ++ divisions. ++ + 2013-01-20 Colin Watson <cjwat...@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 -- _______________________________________________ Openembedded-core mailing list Openembedded-core@lists.openembedded.org http://lists.openembedded.org/mailman/listinfo/openembedded-core