cvs: php-src /ext/standard php_var.h var.c var_unserializer.c /ext/standard/tests/serialize bug25378.phpt

From: Date: Sun, 05 Sep 2004 16:29:05 +0000
Subject: cvs: php-src /ext/standard php_var.h var.c var_unserializer.c /ext/standard/tests/serialize bug25378.phpt
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-28569@lists.php.net to get a copy of this message
helly Sun Sep 5 12:29:05 2004 EDT Modified files: /php-src/ext/standard php_var.h var_unserializer.c var.c /php-src/ext/standard/tests/serialize bug25378.phpt Log: - Add some checks when unserializing data to prevent buffer overflows

http://cvs.php.net/diff.php/php-src/ext/standard/php_var.h?r1=1.27&r2=1.28&ty=u Index: php-src/ext/standard/php_var.h diff -u php-src/ext/standard/php_var.h:1.27 php-src/ext/standard/php_var.h:1.28 --- php-src/ext/standard/php_var.h:1.27 Thu Jan 8 12:32:51 2004 +++ php-src/ext/standard/php_var.h Sun Sep 5 12:29:04 2004 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_var.h,v 1.27 2004/01/08 17:32:51 sniper Exp $ */ +/* $Id: php_var.h,v 1.28 2004/09/05 16:29:04 helly Exp $ */ #ifndef PHP_VAR_H #define PHP_VAR_H @@ -46,7 +46,7 @@ typedef struct php_unserialize_data php_unserialize_data_t; PHPAPI void php_var_serialize(smart_str *buf, zval **struc, php_serialize_data_t *var_hash TSRMLS_DC); -PHPAPI int php_var_unserialize(zval **rval, const char **p, const char *max, php_unserialize_data_t *var_hash TSRMLS_DC); +PHPAPI int php_var_unserialize(zval **rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC); #define PHP_VAR_SERIALIZE_INIT(var_hash) \ zend_hash_init(&(var_hash), 10, NULL, NULL, 0) http://cvs.php.net/diff.php/php-src/ext/standard/var_unserializer.c?r1=1.39&r2=1.40&ty=u Index: php-src/ext/standard/var_unserializer.c diff -u php-src/ext/standard/var_unserializer.c:1.39 php-src/ext/standard/var_unserializer.c:1.40 --- php-src/ext/standard/var_unserializer.c:1.39 Mon Jul 19 03:19:46 2004 +++ php-src/ext/standard/var_unserializer.c Sun Sep 5 12:29:04 2004 @@ -1,5 +1,5 @@ -/* Generated by re2c 0.9.2 on Sat Mar 27 02:27:57 2004 */ -#line 1 "/usr/src/php5/ext/standard/var_unserializer.re" +/* Generated by re2c 0.9.4 on Thu Sep 2 20:41:03 2004 */ +#line 1 "/usr/src/php-cvs/ext/standard/var_unserializer.re" /* +----------------------------------------------------------------------+ | PHP Version 5 | @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: var_unserializer.c,v 1.39 2004/07/19 07:19:46 andi Exp $ */ +/* $Id: var_unserializer.c,v 1.40 2004/09/05 16:29:04 helly Exp $ */ #include "php.h" #include "ext/standard/php_var.h" @@ -111,12 +111,12 @@ #define YYMARKER marker -#line 118 "/usr/src/php5/ext/standard/var_unserializer.re" +#line 118 "/usr/src/php-cvs/ext/standard/var_unserializer.re" -static inline int parse_iv2(const char *p, const char **q) +static inline int parse_iv2(const unsigned char *p, const unsigned char **q) { char cursor; int result = 0; @@ -131,7 +131,7 @@ } while (1) { - cursor = *p; + cursor = (char)*p; if (cursor >= '0' && cursor <= '9') { result = result * 10 + cursor - '0'; } else { @@ -144,12 +144,34 @@ return result; } -static inline int parse_iv(const char *p) +static inline int parse_iv(const unsigned char *p) { return parse_iv2(p, NULL); } -#define UNSERIALIZE_PARAMETER zval **rval, const char **p, const char *max, php_unserialize_data_t *var_hash TSRMLS_DC +/* no need to check for length - re2c already did */ +static inline size_t parse_uiv(const unsigned char *p) +{ + unsigned char cursor; + size_t result = 0; + + if (*p == '+') { + p++; + } + + while (1) { + cursor = *p; + if (cursor >= '0' && cursor <= '9') { + result = result * 10 + (size_t)(cursor - (unsigned char)'0'); + } else { + break; + } + p++; + } + return result; +} + +#define UNSERIALIZE_PARAMETER zval **rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC #define UNSERIALIZE_PASSTHRU rval, p, max, var_hash TSRMLS_CC static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, int elements) @@ -187,6 +209,14 @@ zval_dtor(key); FREE_ZVAL(key); + + if (elements && *(*p-1) != ';') { +#if SOMETHING_NEW_MIGHT_LEAD_TO_CRASH_ENABLE_IF_YOU_ARE_BRAVE + zval_ptr_dtor(rval); +#endif + (*p)--; + return 0; + } } return 1; @@ -253,7 +283,7 @@ -#line 7 "re2c-output.c" +#line 7 "<stdout>" { YYCTYPE yych; unsigned int yyaccept; @@ -332,7 +362,7 @@ goto yy16; } else { if(yych <= '}') goto yy14; - if(yych <= '\277') goto yy16; + if(yych <= 0xBF) goto yy16; goto yy2; } } @@ -343,18 +373,18 @@ } yy3: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if(yych == ':') goto yy89; + if(yych == ':') goto yy87; goto yy4; yy4: -#line 478 "/usr/src/php5/ext/standard/var_unserializer.re" +#line 530 "/usr/src/php-cvs/ext/standard/var_unserializer.re" { return 0; } -#line 102 "re2c-output.c" +#line 102 "<stdout>" yy5: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if(yych == ':') goto yy83; + if(yych == ':') goto yy81; goto yy4; yy6: yych = *++YYCURSOR; - if(yych == ';') goto yy81; + if(yych == ';') goto yy79; goto yy4; yy7: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); @@ -384,16 +414,16 @@ yych = *(YYMARKER = ++YYCURSOR); if(yych == ':') goto yy17; goto yy4; -yy14: yych = *++YYCURSOR; +yy14: ++YYCURSOR; goto yy15; yy15: -#line 472 "/usr/src/php5/ext/standard/var_unserializer.re" +#line 524 "/usr/src/php-cvs/ext/standard/var_unserializer.re" { /* this is the case where we have less data than planned */ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unexpected end of serialized data"); return 0; /* not sure if it should be 0 or 1 here? */ } -#line 147 "re2c-output.c" +#line 147 "<stdout>" yy16: yych = *++YYCURSOR; goto yy4; yy17: yych = *++YYCURSOR; @@ -413,14 +443,13 @@ yy21: yych = *++YYCURSOR; if(yych != '"') goto yy2; goto yy22; -yy22: yych = *++YYCURSOR; +yy22: ++YYCURSOR; goto yy23; yy23: -#line 393 "/usr/src/php5/ext/standard/var_unserializer.re" +#line 431 "/usr/src/php-cvs/ext/standard/var_unserializer.re" { - int len; + size_t len, len2, maxlen; int elements; - int len2; char *class_name; zend_class_entry *ce; zend_class_entry **pce; @@ -432,13 +461,28 @@ zval *arg_func_name; INIT_PZVAL(*rval); - len2 = len = parse_iv(start + 2); - if (len == 0) + len2 = len = parse_uiv(start + 2); + maxlen = max - YYCURSOR; + if (maxlen < len || len == 0) { + *p = start + 2; return 0; + } + + class_name = (char*)YYCURSOR; - class_name = estrndup(YYCURSOR, len); YYCURSOR += len; + if (*(YYCURSOR) != '"') { + *p = YYCURSOR; + return 0; + } + if (*(YYCURSOR+1) != ':') { + *p = YYCURSOR+1; + return 0; + } + + class_name = estrndup(class_name, len); + do { /* Try to find class directly */ if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) { @@ -495,7 +539,7 @@ return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 249 "re2c-output.c" +#line 264 "<stdout>" yy24: yych = *++YYCURSOR; if(yych <= ','){ if(yych != '+') goto yy2; @@ -521,10 +565,10 @@ yy28: yych = *++YYCURSOR; if(yych != '"') goto yy2; goto yy29; -yy29: yych = *++YYCURSOR; +yy29: ++YYCURSOR; goto yy30; yy30: -#line 385 "/usr/src/php5/ext/standard/var_unserializer.re" +#line 423 "/usr/src/php-cvs/ext/standard/var_unserializer.re" { INIT_PZVAL(*rval); @@ -532,7 +576,7 @@ return object_common2(UNSERIALIZE_PASSTHRU, object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); } -#line 286 "re2c-output.c" +#line 302 "<stdout>" yy31: yych = *++YYCURSOR; if(yych == '+') goto yy32; if(yych <= '/') goto yy2; @@ -553,10 +597,10 @@ yy35: yych = *++YYCURSOR; if(yych != '{') goto yy2; goto yy36; -yy36: yych = *++YYCURSOR; +yy36: ++YYCURSOR; goto yy37; yy37: -#line 367 "/usr/src/php5/ext/standard/var_unserializer.re" +#line 405 "/usr/src/php-cvs/ext/standard/var_unserializer.re" { int elements = parse_iv(start + 2); @@ -574,7 +618,7 @@ return finish_nested_data(UNSERIALIZE_PASSTHRU); } -#line 328 "re2c-output.c" +#line 345 "<stdout>" yy38: yych = *++YYCURSOR; if(yych == '+') goto yy39; if(yych <= '/') goto yy2; @@ -595,26 +639,38 @@ yy42: yych = *++YYCURSOR; if(yych != '"') goto yy2; goto yy43; -yy43: yych = *++YYCURSOR; +yy43: ++YYCURSOR; goto yy44; yy44: -#line 347 "/usr/src/php5/ext/standard/var_unserializer.re" +#line 377 "/usr/src/php-cvs/ext/standard/var_unserializer.re" { - int len; + size_t len, maxlen; char *str; - len = parse_iv(start + 2); + len = parse_uiv(start + 2); + maxlen = max - YYCURSOR; + if (maxlen < len) { + *p = start + 2; + return 0; + } + + str = (char*)YYCURSOR; + + YYCURSOR += len; - str = estrndup(YYCURSOR, len); + if (*(YYCURSOR) != '"') { + *p = YYCURSOR; + return 0; + } - YYCURSOR += len + 2; + YYCURSOR += 2; *p = YYCURSOR; INIT_PZVAL(*rval); - ZVAL_STRINGL(*rval, str, len, 0); + ZVAL_STRINGL(*rval, str, len, 1); return 1; } -#line 372 "re2c-output.c" +#line 398 "<stdout>" yy45: yych = *++YYCURSOR; if(yych <= '/'){ if(yych <= ','){ @@ -700,17 +756,17 @@ goto yy2; } } -yy55: yych = *++YYCURSOR; +yy55: ++YYCURSOR; goto yy56; yy56: -#line 340 "/usr/src/php5/ext/standard/var_unserializer.re" +#line 370 "/usr/src/php-cvs/ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_DOUBLE(*rval, atof(start + 2)); return 1; } -#line 468 "re2c-output.c" +#line 496 "<stdout>" yy57: yych = *++YYCURSOR; if(yych <= ','){ if(yych != '+') goto yy2; @@ -767,10 +823,10 @@ yy65: yych = *++YYCURSOR; if(yych != ';') goto yy2; goto yy66; -yy66: yych = *++YYCURSOR; +yy66: ++YYCURSOR; goto yy67; yy67: -#line 323 "/usr/src/php5/ext/standard/var_unserializer.re" +#line 353 "/usr/src/php-cvs/ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); @@ -787,7 +843,7 @@ #endif return 1; } -#line 545 "re2c-output.c" +#line 575 "<stdout>" yy68: yych = *++YYCURSOR; if(yych == 'N') goto yy65; goto yy2; @@ -813,87 +869,72 @@ if(yych <= '9') goto yy71; if(yych != ';') goto yy2; goto yy73; -yy73: yych = *++YYCURSOR; +yy73: ++YYCURSOR; goto yy74; yy74: -#line 316 "/usr/src/php5/ext/standard/var_unserializer.re" +#line 346 "/usr/src/php-cvs/ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_LONG(*rval, parse_iv(start + 2)); return 1; } -#line 581 "re2c-output.c" +#line 612 "<stdout>" yy75: yych = *++YYCURSOR; - if(yych <= ','){ - if(yych != '+') goto yy2; - goto yy76; - } else { - if(yych <= '-') goto yy76; - if(yych <= '/') goto yy2; - if(yych <= '9') goto yy77; - goto yy2; - } -yy76: yych = *++YYCURSOR; if(yych <= '/') goto yy2; - if(yych >= ':') goto yy2; + if(yych >= '2') goto yy2; + goto yy76; +yy76: yych = *++YYCURSOR; + if(yych != ';') goto yy2; goto yy77; yy77: ++YYCURSOR; - if(YYLIMIT == YYCURSOR) YYFILL(1); - yych = *YYCURSOR; goto yy78; -yy78: if(yych <= '/') goto yy2; - if(yych <= '9') goto yy77; - if(yych != ';') goto yy2; - goto yy79; -yy79: yych = *++YYCURSOR; - goto yy80; -yy80: -#line 309 "/usr/src/php5/ext/standard/var_unserializer.re" +yy78: +#line 339 "/usr/src/php-cvs/ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_BOOL(*rval, parse_iv(start + 2)); return 1; } -#line 614 "re2c-output.c" -yy81: yych = *++YYCURSOR; - goto yy82; -yy82: -#line 302 "/usr/src/php5/ext/standard/var_unserializer.re" +#line 630 "<stdout>" +yy79: ++YYCURSOR; + goto yy80; +yy80: +#line 332 "/usr/src/php-cvs/ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_NULL(*rval); return 1; } -#line 625 "re2c-output.c" -yy83: yych = *++YYCURSOR; +#line 641 "<stdout>" +yy81: yych = *++YYCURSOR; if(yych <= ','){ if(yych != '+') goto yy2; - goto yy84; + goto yy82; } else { - if(yych <= '-') goto yy84; + if(yych <= '-') goto yy82; if(yych <= '/') goto yy2; - if(yych <= '9') goto yy85; + if(yych <= '9') goto yy83; goto yy2; } -yy84: yych = *++YYCURSOR; +yy82: yych = *++YYCURSOR; if(yych <= '/') goto yy2; if(yych >= ':') goto yy2; - goto yy85; -yy85: ++YYCURSOR; + goto yy83; +yy83: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; - goto yy86; -yy86: if(yych <= '/') goto yy2; - if(yych <= '9') goto yy85; + goto yy84; +yy84: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy83; if(yych != ';') goto yy2; - goto yy87; -yy87: yych = *++YYCURSOR; - goto yy88; -yy88: -#line 281 "/usr/src/php5/ext/standard/var_unserializer.re" + goto yy85; +yy85: ++YYCURSOR; + goto yy86; +yy86: +#line 311 "/usr/src/php-cvs/ext/standard/var_unserializer.re" { int id; @@ -914,33 +955,33 @@ return 1; } -#line 672 "re2c-output.c" -yy89: yych = *++YYCURSOR; +#line 689 "<stdout>" +yy87: yych = *++YYCURSOR; if(yych <= ','){ if(yych != '+') goto yy2; - goto yy90; + goto yy88; } else { - if(yych <= '-') goto yy90; + if(yych <= '-') goto yy88; if(yych <= '/') goto yy2; - if(yych <= '9') goto yy91; + if(yych <= '9') goto yy89; goto yy2; } -yy90: yych = *++YYCURSOR; +yy88: yych = *++YYCURSOR; if(yych <= '/') goto yy2; if(yych >= ':') goto yy2; - goto yy91; -yy91: ++YYCURSOR; + goto yy89; +yy89: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; - goto yy92; -yy92: if(yych <= '/') goto yy2; - if(yych <= '9') goto yy91; + goto yy90; +yy90: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy89; if(yych != ';') goto yy2; - goto yy93; -yy93: yych = *++YYCURSOR; - goto yy94; -yy94: -#line 260 "/usr/src/php5/ext/standard/var_unserializer.re" + goto yy91; +yy91: ++YYCURSOR; + goto yy92; +yy92: +#line 290 "/usr/src/php-cvs/ext/standard/var_unserializer.re" { int id; @@ -961,9 +1002,9 @@ return 1; } -#line 719 "re2c-output.c" +#line 737 "<stdout>" } -#line 480 "/usr/src/php5/ext/standard/var_unserializer.re" +#line 532 "/usr/src/php-cvs/ext/standard/var_unserializer.re" return 0; http://cvs.php.net/diff.php/php-src/ext/standard/var.c?r1=1.194&r2=1.195&ty=u Index: php-src/ext/standard/var.c diff -u php-src/ext/standard/var.c:1.194 php-src/ext/standard/var.c:1.195 --- php-src/ext/standard/var.c:1.194 Thu Sep 2 14:28:47 2004 +++ php-src/ext/standard/var.c Sun Sep 5 12:29:04 2004 @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: var.c,v 1.194 2004/09/02 18:28:47 helly Exp $ */ +/* $Id: var.c,v 1.195 2004/09/05 16:29:04 helly Exp $ */ /* {{{ includes @@ -823,7 +823,7 @@ } if (Z_TYPE_PP(buf) == IS_STRING) { - const char *p = Z_STRVAL_PP(buf); + const unsigned char *p = (unsigned char*)Z_STRVAL_PP(buf); if (Z_STRLEN_PP(buf) == 0) { RETURN_FALSE; @@ -833,7 +833,7 @@ if (!php_var_unserialize(&return_value, &p, p + Z_STRLEN_PP(buf), &var_hash TSRMLS_CC)) { PHP_VAR_UNSERIALIZE_DESTROY(var_hash); zval_dtor(return_value); - php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset %ld of %d bytes", (long)(p - Z_STRVAL_PP(buf)), Z_STRLEN_PP(buf)); + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset %ld of %d bytes", (long)((char*)p - Z_STRVAL_PP(buf)), Z_STRLEN_PP(buf)); RETURN_FALSE; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); http://cvs.php.net/diff.php/php-src/ext/standard/tests/serialize/bug25378.phpt?r1=1.1&r2=1.2&ty=u Index: php-src/ext/standard/tests/serialize/bug25378.phpt diff -u php-src/ext/standard/tests/serialize/bug25378.phpt:1.1 php-src/ext/standard/tests/serialize/bug25378.phpt:1.2 --- php-src/ext/standard/tests/serialize/bug25378.phpt:1.1 Wed Sep 3 12:40:52 2003 +++ php-src/ext/standard/tests/serialize/bug25378.phpt Sun Sep 5 12:29:05 2004 @@ -3,7 +3,57 @@ --FILE-- <?php var_dump(unserialize("s:-1:\"\";")); +var_dump(unserialize("i:823")); +var_dump(unserialize("O:8:\"stdClass :0:{}")); +var_dump(unserialize("O:8:\"stdClass\"+0:{}")); +var_dump(unserialize("O:1000:\"stdClass\":0:{}")); +var_dump(unserialize("a:2:{i:0;s:2:\"12\":")); +var_dump(unserialize("a:2:{i:0;s:2:\"12\";i:1;s:3000:\"123")); +var_dump(unserialize("a:2:{i:0;s:2:\"12\"+i:1;s:3:\"123\";}")); +var_dump(unserialize("a:2:{i:0;s:2:\"12\";i:1;s:3:\"123\";")); +var_dump(unserialize("s:3000:\"123\";")); +var_dump(unserialize("s:3000:\"123")); +var_dump(unserialize("s:3:\"123;")); +var_dump(unserialize("s:0:\"123\";")); ?> +===DONE=== --EXPECTF-- -Notice: unserialize(): Error at offset 0 of 8 bytes in %s on line %d +Notice: unserialize(): Error at offset 0 of 8 bytes in %sbug25378.php on line %d bool(false) + +Notice: unserialize(): Error at offset 0 of 5 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 13 of 19 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 14 of 19 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 2 of 22 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 17 of 18 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 24 of 33 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 17 of 33 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 33 of 32 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 2 of 13 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 2 of 11 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 8 of 9 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 5 of 10 bytes in %sbug25378.php on line %d +bool(false) +===DONE===
« previous php.cvs (#28569) next »