[OE-core] [PATCH] grub: CVE-2017-9763
Zhixiong Chi
zhixiong.chi at windriver.com
Thu Jul 6 08:43:28 UTC 2017
Please ignore this, I will resent one updated patch.
Thanks.
On 2017年07月06日 16:40, Zhixiong Chi wrote:
> 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"
--
---------------------
Thanks,
Zhixiong Chi
Tel: +86-10-8477-7036
More information about the Openembedded-core
mailing list