[git commit] ash: make ${v:N:M} more robust for very large M by clamping to MIN/MAX_INT

Denys Vlasenko vda.linux at googlemail.com
Wed Jan 10 12:22:25 UTC 2018


commit: https://git.busybox.net/busybox/commit/?id=baa41c785551ae0580526298aa6fadf4534fc8c0
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

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 at googlemail.com>
---
 shell/ash.c | 38 +++++++++++++++++++++++++-------------
 1 file changed, 25 insertions(+), 13 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index 83a8e77..a7f330c 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;


More information about the busybox-cvs mailing list