From a5f269cf0964e4d5046f261ca7fc8d6f9119e96e Mon Sep 17 00:00:00 2001 From: liulong Date: Thu, 11 Mar 2021 21:11:50 +0800 Subject: [PATCH] fix CVE --- backport-0001-CVE-2020-27749.patch | 50 +++++ backport-0002-CVE-2020-27749.patch | 77 ++++++++ backport-0003-CVE-2020-27749.patch | 119 +++++++++++ backport-0004-CVE-2020-27749.patch | 65 ++++++ backport-0005-CVE-2020-27749.patch | 90 +++++++++ backport-0006-CVE-2020-27749.patch | 307 +++++++++++++++++++++++++++++ backport-0007-CVE-2020-27749.patch | 247 +++++++++++++++++++++++ backport-CVE-2020-25632.patch | 83 ++++++++ backport-CVE-2020-25647.patch | 110 +++++++++++ backport-CVE-2021-20225.patch | 51 +++++ backport-CVE-2021-20233.patch | 44 +++++ grub.patches | 11 ++ grub2.spec | 8 +- 13 files changed, 1261 insertions(+), 1 deletion(-) create mode 100644 backport-0001-CVE-2020-27749.patch create mode 100644 backport-0002-CVE-2020-27749.patch create mode 100644 backport-0003-CVE-2020-27749.patch create mode 100644 backport-0004-CVE-2020-27749.patch create mode 100644 backport-0005-CVE-2020-27749.patch create mode 100644 backport-0006-CVE-2020-27749.patch create mode 100644 backport-0007-CVE-2020-27749.patch create mode 100644 backport-CVE-2020-25632.patch create mode 100644 backport-CVE-2020-25647.patch create mode 100644 backport-CVE-2021-20225.patch create mode 100644 backport-CVE-2021-20233.patch diff --git a/backport-0001-CVE-2020-27749.patch b/backport-0001-CVE-2020-27749.patch new file mode 100644 index 0000000..57f9700 --- /dev/null +++ b/backport-0001-CVE-2020-27749.patch @@ -0,0 +1,50 @@ +From d06161b035dde4769199ad65aa0a587a5920012b Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Fri, 22 Jan 2021 12:32:41 +0000 +Subject: kern/parser: Fix resource leak if argc == 0 + +After processing the command-line yet arriving at the point where we are +setting argv, we are allocating memory, even if argc == 0, which makes +no sense since we never put anything into the allocated argv. + +The solution is to simply return that we've successfully processed the +arguments but that argc == 0, and also ensure that argv is NULL when +we're not allocating anything in it. + +There are only 2 callers of this function, and both are handling a zero +value in argc assuming nothing is allocated in argv. + +Fixes: CID 96680 + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/kern/parser.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c +index 619db31..d1cf061 100644 +--- a/grub-core/kern/parser.c ++++ b/grub-core/kern/parser.c +@@ -146,6 +146,7 @@ grub_parser_split_cmdline (const char *cmdline, + int i; + + *argc = 0; ++ *argv = NULL; + do + { + if (!rd || !*rd) +@@ -207,6 +208,10 @@ grub_parser_split_cmdline (const char *cmdline, + (*argc)++; + } + ++ /* If there are no args, then we're done. */ ++ if (!*argc) ++ return 0; ++ + /* Reserve memory for the return values. */ + args = grub_malloc (bp - buffer); + if (!args) +-- +2.23.0 + diff --git a/backport-0002-CVE-2020-27749.patch b/backport-0002-CVE-2020-27749.patch new file mode 100644 index 0000000..51b3c28 --- /dev/null +++ b/backport-0002-CVE-2020-27749.patch @@ -0,0 +1,77 @@ +From c6c426e5ab6ea715153b72584de6bd8c82f698ec Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Wed, 18 Nov 2020 00:59:24 +0000 +Subject: kern/parser: Fix a memory leak + +The getline() function supplied to grub_parser_split_cmdline() returns +a newly allocated buffer and can be called multiple times, but the +returned buffer is never freed. + +Signed-off-by: Chris Coulson +Reviewed-by: Daniel Kiper +--- + grub-core/kern/parser.c | 22 +++++++++++++++++----- + 1 file changed, 17 insertions(+), 5 deletions(-) + +diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c +index d1cf061..0163a62 100644 +--- a/grub-core/kern/parser.c ++++ b/grub-core/kern/parser.c +@@ -141,6 +141,7 @@ grub_parser_split_cmdline (const char *cmdline, + char *bp = buffer; + char *rd = (char *) cmdline; + char varname[200]; ++ char *rp = rd; + char *vp = varname; + char *args; + int i; +@@ -149,10 +150,18 @@ grub_parser_split_cmdline (const char *cmdline, + *argv = NULL; + do + { +- if (!rd || !*rd) +- { ++ if (rp == NULL || *rp == '\0') ++ { ++ if (rd != cmdline) ++ { ++ grub_free (rd); ++ rd = rp = NULL; ++ } + if (getline) +- getline (&rd, 1, getline_data); ++ { ++ getline (&rd, 1, getline_data); ++ rp = rd; ++ } + else + break; + } +@@ -160,12 +169,12 @@ grub_parser_split_cmdline (const char *cmdline, + if (!rd) + break; + +- for (; *rd; rd++) ++ for (; *rp != '\0'; rp++) + { + grub_parser_state_t newstate; + char use; + +- newstate = grub_parser_cmdline_state (state, *rd, &use); ++ newstate = grub_parser_cmdline_state (state, *rp, &use); + + /* If a variable was being processed and this character does + not describe the variable anymore, write the variable to +@@ -198,6 +207,9 @@ grub_parser_split_cmdline (const char *cmdline, + } + while (state != GRUB_PARSER_STATE_TEXT && !check_varstate (state)); + ++ if (rd != cmdline) ++ grub_free (rd); ++ + /* A special case for when the last character was part of a + variable. */ + add_var (varname, &bp, &vp, state, GRUB_PARSER_STATE_TEXT); +-- +2.23.0 + diff --git a/backport-0003-CVE-2020-27749.patch b/backport-0003-CVE-2020-27749.patch new file mode 100644 index 0000000..4cfac0a --- /dev/null +++ b/backport-0003-CVE-2020-27749.patch @@ -0,0 +1,119 @@ +From b1c9e9e889e4273fb15712051c887e6078511448 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Tue, 5 Jan 2021 22:17:28 +0000 +Subject: kern/parser: Introduce process_char() helper + +grub_parser_split_cmdline() iterates over each command line character. +In order to add error checking and to simplify the subsequent error +handling, split the character processing in to a separate function. + +Signed-off-by: Chris Coulson +Reviewed-by: Daniel Kiper +--- + grub-core/kern/parser.c | 74 +++++++++++++++++++++++++---------------- + 1 file changed, 46 insertions(+), 28 deletions(-) + +diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c +index 0163a62..7e1ba99 100644 +--- a/grub-core/kern/parser.c ++++ b/grub-core/kern/parser.c +@@ -1,7 +1,7 @@ + /* parser.c - the part of the parser that can return partial tokens */ + /* + * GRUB -- GRand Unified Bootloader +- * Copyright (C) 2005,2007,2009 Free Software Foundation, Inc. ++ * Copyright (C) 2005,2007,2009,2021 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -129,6 +129,46 @@ add_var (char *varname, char **bp, char **vp, + *((*bp)++) = *val; + } + ++static grub_err_t ++process_char (char c, char *buffer, char **bp, char *varname, char **vp, ++ grub_parser_state_t state, int *argc, ++ grub_parser_state_t *newstate) ++{ ++ char use; ++ ++ *newstate = grub_parser_cmdline_state (state, c, &use); ++ ++ /* ++ * If a variable was being processed and this character does ++ * not describe the variable anymore, write the variable to ++ * the buffer. ++ */ ++ add_var (varname, bp, vp, state, *newstate); ++ ++ if (check_varstate (*newstate)) ++ { ++ if (use) ++ *((*vp)++) = use; ++ } ++ else if (*newstate == GRUB_PARSER_STATE_TEXT && ++ state != GRUB_PARSER_STATE_ESC && grub_isspace (use)) ++ { ++ /* ++ * Don't add more than one argument if multiple ++ * spaces are used. ++ */ ++ if (*bp != buffer && *((*bp) - 1) != '\0') ++ { ++ *((*bp)++) = '\0'; ++ (*argc)++; ++ } ++ } ++ else if (use) ++ *((*bp)++) = use; ++ ++ return GRUB_ERR_NONE; ++} ++ + grub_err_t + grub_parser_split_cmdline (const char *cmdline, + grub_reader_getline_t getline, void *getline_data, +@@ -172,35 +212,13 @@ grub_parser_split_cmdline (const char *cmdline, + for (; *rp != '\0'; rp++) + { + grub_parser_state_t newstate; +- char use; +- +- newstate = grub_parser_cmdline_state (state, *rp, &use); + +- /* If a variable was being processed and this character does +- not describe the variable anymore, write the variable to +- the buffer. */ +- add_var (varname, &bp, &vp, state, newstate); +- +- if (check_varstate (newstate)) +- { +- if (use) +- *(vp++) = use; +- } +- else ++ if (process_char (*rp, buffer, &bp, varname, &vp, state, argc, ++ &newstate) != GRUB_ERR_NONE) + { +- if (newstate == GRUB_PARSER_STATE_TEXT +- && state != GRUB_PARSER_STATE_ESC && grub_isspace (use)) +- { +- /* Don't add more than one argument if multiple +- spaces are used. */ +- if (bp != buffer && *(bp - 1)) +- { +- *(bp++) = '\0'; +- (*argc)++; +- } +- } +- else if (use) +- *(bp++) = use; ++ if (rd != cmdline) ++ grub_free (rd); ++ return grub_errno; + } + state = newstate; + } +-- +2.23.0 + diff --git a/backport-0004-CVE-2020-27749.patch b/backport-0004-CVE-2020-27749.patch new file mode 100644 index 0000000..bec946e --- /dev/null +++ b/backport-0004-CVE-2020-27749.patch @@ -0,0 +1,65 @@ +From 3d157bbd06506b170fde5ec23980c4bf9f7660e2 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Thu, 7 Jan 2021 19:53:55 +0000 +Subject: kern/parser: Introduce terminate_arg() helper + +process_char() and grub_parser_split_cmdline() use similar code for +terminating the most recent argument. Add a helper function for this. + +Signed-off-by: Chris Coulson +Reviewed-by: Daniel Kiper +--- + grub-core/kern/parser.c | 23 +++++++++++++---------- + 1 file changed, 13 insertions(+), 10 deletions(-) + +diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c +index 7e1ba99..45d0871 100644 +--- a/grub-core/kern/parser.c ++++ b/grub-core/kern/parser.c +@@ -129,6 +129,16 @@ add_var (char *varname, char **bp, char **vp, + *((*bp)++) = *val; + } + ++static void ++terminate_arg (char *buffer, char **bp, int *argc) ++{ ++ if (*bp != buffer && *((*bp) - 1) != '\0') ++ { ++ *((*bp)++) = '\0'; ++ (*argc)++; ++ } ++} ++ + static grub_err_t + process_char (char c, char *buffer, char **bp, char *varname, char **vp, + grub_parser_state_t state, int *argc, +@@ -157,11 +167,7 @@ process_char (char c, char *buffer, char **bp, char *varname, char **vp, + * Don't add more than one argument if multiple + * spaces are used. + */ +- if (*bp != buffer && *((*bp) - 1) != '\0') +- { +- *((*bp)++) = '\0'; +- (*argc)++; +- } ++ terminate_arg (buffer, bp, argc); + } + else if (use) + *((*bp)++) = use; +@@ -232,11 +238,8 @@ grub_parser_split_cmdline (const char *cmdline, + variable. */ + add_var (varname, &bp, &vp, state, GRUB_PARSER_STATE_TEXT); + +- if (bp != buffer && *(bp - 1)) +- { +- *(bp++) = '\0'; +- (*argc)++; +- } ++ /* Ensure that the last argument is terminated. */ ++ terminate_arg (buffer, &bp, argc); + + /* If there are no args, then we're done. */ + if (!*argc) +-- +2.23.0 + diff --git a/backport-0005-CVE-2020-27749.patch b/backport-0005-CVE-2020-27749.patch new file mode 100644 index 0000000..4cf21e0 --- /dev/null +++ b/backport-0005-CVE-2020-27749.patch @@ -0,0 +1,90 @@ +From 8bc817014ce3d7a498db44eae33c8b90e2430926 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Wed, 6 Jan 2021 13:54:26 +0000 +Subject: kern/parser: Refactor grub_parser_split_cmdline() cleanup + +Introduce a common function epilogue used for cleaning up on all +return paths, which will simplify additional error handling to be +introduced in a subsequent commit. + +Signed-off-by: Chris Coulson +Reviewed-by: Daniel Kiper +--- + grub-core/kern/parser.c | 35 ++++++++++++++++++++--------------- + 1 file changed, 20 insertions(+), 15 deletions(-) + +diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c +index 572c67089..e010eaa1f 100644 +--- a/grub-core/kern/parser.c ++++ b/grub-core/kern/parser.c +@@ -221,19 +221,13 @@ grub_parser_split_cmdline (const char *cmdline, + + if (process_char (*rp, buffer, &bp, varname, &vp, state, argc, + &newstate) != GRUB_ERR_NONE) +- { +- if (rd != cmdline) +- grub_free (rd); +- return grub_errno; +- } ++ goto fail; ++ + state = newstate; + } + } + while (state != GRUB_PARSER_STATE_TEXT && !check_varstate (state)); + +- if (rd != cmdline) +- grub_free (rd); +- + /* A special case for when the last character was part of a + variable. */ + add_var (varname, &bp, &vp, state, GRUB_PARSER_STATE_TEXT); +@@ -243,20 +237,20 @@ grub_parser_split_cmdline (const char *cmdline, + + /* If there are no args, then we're done. */ + if (!*argc) +- return 0; ++ { ++ grub_errno = GRUB_ERR_NONE; ++ goto out; ++ } + + /* Reserve memory for the return values. */ + args = grub_malloc (bp - buffer); + if (!args) +- return grub_errno; ++ goto fail; + grub_memcpy (args, buffer, bp - buffer); + + *argv = grub_calloc (*argc + 1, sizeof (char *)); + if (!*argv) +- { +- grub_free (args); +- return grub_errno; +- } ++ goto fail; + + /* The arguments are separated with 0's, setup argv so it points to + the right values. */ +@@ -269,7 +263,18 @@ grub_parser_split_cmdline (const char *cmdline, + bp++; + } + +- return 0; ++ grub_errno = GRUB_ERR_NONE; ++ ++ out: ++ if (rd != cmdline) ++ grub_free (rd); ++ ++ return grub_errno; ++ ++ fail: ++ grub_free (*argv); ++ grub_free (args); ++ goto out; + } + + /* Helper for grub_parser_execute. */ +-- +cgit v1.2.1 \ No newline at end of file diff --git a/backport-0006-CVE-2020-27749.patch b/backport-0006-CVE-2020-27749.patch new file mode 100644 index 0000000..a54feef --- /dev/null +++ b/backport-0006-CVE-2020-27749.patch @@ -0,0 +1,307 @@ +From 030fb6c4fa354cdbd6a8d6903dfed5d36eaf3cb2 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Thu, 7 Jan 2021 15:15:43 +0000 +Subject: kern/buffer: Add variable sized heap buffer + +Add a new variable sized heap buffer type (grub_buffer_t) with simple +operations for appending data, accessing the data and maintaining +a read cursor. + +Signed-off-by: Chris Coulson +Reviewed-by: Daniel Kiper +--- + grub-core/Makefile.core.def | 1 + + grub-core/kern/buffer.c | 117 +++++++++++++++++++++++++++++++++++ + include/grub/buffer.h | 144 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 262 insertions(+) + create mode 100644 grub-core/kern/buffer.c + create mode 100644 include/grub/buffer.h + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index b283c50..c7563bb 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -123,6 +123,7 @@ kernel = { + riscv32_efi_startup = kern/riscv/efi/startup.S; + riscv64_efi_startup = kern/riscv/efi/startup.S; + ++ common = kern/buffer.c; + common = kern/command.c; + common = kern/corecmd.c; + common = kern/device.c; +diff --git a/grub-core/kern/buffer.c b/grub-core/kern/buffer.c +new file mode 100644 +index 0000000..b50a187 +--- /dev/null ++++ b/grub-core/kern/buffer.c +@@ -0,0 +1,117 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2021 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++grub_buffer_t ++grub_buffer_new (grub_size_t sz) ++{ ++ struct grub_buffer *ret; ++ ++ ret = (struct grub_buffer *) grub_malloc (sizeof (*ret)); ++ if (ret == NULL) ++ return NULL; ++ ++ ret->data = (grub_uint8_t *) grub_malloc (sz); ++ if (ret->data == NULL) ++ { ++ grub_free (ret); ++ return NULL; ++ } ++ ++ ret->sz = sz; ++ ret->pos = 0; ++ ret->used = 0; ++ ++ return ret; ++} ++ ++void ++grub_buffer_free (grub_buffer_t buf) ++{ ++ grub_free (buf->data); ++ grub_free (buf); ++} ++ ++grub_err_t ++grub_buffer_ensure_space (grub_buffer_t buf, grub_size_t req) ++{ ++ grub_uint8_t *d; ++ grub_size_t newsz = 1; ++ ++ /* Is the current buffer size adequate? */ ++ if (buf->sz >= req) ++ return GRUB_ERR_NONE; ++ ++ /* Find the smallest power-of-2 size that satisfies the request. */ ++ while (newsz < req) ++ { ++ if (newsz == 0) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("requested buffer size is too large")); ++ newsz <<= 1; ++ } ++ ++ d = (grub_uint8_t *) grub_realloc (buf->data, newsz); ++ if (d == NULL) ++ return grub_errno; ++ ++ buf->data = d; ++ buf->sz = newsz; ++ ++ return GRUB_ERR_NONE; ++} ++ ++void * ++grub_buffer_take_data (grub_buffer_t buf) ++{ ++ void *data = buf->data; ++ ++ buf->data = NULL; ++ buf->sz = buf->pos = buf->used = 0; ++ ++ return data; ++} ++ ++void ++grub_buffer_reset (grub_buffer_t buf) ++{ ++ buf->pos = buf->used = 0; ++} ++ ++grub_err_t ++grub_buffer_advance_read_pos (grub_buffer_t buf, grub_size_t n) ++{ ++ grub_size_t newpos; ++ ++ if (grub_add (buf->pos, n, &newpos)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++ ++ if (newpos > buf->used) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("new read is position beyond the end of the written data")); ++ ++ buf->pos = newpos; ++ ++ return GRUB_ERR_NONE; ++} +diff --git a/include/grub/buffer.h b/include/grub/buffer.h +new file mode 100644 +index 0000000..f4b10cf +--- /dev/null ++++ b/include/grub/buffer.h +@@ -0,0 +1,144 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2021 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_BUFFER_H ++#define GRUB_BUFFER_H 1 ++ ++#include ++#include ++#include ++#include ++#include ++ ++struct grub_buffer ++{ ++ grub_uint8_t *data; ++ grub_size_t sz; ++ grub_size_t pos; ++ grub_size_t used; ++}; ++ ++/* ++ * grub_buffer_t represents a simple variable sized byte buffer with ++ * read and write cursors. It currently only implements ++ * functionality required by the only user in GRUB (append byte[s], ++ * peeking data at a specified position and updating the read cursor. ++ * Some things that this doesn't do yet are: ++ * - Reading a portion of the buffer by copying data from the current ++ * read position in to a caller supplied destination buffer and then ++ * automatically updating the read cursor. ++ * - Dropping the read part at the start of the buffer when an append ++ * requires more space. ++ */ ++typedef struct grub_buffer *grub_buffer_t; ++ ++/* Allocate a new buffer with the specified initial size. */ ++extern grub_buffer_t grub_buffer_new (grub_size_t sz); ++ ++/* Free the buffer and its resources. */ ++extern void grub_buffer_free (grub_buffer_t buf); ++ ++/* Return the number of unread bytes in this buffer. */ ++static inline grub_size_t ++grub_buffer_get_unread_bytes (grub_buffer_t buf) ++{ ++ return buf->used - buf->pos; ++} ++ ++/* ++ * Ensure that the buffer size is at least the requested ++ * number of bytes. ++ */ ++extern grub_err_t grub_buffer_ensure_space (grub_buffer_t buf, grub_size_t req); ++ ++/* ++ * Append the specified number of bytes from the supplied ++ * data to the buffer. ++ */ ++static inline grub_err_t ++grub_buffer_append_data (grub_buffer_t buf, const void *data, grub_size_t len) ++{ ++ grub_size_t req; ++ ++ if (grub_add (buf->used, len, &req)) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++ ++ if (grub_buffer_ensure_space (buf, req) != GRUB_ERR_NONE) ++ return grub_errno; ++ ++ grub_memcpy (&buf->data[buf->used], data, len); ++ buf->used = req; ++ ++ return GRUB_ERR_NONE; ++} ++ ++/* Append the supplied character to the buffer. */ ++static inline grub_err_t ++grub_buffer_append_char (grub_buffer_t buf, char c) ++{ ++ return grub_buffer_append_data (buf, &c, 1); ++} ++ ++/* ++ * Forget and return the underlying data buffer. The caller ++ * becomes the owner of this buffer, and must free it when it ++ * is no longer required. ++ */ ++extern void *grub_buffer_take_data (grub_buffer_t buf); ++ ++/* Reset this buffer. Note that this does not deallocate any resources. */ ++void grub_buffer_reset (grub_buffer_t buf); ++ ++/* ++ * Return a pointer to the underlying data buffer at the specified ++ * offset from the current read position. Note that this pointer may ++ * become invalid if the buffer is mutated further. ++ */ ++static inline void * ++grub_buffer_peek_data_at (grub_buffer_t buf, grub_size_t off) ++{ ++ if (grub_add (buf->pos, off, &off)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected.")); ++ return NULL; ++ } ++ ++ if (off >= buf->used) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("peek out of range")); ++ return NULL; ++ } ++ ++ return &buf->data[off]; ++} ++ ++/* ++ * Return a pointer to the underlying data buffer at the current ++ * read position. Note that this pointer may become invalid if the ++ * buffer is mutated further. ++ */ ++static inline void * ++grub_buffer_peek_data (grub_buffer_t buf) ++{ ++ return grub_buffer_peek_data_at (buf, 0); ++} ++ ++/* Advance the read position by the specified number of bytes. */ ++extern grub_err_t grub_buffer_advance_read_pos (grub_buffer_t buf, grub_size_t n); ++ ++#endif /* GRUB_BUFFER_H */ +-- +2.23.0 + diff --git a/backport-0007-CVE-2020-27749.patch b/backport-0007-CVE-2020-27749.patch new file mode 100644 index 0000000..53089f3 --- /dev/null +++ b/backport-0007-CVE-2020-27749.patch @@ -0,0 +1,247 @@ +From 4ea7bae51f97e49c84dc67ea30b466ca8633b9f6 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Thu, 7 Jan 2021 19:21:03 +0000 +Subject: kern/parser: Fix a stack buffer overflow + +grub_parser_split_cmdline() expands variable names present in the supplied +command line in to their corresponding variable contents and uses a 1 kiB +stack buffer for temporary storage without sufficient bounds checking. If +the function is called with a command line that references a variable with +a sufficiently large payload, it is possible to overflow the stack +buffer via tab completion, corrupt the stack frame and potentially +control execution. + +Fixes: CVE-2020-27749 + +Reported-by: Chris Coulson +Signed-off-by: Chris Coulson +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +--- + grub-core/kern/parser.c | 110 ++++++++++++++++++++++++---------------- + 1 file changed, 67 insertions(+), 43 deletions(-) + +diff --git a/grub-core/kern/parser.c b/grub-core/kern/parser.c +index d50538f..89276d5 100644 +--- a/grub-core/kern/parser.c ++++ b/grub-core/kern/parser.c +@@ -18,6 +18,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -107,8 +108,8 @@ check_varstate (grub_parser_state_t s) + } + + +-static void +-add_var (char *varname, char **bp, char **vp, ++static grub_err_t ++add_var (grub_buffer_t varname, grub_buffer_t buf, + grub_parser_state_t state, grub_parser_state_t newstate) + { + const char *val; +@@ -116,31 +117,41 @@ add_var (char *varname, char **bp, char **vp, + /* Check if a variable was being read in and the end of the name + was reached. */ + if (!(check_varstate (state) && !check_varstate (newstate))) +- return; ++ return GRUB_ERR_NONE; ++ ++ if (grub_buffer_append_char (varname, '\0') != GRUB_ERR_NONE) ++ return grub_errno; + +- *((*vp)++) = '\0'; +- val = grub_env_get (varname); +- *vp = varname; ++ val = grub_env_get ((const char *) grub_buffer_peek_data (varname)); ++ grub_buffer_reset (varname); + if (!val) +- return; ++ return GRUB_ERR_NONE; + + /* Insert the contents of the variable in the buffer. */ +- for (; *val; val++) +- *((*bp)++) = *val; ++ return grub_buffer_append_data (buf, val, grub_strlen (val)); + } + +-static void +-terminate_arg (char *buffer, char **bp, int *argc) ++static grub_err_t ++terminate_arg (grub_buffer_t buffer, int *argc) + { +- if (*bp != buffer && *((*bp) - 1) != '\0') +- { +- *((*bp)++) = '\0'; +- (*argc)++; +- } ++ grub_size_t unread = grub_buffer_get_unread_bytes (buffer); ++ ++ if (unread == 0) ++ return GRUB_ERR_NONE; ++ ++ if (*(const char *) grub_buffer_peek_data_at (buffer, unread - 1) == '\0') ++ return GRUB_ERR_NONE; ++ ++ if (grub_buffer_append_char (buffer, '\0') != GRUB_ERR_NONE) ++ return grub_errno; ++ ++ (*argc)++; ++ ++ return GRUB_ERR_NONE; + } + + static grub_err_t +-process_char (char c, char *buffer, char **bp, char *varname, char **vp, ++process_char (char c, grub_buffer_t buffer, grub_buffer_t varname, + grub_parser_state_t state, int *argc, + grub_parser_state_t *newstate) + { +@@ -153,12 +164,13 @@ process_char (char c, char *buffer, char **bp, char *varname, char **vp, + * not describe the variable anymore, write the variable to + * the buffer. + */ +- add_var (varname, bp, vp, state, *newstate); ++ if (add_var (varname, buffer, state, *newstate) != GRUB_ERR_NONE) ++ return grub_errno; + + if (check_varstate (*newstate)) + { + if (use) +- *((*vp)++) = use; ++ return grub_buffer_append_char (varname, use); + } + else if (*newstate == GRUB_PARSER_STATE_TEXT && + state != GRUB_PARSER_STATE_ESC && grub_isspace (use)) +@@ -167,10 +179,10 @@ process_char (char c, char *buffer, char **bp, char *varname, char **vp, + * Don't add more than one argument if multiple + * spaces are used. + */ +- terminate_arg (buffer, bp, argc); ++ return terminate_arg (buffer, argc); + } + else if (use) +- *((*bp)++) = use; ++ return grub_buffer_append_char (buffer, use); + + return GRUB_ERR_NONE; + } +@@ -181,19 +193,22 @@ grub_parser_split_cmdline (const char *cmdline, + int *argc, char ***argv) + { + grub_parser_state_t state = GRUB_PARSER_STATE_TEXT; +- /* XXX: Fixed size buffer, perhaps this buffer should be dynamically +- allocated. */ +- char buffer[1024]; +- char *bp = buffer; ++ grub_buffer_t buffer, varname; + char *rd = (char *) cmdline; +- char varname[200]; + char *rp = rd; +- char *vp = varname; +- char *args; + int i; + + *argc = 0; + *argv = NULL; ++ ++ buffer = grub_buffer_new (1024); ++ if (buffer == NULL) ++ return grub_errno; ++ ++ varname = grub_buffer_new (200); ++ if (varname == NULL) ++ goto fail; ++ + do + { + if (rp == NULL || *rp == '\0') +@@ -219,7 +234,7 @@ grub_parser_split_cmdline (const char *cmdline, + { + grub_parser_state_t newstate; + +- if (process_char (*rp, buffer, &bp, varname, &vp, state, argc, ++ if (process_char (*rp, buffer, varname, state, argc, + &newstate) != GRUB_ERR_NONE) + goto fail; + +@@ -230,10 +245,12 @@ grub_parser_split_cmdline (const char *cmdline, + + /* A special case for when the last character was part of a + variable. */ +- add_var (varname, &bp, &vp, state, GRUB_PARSER_STATE_TEXT); ++ if (add_var (varname, buffer, state, GRUB_PARSER_STATE_TEXT) != GRUB_ERR_NONE) ++ goto fail; + + /* Ensure that the last argument is terminated. */ +- terminate_arg (buffer, &bp, argc); ++ if (terminate_arg (buffer, argc) != GRUB_ERR_NONE) ++ goto fail; + + /* If there are no args, then we're done. */ + if (!*argc) +@@ -242,38 +259,45 @@ grub_parser_split_cmdline (const char *cmdline, + goto out; + } + +- /* Reserve memory for the return values. */ +- args = grub_malloc (bp - buffer); +- if (!args) +- goto fail; +- grub_memcpy (args, buffer, bp - buffer); +- + *argv = grub_calloc (*argc + 1, sizeof (char *)); + if (!*argv) + goto fail; + + /* The arguments are separated with 0's, setup argv so it points to + the right values. */ +- bp = args; + for (i = 0; i < *argc; i++) + { +- (*argv)[i] = bp; +- while (*bp) +- bp++; +- bp++; ++ char *arg; ++ ++ if (i > 0) ++ { ++ if (grub_buffer_advance_read_pos (buffer, 1) != GRUB_ERR_NONE) ++ goto fail; ++ } ++ ++ arg = (char *) grub_buffer_peek_data (buffer); ++ if (arg == NULL || ++ grub_buffer_advance_read_pos (buffer, grub_strlen (arg)) != GRUB_ERR_NONE) ++ goto fail; ++ ++ (*argv)[i] = arg; + } + ++ /* Keep memory for the return values. */ ++ grub_buffer_take_data (buffer); ++ + grub_errno = GRUB_ERR_NONE; + + out: + if (rd != cmdline) + grub_free (rd); ++ grub_buffer_free (buffer); ++ grub_buffer_free (varname); + + return grub_errno; + + fail: + grub_free (*argv); +- grub_free (args); + goto out; + } + +-- +2.23.0 + diff --git a/backport-CVE-2020-25632.patch b/backport-CVE-2020-25632.patch new file mode 100644 index 0000000..1795977 --- /dev/null +++ b/backport-CVE-2020-25632.patch @@ -0,0 +1,83 @@ +From 7630ec5397fe418276b360f9011934b8c034936c +From: Daniel Kiper +Date: 2021-03-02 15:54:15 +0100 +Subject: [PATCH] dl: Only allow unloading modules that are not dependencies +When a module is attempted to be removed its reference counter is always +decremented. This means that repeated rmmod invocations will cause the +module to be unloaded even if another module depends on it. + +This may lead to a use-after-free scenario allowing an attacker to execute +arbitrary code and by-pass the UEFI Secure Boot protection. + +While being there, add the extern keyword to some function declarations in +that header file. + +Fixes: CVE-2020-25632 + +Reference:http://git.savannah.gnu.org/cgit/grub.git/commit/?id=7630ec5397fe418276b360f9011934b8c034936c + +Reported-by: Chris Coulson +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +Diffstat +-rw-r--r-- grub-core/commands/minicmd.c 7 +-rw-r--r-- grub-core/kern/dl.c 9 +-rw-r--r-- include/grub/dl.h 8 +3 files changed, 19 insertions, 5 deletions +diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c +index 6bbce3128..fa498931e 100644 +--- a/grub-core/commands/minicmd.c ++++ b/grub-core/commands/minicmd.c +@@ -140,8 +140,11 @@ grub_mini_cmd_rmmod (struct grub_command *cmd __attribute__ ((unused)), + if (grub_dl_is_persistent (mod)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "cannot unload persistent module"); + +- if (grub_dl_unref (mod) <= 0) +- grub_dl_unload (mod); ++ if (grub_dl_ref_count (mod) > 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "cannot unload referenced module"); ++ ++ grub_dl_unref (mod); ++ grub_dl_unload (mod); + + return 0; + } +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index 48eb5e7b6..48f8a7907 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -549,6 +549,15 @@ grub_dl_unref (grub_dl_t mod) + return --mod->ref_count; + } + ++int ++grub_dl_ref_count (grub_dl_t mod) ++{ ++ if (mod == NULL) ++ return 0; ++ ++ return mod->ref_count; ++} ++ + static void + grub_dl_flush_cache (grub_dl_t mod) + { +diff --git a/include/grub/dl.h b/include/grub/dl.h +index f03c03561..b3753c9ca 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -203,9 +203,11 @@ grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name); + grub_dl_t grub_dl_load_core (void *addr, grub_size_t size); + grub_dl_t EXPORT_FUNC(grub_dl_load_core_noinit) (void *addr, grub_size_t size); + int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod); +-void grub_dl_unload_unneeded (void); +-int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod); +-int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod); ++extern void grub_dl_unload_unneeded (void); ++extern int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod); ++extern int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod); ++extern int EXPORT_FUNC(grub_dl_ref_count) (grub_dl_t mod); ++ + extern grub_dl_t EXPORT_VAR(grub_dl_head); + + #ifndef GRUB_UTIL diff --git a/backport-CVE-2020-25647.patch b/backport-CVE-2020-25647.patch new file mode 100644 index 0000000..bdac237 --- /dev/null +++ b/backport-CVE-2020-25647.patch @@ -0,0 +1,110 @@ +From 128c16a682034263eb519c89bc0934eeb6fa8cfa +From: Daniel Kiper +Date: 2021-03-02 15:54:15 +0100 +Subject: [PATCH] usb: Avoid possible out-of-bound accesses caused by malicious devices +The maximum number of configurations and interfaces are fixed but there is +no out-of-bound checking to prevent a malicious USB device to report large +values for these and cause accesses outside the arrays' memory. + +Fixes: CVE-2020-25647 +Reference:http://git.savannah.gnu.org/cgit/grub.git/commit/?id=128c16a682034263eb519c89bc0934eeb6fa8cfa + +Reported-by: Joseph Tartaro +Reported-by: Ilja Van Sprundel +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +Diffstat +-rw-r--r-- grub-core/bus/usb/usb.c 15 +-rw-r--r-- include/grub/usb.h 10 +2 files changed, 19 insertions, 6 deletions +diff --git a/grub-core/bus/usb/usb.c b/grub-core/bus/usb/usb.c +index 8da5e4c74..7cb3cc230 100644 +--- a/grub-core/bus/usb/usb.c ++++ b/grub-core/bus/usb/usb.c +@@ -75,6 +75,9 @@ grub_usb_controller_iterate (grub_usb_controller_iterate_hook_t hook, + grub_usb_err_t + grub_usb_clear_halt (grub_usb_device_t dev, int endpoint) + { ++ if (endpoint >= GRUB_USB_MAX_TOGGLE) ++ return GRUB_USB_ERR_BADDEVICE; ++ + dev->toggle[endpoint] = 0; + return grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT + | GRUB_USB_REQTYPE_STANDARD +@@ -134,10 +137,10 @@ grub_usb_device_initialize (grub_usb_device_t dev) + return err; + descdev = &dev->descdev; + +- for (i = 0; i < 8; i++) ++ for (i = 0; i < GRUB_USB_MAX_CONF; i++) + dev->config[i].descconf = NULL; + +- if (descdev->configcnt == 0) ++ if (descdev->configcnt == 0 || descdev->configcnt > GRUB_USB_MAX_CONF) + { + err = GRUB_USB_ERR_BADDEVICE; + goto fail; +@@ -172,6 +175,12 @@ grub_usb_device_initialize (grub_usb_device_t dev) + /* Skip the configuration descriptor. */ + pos = dev->config[i].descconf->length; + ++ if (dev->config[i].descconf->numif > GRUB_USB_MAX_IF) ++ { ++ err = GRUB_USB_ERR_BADDEVICE; ++ goto fail; ++ } ++ + /* Read all interfaces. */ + for (currif = 0; currif < dev->config[i].descconf->numif; currif++) + { +@@ -217,7 +226,7 @@ grub_usb_device_initialize (grub_usb_device_t dev) + + fail: + +- for (i = 0; i < 8; i++) ++ for (i = 0; i < GRUB_USB_MAX_CONF; i++) + grub_free (dev->config[i].descconf); + + return err; +diff --git a/include/grub/usb.h b/include/grub/usb.h +index 512ae1dd0..6475c552f 100644 +--- a/include/grub/usb.h ++++ b/include/grub/usb.h +@@ -23,6 +23,10 @@ + #include + #include + ++#define GRUB_USB_MAX_CONF 8 ++#define GRUB_USB_MAX_IF 32 ++#define GRUB_USB_MAX_TOGGLE 256 ++ + typedef struct grub_usb_device *grub_usb_device_t; + typedef struct grub_usb_controller *grub_usb_controller_t; + typedef struct grub_usb_controller_dev *grub_usb_controller_dev_t; +@@ -167,7 +171,7 @@ struct grub_usb_configuration + struct grub_usb_desc_config *descconf; + + /* Interfaces associated to this configuration. */ +- struct grub_usb_interface interf[32]; ++ struct grub_usb_interface interf[GRUB_USB_MAX_IF]; + }; + + struct grub_usb_hub_port +@@ -191,7 +195,7 @@ struct grub_usb_device + struct grub_usb_controller controller; + + /* Device configurations (after opening the device). */ +- struct grub_usb_configuration config[8]; ++ struct grub_usb_configuration config[GRUB_USB_MAX_CONF]; + + /* Device address. */ + int addr; +@@ -203,7 +207,7 @@ struct grub_usb_device + int initialized; + + /* Data toggle values (used for bulk transfers only). */ +- int toggle[256]; ++ int toggle[GRUB_USB_MAX_TOGGLE]; + + /* Used by libusb wrapper. Schedulded for removal. */ + void *data; diff --git a/backport-CVE-2021-20225.patch b/backport-CVE-2021-20225.patch new file mode 100644 index 0000000..e161ad0 --- /dev/null +++ b/backport-CVE-2021-20225.patch @@ -0,0 +1,51 @@ +From 2a330dba93ff11bc00eda76e9419bc52b0c7ead6 +From: Daniel Kiper +Date: 2021-03-02 15:54:15 +0100 +Subject: [PATCH] lib/arg: Block repeated short options that require an argument +Fuzzing found the following crash: + + search -hhhhhhhhhhhhhf + +We didn't allocate enough option space for 13 hints because the +allocation code counts the number of discrete arguments (i.e. argc). +However, the shortopt parsing code will happily keep processing +a combination of short options without checking if those short +options require an argument. This means you can easily end writing +past the allocated option space. + +This fixes a OOB write which can cause heap corruption. + +Fixes: CVE-2021-20225 + +Reference:http://git.savannah.gnu.org/cgit/grub.git/commit/?id=2a330dba93ff11bc00eda76e9419bc52b0c7ead6 + +Reported-by: Daniel Axtens +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +Diffstat +-rw-r--r-- grub-core/lib/arg.c 13 +1 files changed, 13 insertions, 0 deletions +diff --git a/grub-core/lib/arg.c b/grub-core/lib/arg.c +index 8439a0062..ade82d5dc 100644 +--- a/grub-core/lib/arg.c ++++ b/grub-core/lib/arg.c +@@ -299,6 +299,19 @@ grub_arg_parse (grub_extcmd_t cmd, int argc, char **argv, + it can have an argument value. */ + if (*curshort) + { ++ /* ++ * Only permit further short opts if this one doesn't ++ * require a value. ++ */ ++ if (opt->type != ARG_TYPE_NONE && ++ !(opt->flags & GRUB_ARG_OPTION_OPTIONAL)) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("missing mandatory option for `%s'"), ++ opt->longarg); ++ goto fail; ++ } ++ + if (parse_option (cmd, opt, 0, usr) || grub_errno) + goto fail; + } diff --git a/backport-CVE-2021-20233.patch b/backport-CVE-2021-20233.patch new file mode 100644 index 0000000..0909104 --- /dev/null +++ b/backport-CVE-2021-20233.patch @@ -0,0 +1,44 @@ +From 2f533a89a8dfcacbf2c9dbc77d910f111f24bf33 +From: Daniel Kiper +Date: 2021-03-02 15:54:15 +0100 +Subject: [PATCH] commands/menuentry: Fix quoting in setparams_prefix() +Commit 9acdcbf32542 (use single quotes in menuentry setparams command) +says that expressing a quoted single quote will require 3 characters. It +actually requires (and always did require!) 4 characters: + + str: a'b => a'\''b + len: 3 => 6 (2 for the letters + 4 for the quote) + +This leads to not allocating enough memory and thus out of bounds writes +that have been observed to cause heap corruption. + +Allocate 4 bytes for each single quote. + +Commit 22e7dbb2bb81 (Fix quoting in legacy parser.) does the same +quoting, but it adds 3 as extra overhead on top of the single byte that +the quote already needs. So it's correct. + +Fixes: 9acdcbf32542 (use single quotes in menuentry setparams command) +Fixes: CVE-2021-20233 + +Reference:http://git.savannah.gnu.org/cgit/grub.git/commit/?id=2f533a89a8dfcacbf2c9dbc77d910f111f24bf33 + +Reported-by: Daniel Axtens +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +Diffstat +-rw-r--r-- grub-core/commands/menuentry.c 2 +1 files changed, 1 insertions, 1 deletions +diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c +index 9164df744..720e6d8ea 100644 +--- a/grub-core/commands/menuentry.c ++++ b/grub-core/commands/menuentry.c +@@ -230,7 +230,7 @@ setparams_prefix (int argc, char **args) + len += 3; /* 3 = 1 space + 2 quotes */ + p = args[i]; + while (*p) +- len += (*p++ == '\'' ? 3 : 1); ++ len += (*p++ == '\'' ? 4 : 1); + } + + result = grub_malloc (len + 2); diff --git a/grub.patches b/grub.patches index 43501a6..c7ef8e5 100644 --- a/grub.patches +++ b/grub.patches @@ -248,3 +248,14 @@ Patch0247: 0247-linux-Fix-integer-overflows-in-initrd-size-handling.patch Patch0248: 0248-linuxefi-fail-kernel-validation-without-shim-protoco.patch Patch0249: 0249-remove-08_fallback_counting.in-apply-grubby.patch Patch0250: 0250-tftp-roll-over-block-counter-to-prevent-timeouts-wit.patch +Patch0251: backport-CVE-2020-25632.patch +Patch0252: backport-CVE-2020-25647.patch +Patch0253: backport-0001-CVE-2020-27749.patch +Patch0254: backport-0002-CVE-2020-27749.patch +Patch0255: backport-0003-CVE-2020-27749.patch +Patch0256: backport-0004-CVE-2020-27749.patch +Patch0257: backport-0005-CVE-2020-27749.patch +Patch0258: backport-0006-CVE-2020-27749.patch +Patch0259: backport-0007-CVE-2020-27749.patch +Patch0260: backport-CVE-2021-20225.patch +Patch0261: backport-CVE-2020-20233.patch diff --git a/grub2.spec b/grub2.spec index 3fc4649..56de6b5 100644 --- a/grub2.spec +++ b/grub2.spec @@ -7,7 +7,7 @@ Name: grub2 Epoch: 1 Version: 2.04 -Release: 9 +Release: 10 Summary: Bootloader with support for Linux, Multiboot and more License: GPLv3+ URL: http://www.gnu.org/software/grub/ @@ -448,6 +448,12 @@ rm -r /boot/grub2.tmp/ || : %{_datadir}/man/man* %changelog +* Thu May 11 2021 yanglu - 2.04-10 +- Type:cves +- Id:CVE-2020-25632 CVE-2020-25647 CVE-2020-27749 CVE-2021-20225 CVE-2021-20233 +- SUG:NA +- DESC:fix CVE-2020-25632 CVE-2020-25647 CVE-2020-27749 CVE-2021-20225 CVE-2021-20233 + * Sat Feb 27 2021 fengtao - 2.04-9 - Type:bugfix - ID:NA -- Gitee