Message ID | 20230707045055.8314-1-hprajapati@mvista.com |
---|---|
State | New, archived |
Headers | show |
Series | [dunfell,PATCHv2] grub2: Fix Multiple CVEs | expand |
On Fri, 2023-07-07 at 10:20 +0530, Hitendra Prajapati wrote: > Backport fixes for: > * CVE-2020-27749 - Upstream-Status: Backport from > https://git.savannah.gnu.org/cgit/grub.git/commit/?h=grub-2.06&id=4ea7bae51f97e49c84dc67ea30b466ca8633b9f6 > * CVE-2021-20225 - Upstream-Status: Backport from > https://git.savannah.gnu.org/cgit/grub.git/commit/?h=grub-2.06&id=2a330dba93ff11bc00eda76e9419bc52b0c7ead6 > * CVE-2021-20233 - Upstream-Status: Backport from > https://git.savannah.gnu.org/cgit/grub.git/commit/?h=grub-2.06&id=2f533a89a8dfcacbf2c9dbc77d910f111f24bf33 > > Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> > --- > .../grub/files/CVE-2020-27749.patch | 609 > ++++++++++++++++++ > .../grub/files/CVE-2021-20225.patch | 58 ++ > .../grub/files/CVE-2021-20233.patch | 50 ++ > meta/recipes-bsp/grub/grub2.inc | 3 + > 4 files changed, 720 insertions(+) > create mode 100644 meta/recipes-bsp/grub/files/CVE-2020-27749.patch > create mode 100644 meta/recipes-bsp/grub/files/CVE-2021-20225.patch > create mode 100644 meta/recipes-bsp/grub/files/CVE-2021-20233.patch > > diff --git a/meta/recipes-bsp/grub/files/CVE-2020-27749.patch > b/meta/recipes-bsp/grub/files/CVE-2020-27749.patch > new file mode 100644 > index 0000000000..b95be47772 > --- /dev/null > +++ b/meta/recipes-bsp/grub/files/CVE-2020-27749.patch > @@ -0,0 +1,609 @@ > +From 4ea7bae51f97e49c84dc67ea30b466ca8633b9f6 Mon Sep 17 00:00:00 > 2001 > +From: Chris Coulson <chris.coulson@canonical.com> > +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 <chris.coulson@canonical.com> > +Signed-off-by: Chris Coulson <chris.coulson@canonical.com> > +Signed-off-by: Darren Kenny <darren.kenny@oracle.com> > +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> > + > +Upstream-Status: Backport > [https://git.savannah.gnu.org/cgit/grub.git/commit/?h=grub-2.06&id=4e > a7bae51f97e49c84dc67ea30b466ca8633b9f6] The patch below doesn't look like a backport of this. Perhaps the dependent patches should be included separately or at least mentioned here in commit message so it's clear where the changes are coming from. Thanks, Anuj > +CVE: CVE-2020-27749 > + > +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> > +--- > + grub-core/Makefile.core.def | 1 + > + grub-core/kern/buffer.c | 117 +++++++++++++++++++++ > + grub-core/kern/parser.c | 204 +++++++++++++++++++++++---------- > --- > + include/grub/buffer.h | 144 +++++++++++++++++++++++++ > + 4 files changed, 395 insertions(+), 71 deletions(-) > + 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 651ea2a..823cd57 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..9f5f8b8 > +--- /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 <http://www.gnu.org/licenses/>. > ++ */ > ++ > ++#include <grub/buffer.h> > ++#include <grub/err.h> > ++#include <grub/misc.h> > ++#include <grub/mm.h> > ++#include <grub/safemath.h> > ++#include <grub/types.h> > ++ > ++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/grub-core/kern/parser.c b/grub-core/kern/parser.c > +index d1cf061..6ab7aa4 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 > +@@ -18,6 +18,7 @@ > + */ > + > + #include <grub/parser.h> > ++#include <grub/buffer.h> > + #include <grub/env.h> > + #include <grub/misc.h> > + #include <grub/mm.h> > +@@ -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,17 +117,74 @@ 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 grub_err_t > ++terminate_arg (grub_buffer_t buffer, int *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, grub_buffer_t buffer, grub_buffer_t varname, > ++ 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. > ++ */ > ++ if (add_var (varname, buffer, state, *newstate) != GRUB_ERR_NONE) > ++ return grub_errno; > ++ > ++ if (check_varstate (*newstate)) > ++ { > ++ if (use) > ++ return grub_buffer_append_char (varname, 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. > ++ */ > ++ return terminate_arg (buffer, argc); > ++ } > ++ else if (use) > ++ return grub_buffer_append_char (buffer, use); > ++ > ++ return GRUB_ERR_NONE; > + } > + > + grub_err_t > +@@ -135,24 +193,36 @@ 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 *vp = varname; > +- char *args; > ++ char *rp = rd; > + 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 (!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,39 +230,14 @@ 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); > ++ if (process_char (*rp, buffer, varname, state, argc, > ++ &newstate) != GRUB_ERR_NONE) > ++ goto fail; > + > +- /* 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)) > +- { > +- *(bp++) = '\0'; > +- (*argc)++; > +- } > +- } > +- else if (use) > +- *(bp++) = use; > +- } > + state = newstate; > + } > + } > +@@ -200,43 +245,60 @@ 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; > + > +- if (bp != buffer && *(bp - 1)) > +- { > +- *(bp++) = '\0'; > +- (*argc)++; > +- } > ++ /* Ensure that the last argument is terminated. */ > ++ if (terminate_arg (buffer, argc) != GRUB_ERR_NONE) > ++ goto fail; > + > + /* 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) > +- return grub_errno; > +- grub_memcpy (args, buffer, bp - buffer); > ++ { > ++ grub_errno = GRUB_ERR_NONE; > ++ goto out; > ++ } > + > + *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. */ > +- 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; > + } > + > +- return 0; > ++ /* 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); > ++ goto out; > + } > + > + /* Helper for grub_parser_execute. */ > +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 <http://www.gnu.org/licenses/>. > ++ */ > ++ > ++#ifndef GRUB_BUFFER_H > ++#define GRUB_BUFFER_H 1 > ++ > ++#include <grub/err.h> > ++#include <grub/misc.h> > ++#include <grub/mm.h> > ++#include <grub/safemath.h> > ++#include <grub/types.h> > ++ > ++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.25.1 > + > diff --git a/meta/recipes-bsp/grub/files/CVE-2021-20225.patch > b/meta/recipes-bsp/grub/files/CVE-2021-20225.patch > new file mode 100644 > index 0000000000..b864febe62 > --- /dev/null > +++ b/meta/recipes-bsp/grub/files/CVE-2021-20225.patch > @@ -0,0 +1,58 @@ > +From 2a330dba93ff11bc00eda76e9419bc52b0c7ead6 Mon Sep 17 00:00:00 > 2001 > +From: Daniel Axtens <dja@axtens.net> > +Date: Fri, 22 Jan 2021 16:07:29 +1100 > +Subject: 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 > + > +Reported-by: Daniel Axtens <dja@axtens.net> > +Signed-off-by: Daniel Axtens <dja@axtens.net> > +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> > + > +Upstream-Status: Backport > [https://git.savannah.gnu.org/cgit/grub.git/commit/?h=grub-2.06&id=2a > 330dba93ff11bc00eda76e9419bc52b0c7ead6] > +CVE: CVE-2021-20225 > +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> > +--- > + grub-core/lib/arg.c | 13 +++++++++++++ > + 1 file changed, 13 insertions(+) > + > +diff --git a/grub-core/lib/arg.c b/grub-core/lib/arg.c > +index 3288609..537c5e9 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; > + } > +-- > +2.25.1 > + > diff --git a/meta/recipes-bsp/grub/files/CVE-2021-20233.patch > b/meta/recipes-bsp/grub/files/CVE-2021-20233.patch > new file mode 100644 > index 0000000000..d2069afc18 > --- /dev/null > +++ b/meta/recipes-bsp/grub/files/CVE-2021-20233.patch > @@ -0,0 +1,50 @@ > +From 2f533a89a8dfcacbf2c9dbc77d910f111f24bf33 Mon Sep 17 00:00:00 > 2001 > +From: Daniel Axtens <dja@axtens.net> > +Date: Fri, 22 Jan 2021 17:10:48 +1100 > +Subject: 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 > + > +Reported-by: Daniel Axtens <dja@axtens.net> > +Signed-off-by: Daniel Axtens <dja@axtens.net> > + > +Upstream-Status: Backport > [https://git.savannah.gnu.org/cgit/grub.git/commit/?h=grub-2.06&id=2f > 533a89a8dfcacbf2c9dbc77d910f111f24bf33] > +CVE: CVE-2021-20233 > +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> > +--- > + grub-core/commands/menuentry.c | 2 +- > + 1 file changed, 1 insertion(+), 1 deletion(-) > + > +diff --git a/grub-core/commands/menuentry.c b/grub- > core/commands/menuentry.c > +index 9164df7..720e6d8 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); > +-- > +2.25.1 > + > diff --git a/meta/recipes-bsp/grub/grub2.inc b/meta/recipes- > bsp/grub/grub2.inc > index d09eecd8ac..5a6e213936 100644 > --- a/meta/recipes-bsp/grub/grub2.inc > +++ b/meta/recipes-bsp/grub/grub2.inc > @@ -106,6 +106,9 @@ SRC_URI = "${GNU_MIRROR}/grub/grub-${PV}.tar.gz \ > > file://font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch \ > file://CVE-2022-2601.patch \ > file://CVE-2022-3775.patch \ > + file://CVE-2020-27749.patch \ > + file://CVE-2021-20225.patch \ > + file://CVE-2021-20233.patch \ > " > SRC_URI[md5sum] = "5ce674ca6b2612d8939b9e6abed32934" > SRC_URI[sha256sum] = > "f10c85ae3e204dbaec39ae22fa3c5e99f0665417e91c2cb49b7e5031658ba6ea" > > -=-=-=-=-=-=-=-=-=-=-=- > Links: You receive all messages sent to this group. > View/Reply Online (#183996): > https://lists.openembedded.org/g/openembedded-core/message/183996 > Mute This Topic: https://lists.openembedded.org/mt/100000567/3616702 > Group Owner: openembedded-core+owner@lists.openembedded.org > Unsubscribe: > https://lists.openembedded.org/g/openembedded-core/unsub [ > anuj.mittal@intel.com] > -=-=-=-=-=-=-=-=-=-=-=- >
diff --git a/meta/recipes-bsp/grub/files/CVE-2020-27749.patch b/meta/recipes-bsp/grub/files/CVE-2020-27749.patch new file mode 100644 index 0000000000..b95be47772 --- /dev/null +++ b/meta/recipes-bsp/grub/files/CVE-2020-27749.patch @@ -0,0 +1,609 @@ +From 4ea7bae51f97e49c84dc67ea30b466ca8633b9f6 Mon Sep 17 00:00:00 2001 +From: Chris Coulson <chris.coulson@canonical.com> +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 <chris.coulson@canonical.com> +Signed-off-by: Chris Coulson <chris.coulson@canonical.com> +Signed-off-by: Darren Kenny <darren.kenny@oracle.com> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> + +Upstream-Status: Backport [https://git.savannah.gnu.org/cgit/grub.git/commit/?h=grub-2.06&id=4ea7bae51f97e49c84dc67ea30b466ca8633b9f6] +CVE: CVE-2020-27749 + +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + grub-core/Makefile.core.def | 1 + + grub-core/kern/buffer.c | 117 +++++++++++++++++++++ + grub-core/kern/parser.c | 204 +++++++++++++++++++++++------------- + include/grub/buffer.h | 144 +++++++++++++++++++++++++ + 4 files changed, 395 insertions(+), 71 deletions(-) + 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 651ea2a..823cd57 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..9f5f8b8 +--- /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 <http://www.gnu.org/licenses/>. ++ */ ++ ++#include <grub/buffer.h> ++#include <grub/err.h> ++#include <grub/misc.h> ++#include <grub/mm.h> ++#include <grub/safemath.h> ++#include <grub/types.h> ++ ++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/grub-core/kern/parser.c b/grub-core/kern/parser.c +index d1cf061..6ab7aa4 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 +@@ -18,6 +18,7 @@ + */ + + #include <grub/parser.h> ++#include <grub/buffer.h> + #include <grub/env.h> + #include <grub/misc.h> + #include <grub/mm.h> +@@ -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,17 +117,74 @@ 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 grub_err_t ++terminate_arg (grub_buffer_t buffer, int *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, grub_buffer_t buffer, grub_buffer_t varname, ++ 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. ++ */ ++ if (add_var (varname, buffer, state, *newstate) != GRUB_ERR_NONE) ++ return grub_errno; ++ ++ if (check_varstate (*newstate)) ++ { ++ if (use) ++ return grub_buffer_append_char (varname, 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. ++ */ ++ return terminate_arg (buffer, argc); ++ } ++ else if (use) ++ return grub_buffer_append_char (buffer, use); ++ ++ return GRUB_ERR_NONE; + } + + grub_err_t +@@ -135,24 +193,36 @@ 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 *vp = varname; +- char *args; ++ char *rp = rd; + 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 (!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,39 +230,14 @@ 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); ++ if (process_char (*rp, buffer, varname, state, argc, ++ &newstate) != GRUB_ERR_NONE) ++ goto fail; + +- /* 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)) +- { +- *(bp++) = '\0'; +- (*argc)++; +- } +- } +- else if (use) +- *(bp++) = use; +- } + state = newstate; + } + } +@@ -200,43 +245,60 @@ 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; + +- if (bp != buffer && *(bp - 1)) +- { +- *(bp++) = '\0'; +- (*argc)++; +- } ++ /* Ensure that the last argument is terminated. */ ++ if (terminate_arg (buffer, argc) != GRUB_ERR_NONE) ++ goto fail; + + /* 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) +- return grub_errno; +- grub_memcpy (args, buffer, bp - buffer); ++ { ++ grub_errno = GRUB_ERR_NONE; ++ goto out; ++ } + + *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. */ +- 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; + } + +- return 0; ++ /* 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); ++ goto out; + } + + /* Helper for grub_parser_execute. */ +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 <http://www.gnu.org/licenses/>. ++ */ ++ ++#ifndef GRUB_BUFFER_H ++#define GRUB_BUFFER_H 1 ++ ++#include <grub/err.h> ++#include <grub/misc.h> ++#include <grub/mm.h> ++#include <grub/safemath.h> ++#include <grub/types.h> ++ ++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.25.1 + diff --git a/meta/recipes-bsp/grub/files/CVE-2021-20225.patch b/meta/recipes-bsp/grub/files/CVE-2021-20225.patch new file mode 100644 index 0000000000..b864febe62 --- /dev/null +++ b/meta/recipes-bsp/grub/files/CVE-2021-20225.patch @@ -0,0 +1,58 @@ +From 2a330dba93ff11bc00eda76e9419bc52b0c7ead6 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Fri, 22 Jan 2021 16:07:29 +1100 +Subject: 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 + +Reported-by: Daniel Axtens <dja@axtens.net> +Signed-off-by: Daniel Axtens <dja@axtens.net> +Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> + +Upstream-Status: Backport [https://git.savannah.gnu.org/cgit/grub.git/commit/?h=grub-2.06&id=2a330dba93ff11bc00eda76e9419bc52b0c7ead6] +CVE: CVE-2021-20225 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + grub-core/lib/arg.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/grub-core/lib/arg.c b/grub-core/lib/arg.c +index 3288609..537c5e9 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; + } +-- +2.25.1 + diff --git a/meta/recipes-bsp/grub/files/CVE-2021-20233.patch b/meta/recipes-bsp/grub/files/CVE-2021-20233.patch new file mode 100644 index 0000000000..d2069afc18 --- /dev/null +++ b/meta/recipes-bsp/grub/files/CVE-2021-20233.patch @@ -0,0 +1,50 @@ +From 2f533a89a8dfcacbf2c9dbc77d910f111f24bf33 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens <dja@axtens.net> +Date: Fri, 22 Jan 2021 17:10:48 +1100 +Subject: 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 + +Reported-by: Daniel Axtens <dja@axtens.net> +Signed-off-by: Daniel Axtens <dja@axtens.net> + +Upstream-Status: Backport [https://git.savannah.gnu.org/cgit/grub.git/commit/?h=grub-2.06&id=2f533a89a8dfcacbf2c9dbc77d910f111f24bf33] +CVE: CVE-2021-20233 +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> +--- + grub-core/commands/menuentry.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c +index 9164df7..720e6d8 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); +-- +2.25.1 + diff --git a/meta/recipes-bsp/grub/grub2.inc b/meta/recipes-bsp/grub/grub2.inc index d09eecd8ac..5a6e213936 100644 --- a/meta/recipes-bsp/grub/grub2.inc +++ b/meta/recipes-bsp/grub/grub2.inc @@ -106,6 +106,9 @@ SRC_URI = "${GNU_MIRROR}/grub/grub-${PV}.tar.gz \ file://font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch \ file://CVE-2022-2601.patch \ file://CVE-2022-3775.patch \ + file://CVE-2020-27749.patch \ + file://CVE-2021-20225.patch \ + file://CVE-2021-20233.patch \ " SRC_URI[md5sum] = "5ce674ca6b2612d8939b9e6abed32934" SRC_URI[sha256sum] = "f10c85ae3e204dbaec39ae22fa3c5e99f0665417e91c2cb49b7e5031658ba6ea"
Backport fixes for: * CVE-2020-27749 - Upstream-Status: Backport from https://git.savannah.gnu.org/cgit/grub.git/commit/?h=grub-2.06&id=4ea7bae51f97e49c84dc67ea30b466ca8633b9f6 * CVE-2021-20225 - Upstream-Status: Backport from https://git.savannah.gnu.org/cgit/grub.git/commit/?h=grub-2.06&id=2a330dba93ff11bc00eda76e9419bc52b0c7ead6 * CVE-2021-20233 - Upstream-Status: Backport from https://git.savannah.gnu.org/cgit/grub.git/commit/?h=grub-2.06&id=2f533a89a8dfcacbf2c9dbc77d910f111f24bf33 Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> --- .../grub/files/CVE-2020-27749.patch | 609 ++++++++++++++++++ .../grub/files/CVE-2021-20225.patch | 58 ++ .../grub/files/CVE-2021-20233.patch | 50 ++ meta/recipes-bsp/grub/grub2.inc | 3 + 4 files changed, 720 insertions(+) create mode 100644 meta/recipes-bsp/grub/files/CVE-2020-27749.patch create mode 100644 meta/recipes-bsp/grub/files/CVE-2021-20225.patch create mode 100644 meta/recipes-bsp/grub/files/CVE-2021-20233.patch