summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStanislav Malyshev <stas@php.net>2015-05-10 23:06:08 -0700
committerStanislav Malyshev <stas@php.net>2015-05-10 23:06:08 -0700
commitba1d9cc4b730811c0366158f3157af26268814a6 (patch)
treec20d6461331f218992f083037d4acb8c072d0c26
parente2bbf0a2df2cd864fa86d613eb316b249811a6f6 (diff)
downloadphp-git-ba1d9cc4b730811c0366158f3157af26268814a6.tar.gz
Fix bug #69522 - do not allow int overflow
-rw-r--r--ext/standard/pack.c139
1 files changed, 70 insertions, 69 deletions
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;
}