fix CVE
This commit is contained in:
parent
e21afe78df
commit
581b26921d
50
backport-0001-CVE-2020-27749.patch
Normal file
50
backport-0001-CVE-2020-27749.patch
Normal file
@ -0,0 +1,50 @@
|
||||
From d06161b035dde4769199ad65aa0a587a5920012b Mon Sep 17 00:00:00 2001
|
||||
From: Darren Kenny <darren.kenny@oracle.com>
|
||||
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 <darren.kenny@oracle.com>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
---
|
||||
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
|
||||
|
||||
77
backport-0002-CVE-2020-27749.patch
Normal file
77
backport-0002-CVE-2020-27749.patch
Normal file
@ -0,0 +1,77 @@
|
||||
From c6c426e5ab6ea715153b72584de6bd8c82f698ec Mon Sep 17 00:00:00 2001
|
||||
From: Chris Coulson <chris.coulson@canonical.com>
|
||||
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 <chris.coulson@canonical.com>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
---
|
||||
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
|
||||
|
||||
119
backport-0003-CVE-2020-27749.patch
Normal file
119
backport-0003-CVE-2020-27749.patch
Normal file
@ -0,0 +1,119 @@
|
||||
From b1c9e9e889e4273fb15712051c887e6078511448 Mon Sep 17 00:00:00 2001
|
||||
From: Chris Coulson <chris.coulson@canonical.com>
|
||||
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 <chris.coulson@canonical.com>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
---
|
||||
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
|
||||
|
||||
65
backport-0004-CVE-2020-27749.patch
Normal file
65
backport-0004-CVE-2020-27749.patch
Normal file
@ -0,0 +1,65 @@
|
||||
From 3d157bbd06506b170fde5ec23980c4bf9f7660e2 Mon Sep 17 00:00:00 2001
|
||||
From: Chris Coulson <chris.coulson@canonical.com>
|
||||
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 <chris.coulson@canonical.com>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
---
|
||||
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
|
||||
|
||||
90
backport-0005-CVE-2020-27749.patch
Normal file
90
backport-0005-CVE-2020-27749.patch
Normal file
@ -0,0 +1,90 @@
|
||||
From 8bc817014ce3d7a498db44eae33c8b90e2430926 Mon Sep 17 00:00:00 2001
|
||||
From: Chris Coulson <chris.coulson@canonical.com>
|
||||
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 <chris.coulson@canonical.com>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
---
|
||||
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
|
||||
307
backport-0006-CVE-2020-27749.patch
Normal file
307
backport-0006-CVE-2020-27749.patch
Normal file
@ -0,0 +1,307 @@
|
||||
From 030fb6c4fa354cdbd6a8d6903dfed5d36eaf3cb2 Mon Sep 17 00:00:00 2001
|
||||
From: Chris Coulson <chris.coulson@canonical.com>
|
||||
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 <chris.coulson@canonical.com>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
---
|
||||
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 <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/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.23.0
|
||||
|
||||
247
backport-0007-CVE-2020-27749.patch
Normal file
247
backport-0007-CVE-2020-27749.patch
Normal file
@ -0,0 +1,247 @@
|
||||
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>
|
||||
---
|
||||
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 <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,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
|
||||
|
||||
83
backport-CVE-2020-25632.patch
Normal file
83
backport-CVE-2020-25632.patch
Normal file
@ -0,0 +1,83 @@
|
||||
From 7630ec5397fe418276b360f9011934b8c034936c
|
||||
From: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
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 <chris.coulson@canonical.com>
|
||||
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
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
|
||||
110
backport-CVE-2020-25647.patch
Normal file
110
backport-CVE-2020-25647.patch
Normal file
@ -0,0 +1,110 @@
|
||||
From 128c16a682034263eb519c89bc0934eeb6fa8cfa
|
||||
From: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
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 <joseph.tartaro@ioactive.com>
|
||||
Reported-by: Ilja Van Sprundel <ivansprundel@ioactive.com>
|
||||
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
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 <grub/usbdesc.h>
|
||||
#include <grub/usbtrans.h>
|
||||
|
||||
+#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;
|
||||
51
backport-CVE-2021-20225.patch
Normal file
51
backport-CVE-2021-20225.patch
Normal file
@ -0,0 +1,51 @@
|
||||
From 2a330dba93ff11bc00eda76e9419bc52b0c7ead6
|
||||
From: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
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 <dja@axtens.net>
|
||||
Signed-off-by: Daniel Axtens <dja@axtens.net>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
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;
|
||||
}
|
||||
44
backport-CVE-2021-20233.patch
Normal file
44
backport-CVE-2021-20233.patch
Normal file
@ -0,0 +1,44 @@
|
||||
From 2f533a89a8dfcacbf2c9dbc77d910f111f24bf33
|
||||
From: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
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 <dja@axtens.net>
|
||||
Signed-off-by: Daniel Axtens <dja@axtens.net>
|
||||
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
|
||||
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);
|
||||
11
grub.patches
11
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-2021-20233.patch
|
||||
|
||||
@ -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
|
||||
* Fri Mar 12 2021 yanglu <yanglu60@huawei.com> - 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 <fengtao40@huawei.com> - 2.04-9
|
||||
- Type:bugfix
|
||||
- ID:NA
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user