diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-01-10 13:22:25 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-01-10 13:22:25 +0100 |
commit | baa41c785551ae0580526298aa6fadf4534fc8c0 (patch) | |
tree | fd23926ca1e7d7f2be2b2b4e2dd24fb32a7e8501 /shell | |
parent | 2c876774a90ddb7478937ead096937f64e6bd7ec (diff) |
ash: make ${v:N:M} more robust for very large M by clamping to MIN/MAX_INT
Before this patch, "${v:2:0x100000001}" = "${v:2:1}",
and similarly, constructs like "${v:2:9999999999}" may give wrong result
due to int overflows.
function old new delta
substr_atoi - 43 +43
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 38 |
1 files changed, 25 insertions, 13 deletions
diff --git a/shell/ash.c b/shell/ash.c index 83a8e77f9..a7f330c11 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -5780,6 +5780,26 @@ ash_arith(const char *s) return result; } #endif +#if BASH_SUBSTR +# if ENABLE_FEATURE_SH_MATH +static int substr_atoi(const char *s) +{ + arith_t t = ash_arith(s); + if (sizeof(t) > sizeof(int)) { + /* clamp very large or very large negative nums for ${v:N:M}: + * else "${v:0:0x100000001}" would work as "${v:0:1}" + */ + if (t > INT_MAX) + t = INT_MAX; + if (t < INT_MIN) + t = INT_MIN; + } + return t; +} +# else +# define substr_atoi(s) number(s) +# endif +#endif /* * expandarg flags @@ -6816,13 +6836,10 @@ subevalvar(char *p, char *varname, int strloc, int subtype, loc = str = stackblock() + strloc; -# if !ENABLE_FEATURE_SH_MATH -# define ash_arith number -# endif /* Read POS in ${var:POS:LEN} */ colon = strchr(loc, ':'); if (colon) *colon = '\0'; - pos = ash_arith(loc); + pos = substr_atoi(loc); if (colon) *colon = ':'; /* Read LEN in ${var:POS:LEN} */ @@ -6830,7 +6847,6 @@ subevalvar(char *p, char *varname, int strloc, int subtype, /* *loc != '\0', guaranteed by parser */ if (quotes) { char *ptr; - /* Adjust the length by the number of escapes */ for (ptr = startp; ptr < (str - 1); ptr++) { if ((unsigned char)*ptr == CTLESC) { @@ -6842,19 +6858,15 @@ subevalvar(char *p, char *varname, int strloc, int subtype, orig_len = len; if (*loc++ == ':') { /* ${var::LEN} */ - len = ash_arith(loc); + len = substr_atoi(loc); } else { /* Skip POS in ${var:POS:LEN} */ len = orig_len; - while (*loc && *loc != ':') { + while (*loc && *loc != ':') loc++; - } - if (*loc++ == ':') { - len = ash_arith(loc); - } + if (*loc++ == ':') + len = substr_atoi(loc); } -# undef ash_arith - if (pos < 0) { /* ${VAR:$((-n)):l} starts n chars from the end */ pos = orig_len + pos; |