diff options
author | Ard Biesheuvel <ardb@kernel.org> | 2020-02-10 17:02:46 +0100 |
---|---|---|
committer | Ard Biesheuvel <ardb@kernel.org> | 2020-02-23 21:57:15 +0100 |
commit | 91d150c0cc637b9d9d6394936add7cd2b7ccc410 (patch) | |
tree | cc604ef224f2a8c476d19984b6d0ef42454c25f0 /drivers/firmware/efi/libstub/string.c | |
parent | 31f5e546655b502d508e160e6cab20462089e34d (diff) | |
download | linux-91d150c0cc637b9d9d6394936add7cd2b7ccc410.tar.gz linux-91d150c0cc637b9d9d6394936add7cd2b7ccc410.tar.bz2 linux-91d150c0cc637b9d9d6394936add7cd2b7ccc410.zip |
efi/libstub: Clean up command line parsing routine
We currently parse the command non-destructively, to avoid having to
allocate memory for a copy before passing it to the standard parsing
routines that are used by the core kernel, and which modify the input
to delineate the parsed tokens with NUL characters.
Instead, we call strstr() and strncmp() to go over the input multiple
times, and match prefixes rather than tokens, which implies that we
would match, e.g., 'nokaslrfoo' in the stub and disable KASLR, while
the kernel would disregard the option and run with KASLR enabled.
In order to avoid having to reason about whether and how this behavior
may be abused, let's clean up the parsing routines, and rebuild them
on top of the existing helpers.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Diffstat (limited to 'drivers/firmware/efi/libstub/string.c')
-rw-r--r-- | drivers/firmware/efi/libstub/string.c | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/drivers/firmware/efi/libstub/string.c b/drivers/firmware/efi/libstub/string.c index ed10e3f602c5..1ac2f8764715 100644 --- a/drivers/firmware/efi/libstub/string.c +++ b/drivers/firmware/efi/libstub/string.c @@ -6,6 +6,7 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ +#include <linux/ctype.h> #include <linux/types.h> #include <linux/string.h> @@ -56,3 +57,58 @@ int strncmp(const char *cs, const char *ct, size_t count) return 0; } #endif + +/* Works only for digits and letters, but small and fast */ +#define TOLOWER(x) ((x) | 0x20) + +static unsigned int simple_guess_base(const char *cp) +{ + if (cp[0] == '0') { + if (TOLOWER(cp[1]) == 'x' && isxdigit(cp[2])) + return 16; + else + return 8; + } else { + return 10; + } +} + +/** + * simple_strtoull - convert a string to an unsigned long long + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ + +unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base) +{ + unsigned long long result = 0; + + if (!base) + base = simple_guess_base(cp); + + if (base == 16 && cp[0] == '0' && TOLOWER(cp[1]) == 'x') + cp += 2; + + while (isxdigit(*cp)) { + unsigned int value; + + value = isdigit(*cp) ? *cp - '0' : TOLOWER(*cp) - 'a' + 10; + if (value >= base) + break; + result = result * base + value; + cp++; + } + if (endp) + *endp = (char *)cp; + + return result; +} + +long simple_strtol(const char *cp, char **endp, unsigned int base) +{ + if (*cp == '-') + return -simple_strtoull(cp + 1, endp, base); + + return simple_strtoull(cp, endp, base); +} |