mirror of
https://git.savannah.gnu.org/git/grub.git
synced 2026-10-23 07:39:22 +00:00
commands/test: Stack overflow due to unlimited recursion depth
The test_parse() evaluates test expression recursively. Due to lack of recursion depth check a specially crafted expression may cause a stack overflow. The recursion is only triggered by the parentheses usage and it can be unlimited. However, sensible expressions are unlikely to contain more than a few parentheses. So, this patch limits the recursion depth to 100, which should be sufficient. Reported-by: Nils Langius <nils@langius.de> Signed-off-by: Lidong Chen <lidong.chen@oracle.com> Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
This commit is contained in:
1 parent
dad8f50297
commit
c68b7d2362
1 file changed
+18
-3
@@ -29,6 +29,9 @@
|
|||||||
|
|
||||||
GRUB_MOD_LICENSE ("GPLv3+");
|
GRUB_MOD_LICENSE ("GPLv3+");
|
||||||
|
|
||||||
|
/* Set a limit on recursion to avoid stack overflow. */
|
||||||
|
#define MAX_TEST_RECURSION_DEPTH 100
|
||||||
|
|
||||||
/* A simple implementation for signed numbers. */
|
/* A simple implementation for signed numbers. */
|
||||||
static int
|
static int
|
||||||
grub_strtosl (char *arg, const char ** const end, int base)
|
grub_strtosl (char *arg, const char ** const end, int base)
|
||||||
@@ -150,7 +153,7 @@ get_fileinfo (char *path, struct test_parse_ctx *ctx)
|
|||||||
|
|
||||||
/* Parse a test expression starting from *argn. */
|
/* Parse a test expression starting from *argn. */
|
||||||
static int
|
static int
|
||||||
test_parse (char **args, int *argn, int argc)
|
test_parse (char **args, int *argn, int argc, int *depth)
|
||||||
{
|
{
|
||||||
struct test_parse_ctx ctx = {
|
struct test_parse_ctx ctx = {
|
||||||
.and = 1,
|
.and = 1,
|
||||||
@@ -387,13 +390,24 @@ test_parse (char **args, int *argn, int argc)
|
|||||||
if (grub_strcmp (args[*argn], ")") == 0)
|
if (grub_strcmp (args[*argn], ")") == 0)
|
||||||
{
|
{
|
||||||
(*argn)++;
|
(*argn)++;
|
||||||
|
if (*depth > 0)
|
||||||
|
(*depth)--;
|
||||||
|
|
||||||
return ctx.or || ctx.and;
|
return ctx.or || ctx.and;
|
||||||
}
|
}
|
||||||
/* Recursively invoke if parenthesis. */
|
/* Recursively invoke if parenthesis. */
|
||||||
if (grub_strcmp (args[*argn], "(") == 0)
|
if (grub_strcmp (args[*argn], "(") == 0)
|
||||||
{
|
{
|
||||||
(*argn)++;
|
(*argn)++;
|
||||||
update_val (test_parse (args, argn, argc), &ctx);
|
|
||||||
|
if (++(*depth) > MAX_TEST_RECURSION_DEPTH)
|
||||||
|
{
|
||||||
|
grub_error (GRUB_ERR_OUT_OF_RANGE, N_("max recursion depth exceeded"));
|
||||||
|
depth--;
|
||||||
|
return ctx.or || ctx.and;
|
||||||
|
}
|
||||||
|
|
||||||
|
update_val (test_parse (args, argn, argc, depth), &ctx);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -428,11 +442,12 @@ grub_cmd_test (grub_command_t cmd __attribute__ ((unused)),
|
|||||||
int argc, char **args)
|
int argc, char **args)
|
||||||
{
|
{
|
||||||
int argn = 0;
|
int argn = 0;
|
||||||
|
int depth = 0;
|
||||||
|
|
||||||
if (argc >= 1 && grub_strcmp (args[argc - 1], "]") == 0)
|
if (argc >= 1 && grub_strcmp (args[argc - 1], "]") == 0)
|
||||||
argc--;
|
argc--;
|
||||||
|
|
||||||
return test_parse (args, &argn, argc) ? GRUB_ERR_NONE
|
return test_parse (args, &argn, argc, &depth) ? GRUB_ERR_NONE
|
||||||
: grub_error (GRUB_ERR_TEST_FAILURE, N_("false"));
|
: grub_error (GRUB_ERR_TEST_FAILURE, N_("false"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user