From: Stanislav Malyshev Date: Mon, 11 May 2015 06:06:08 +0000 (-0700) Subject: Fix bug #69522 - do not allow int overflow X-Git-Tag: php-5.4.41~3 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ba1d9cc4b730811c0366158f3157af26268814a6;p=php Fix bug #69522 - do not allow int overflow --- diff --git a/ext/standard/pack.c b/ext/standard/pack.c index d133e66d98..c1c2c7a02c 100644 --- a/ext/standard/pack.c +++ b/ext/standard/pack.c @@ -148,7 +148,7 @@ PHP_FUNCTION(pack) } else if (c >= '0' && c <= '9') { arg = atoi(&format[i]); - + while (format[i] >= '0' && format[i] <= '9' && i < formatlen) { i++; } @@ -158,8 +158,8 @@ PHP_FUNCTION(pack) /* Handle special arg '*' for all codes and check argv overflows */ switch ((int) code) { /* Never uses any args */ - case 'x': - case 'X': + case 'x': + case 'X': case '@': if (arg < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: '*' ignored", code); @@ -168,9 +168,9 @@ PHP_FUNCTION(pack) break; /* Always uses one arg */ - case 'a': - case 'A': - case 'h': + case 'a': + case 'A': + case 'h': case 'H': if (currentarg >= num_args) { efree(argv); @@ -192,20 +192,20 @@ PHP_FUNCTION(pack) break; /* Use as many args as specified */ - case 'c': - case 'C': - case 's': - case 'S': - case 'i': + case 'c': + case 'C': + case 's': + case 'S': + case 'i': case 'I': - case 'l': - case 'L': - case 'n': - case 'N': - case 'v': + case 'l': + case 'L': + case 'n': + case 'N': + case 'v': case 'V': - case 'f': - case 'd': + case 'f': + case 'd': if (arg < 0) { arg = num_args - currentarg; } @@ -243,34 +243,34 @@ PHP_FUNCTION(pack) int arg = formatargs[i]; switch ((int) code) { - case 'h': - case 'H': + case 'h': + case 'H': INC_OUTPUTPOS((arg + (arg % 2)) / 2,1) /* 4 bit per arg */ break; - case 'a': + case 'a': case 'A': - case 'c': + case 'c': case 'C': case 'x': INC_OUTPUTPOS(arg,1) /* 8 bit per arg */ break; - case 's': - case 'S': - case 'n': + case 's': + case 'S': + case 'n': case 'v': INC_OUTPUTPOS(arg,2) /* 16 bit per arg */ break; - case 'i': + case 'i': case 'I': INC_OUTPUTPOS(arg,sizeof(int)) break; - case 'l': - case 'L': - case 'N': + case 'l': + case 'L': + case 'N': case 'V': INC_OUTPUTPOS(arg,4) /* 32 bit per arg */ break; @@ -313,8 +313,8 @@ PHP_FUNCTION(pack) zval **val; switch ((int) code) { - case 'a': - case 'A': + case 'a': + case 'A': memset(&output[outputpos], (code == 'a') ? '\0' : ' ', arg); val = argv[currentarg++]; if (Z_ISREF_PP(val)) { @@ -326,7 +326,7 @@ PHP_FUNCTION(pack) outputpos += arg; break; - case 'h': + case 'h': case 'H': { int nibbleshift = (code == 'h') ? 0 : 4; int first = 1; @@ -372,7 +372,7 @@ PHP_FUNCTION(pack) break; } - case 'c': + case 'c': case 'C': while (arg-- > 0) { php_pack(argv[currentarg++], 1, byte_map, &output[outputpos]); @@ -380,9 +380,9 @@ PHP_FUNCTION(pack) } break; - case 's': - case 'S': - case 'n': + case 's': + case 'S': + case 'n': case 'v': { int *map = machine_endian_short_map; @@ -399,17 +399,17 @@ PHP_FUNCTION(pack) break; } - case 'i': - case 'I': + case 'i': + case 'I': while (arg-- > 0) { php_pack(argv[currentarg++], sizeof(int), int_map, &output[outputpos]); outputpos += sizeof(int); } break; - case 'l': - case 'L': - case 'N': + case 'l': + case 'L': + case 'N': case 'V': { int *map = machine_endian_long_map; @@ -503,7 +503,7 @@ static long php_unpack(char *data, int size, int issigned, int *map) /* unpack() is based on Perl's unpack(), but is modified a bit from there. * Rather than depending on error-prone ordered lists or syntactically - * unpleasant pass-by-reference, we return an object with named parameters + * unpleasant pass-by-reference, we return an object with named parameters * (like *_fetch_object()). Syntax is "f[repeat]name/...", where "f" is the * formatter char (like pack()), "[repeat]" is the optional repeater argument, * and "name" is the name of the variable to use. @@ -576,7 +576,7 @@ PHP_FUNCTION(unpack) switch ((int) type) { /* Never use any input */ - case 'X': + case 'X': size = -1; break; @@ -584,43 +584,43 @@ PHP_FUNCTION(unpack) size = 0; break; - case 'a': + case 'a': case 'A': size = arg; arg = 1; break; - case 'h': - case 'H': + case 'h': + case 'H': size = (arg > 0) ? (arg + (arg % 2)) / 2 : arg; arg = 1; break; /* Use 1 byte of input */ - case 'c': + case 'c': case 'C': case 'x': size = 1; break; /* Use 2 bytes of input */ - case 's': - case 'S': - case 'n': + case 's': + case 'S': + case 'n': case 'v': size = 2; break; /* Use sizeof(int) bytes of input */ - case 'i': + case 'i': case 'I': size = sizeof(int); break; /* Use 4 bytes of input */ - case 'l': - case 'L': - case 'N': + case 'l': + case 'L': + case 'N': case 'V': size = 4; break; @@ -657,12 +657,13 @@ PHP_FUNCTION(unpack) if (size != 0 && size != -1 && INT_MAX - size + 1 < inputpos) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: integer overflow", type); - inputpos = 0; + zval_dtor(return_value); + RETURN_FALSE; } if ((inputpos + size) <= inputlen) { switch ((int) type) { - case 'a': + case 'a': case 'A': { char pad = (type == 'a') ? '\0' : ' '; int len = inputlen - inputpos; /* Remaining string */ @@ -683,8 +684,8 @@ PHP_FUNCTION(unpack) add_assoc_stringl(return_value, n, &input[inputpos], len + 1, 1); break; } - - case 'h': + + case 'h': case 'H': { int len = (inputlen - inputpos) * 2; /* Remaining */ int nibbleshift = (type == 'h') ? 0 : 4; @@ -695,9 +696,9 @@ PHP_FUNCTION(unpack) /* If size was given take minimum of len and size */ if (size >= 0 && len > (size * 2)) { len = size * 2; - } + } - if (argb > 0) { + if (len > 0 && argb > 0) { len -= argb % 2; } @@ -727,7 +728,7 @@ PHP_FUNCTION(unpack) break; } - case 'c': + case 'c': case 'C': { int issigned = (type == 'c') ? (input[inputpos] & 0x80) : 0; long v = php_unpack(&input[inputpos], 1, issigned, byte_map); @@ -735,9 +736,9 @@ PHP_FUNCTION(unpack) break; } - case 's': - case 'S': - case 'n': + case 's': + case 'S': + case 'n': case 'v': { long v; int issigned = 0; @@ -756,7 +757,7 @@ PHP_FUNCTION(unpack) break; } - case 'i': + case 'i': case 'I': { long v; int issigned = 0; @@ -770,9 +771,9 @@ PHP_FUNCTION(unpack) break; } - case 'l': - case 'L': - case 'N': + case 'l': + case 'L': + case 'N': case 'V': { int issigned = 0; int *map = machine_endian_long_map; @@ -795,7 +796,7 @@ PHP_FUNCTION(unpack) v |= php_unpack(&input[inputpos], 4, issigned, map); if (sizeof(long) > 4) { if (type == 'l') { - v = (signed int) v; + v = (signed int) v; } else { v = (unsigned int) v; }