-
-
Save smalyshev/272028a9e8be40530d0c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
commit 55bcea63a100e831766cfa075d1034183efc5ac8 | |
Author: Stanislav Malyshev <stas@php.net> | |
Date: Sun Aug 23 13:27:59 2015 -0700 | |
Fix bug #70219 (Use after free vulnerability in session deserializer) | |
diff --git a/ext/session/session.c b/ext/session/session.c | |
index 306aba3..0e53c62 100644 | |
--- a/ext/session/session.c | |
+++ b/ext/session/session.c | |
@@ -210,16 +210,18 @@ static char *php_session_encode(int *newlen TSRMLS_DC) /* {{{ */ | |
} | |
/* }}} */ | |
-static void php_session_decode(const char *val, int vallen TSRMLS_DC) /* {{{ */ | |
+static int php_session_decode(const char *val, int vallen TSRMLS_DC) /* {{{ */ | |
{ | |
if (!PS(serializer)) { | |
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown session.serialize_handler. Failed to decode session object"); | |
- return; | |
+ return FAILURE; | |
} | |
if (PS(serializer)->decode(val, vallen TSRMLS_CC) == FAILURE) { | |
php_session_destroy(TSRMLS_C); | |
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to decode session object. Session has been destroyed"); | |
+ return FAILURE; | |
} | |
+ return SUCCESS; | |
} | |
/* }}} */ | |
@@ -855,8 +857,11 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) /* {{{ */ | |
ALLOC_INIT_ZVAL(current); | |
if (php_var_unserialize(¤t, (const unsigned char **) &p, (const unsigned char *) endptr, &var_hash TSRMLS_CC)) { | |
php_set_session_var(name, namelen, current, &var_hash TSRMLS_CC); | |
+ } else { | |
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash); | |
+ return FAILURE; | |
} | |
- zval_ptr_dtor(¤t); | |
+ var_push_dtor_no_addref(&var_hash, ¤t); | |
} | |
PS_ADD_VARL(name, namelen); | |
efree(name); | |
@@ -947,8 +952,13 @@ PS_SERIALIZER_DECODE_FUNC(php) /* {{{ */ | |
ALLOC_INIT_ZVAL(current); | |
if (php_var_unserialize(¤t, (const unsigned char **) &q, (const unsigned char *) endptr, &var_hash TSRMLS_CC)) { | |
php_set_session_var(name, namelen, current, &var_hash TSRMLS_CC); | |
+ } else { | |
+ var_push_dtor_no_addref(&var_hash, ¤t); | |
+ efree(name); | |
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash); | |
+ return FAILURE; | |
} | |
- zval_ptr_dtor(¤t); | |
+ var_push_dtor_no_addref(&var_hash, ¤t); | |
} | |
PS_ADD_VARL(name, namelen); | |
skip: | |
@@ -1922,9 +1932,7 @@ static PHP_FUNCTION(session_decode) | |
return; | |
} | |
- php_session_decode(str, str_len TSRMLS_CC); | |
- | |
- RETURN_TRUE; | |
+ RETVAL_BOOL(php_session_decode(str, str_len TSRMLS_CC) == SUCCESS); | |
} | |
/* }}} */ | |
diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c | |
index ee0cac4..29fcba1 100644 | |
--- a/ext/standard/var_unserializer.c | |
+++ b/ext/standard/var_unserializer.c | |
@@ -1,4 +1,4 @@ | |
-/* Generated by re2c 0.13.7.5 on Tue Mar 17 13:14:30 2015 */ | |
+/* Generated by re2c 0.13.7.5 on Sun Aug 23 16:45:59 2015 */ | |
#line 1 "ext/standard/var_unserializer.re" | |
/* | |
+----------------------------------------------------------------------+ | |
@@ -304,24 +304,20 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long | |
ALLOC_INIT_ZVAL(key); | |
if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) { | |
- zval_dtor(key); | |
- FREE_ZVAL(key); | |
+ var_push_dtor_no_addref(var_hash, &key); | |
return 0; | |
} | |
if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) { | |
- zval_dtor(key); | |
- FREE_ZVAL(key); | |
+ var_push_dtor_no_addref(var_hash, &key); | |
return 0; | |
} | |
ALLOC_INIT_ZVAL(data); | |
if (!php_var_unserialize(&data, p, max, var_hash TSRMLS_CC)) { | |
- zval_dtor(key); | |
- FREE_ZVAL(key); | |
- zval_dtor(data); | |
- FREE_ZVAL(data); | |
+ var_push_dtor_no_addref(var_hash, &key); | |
+ var_push_dtor_no_addref(var_hash, &data); | |
return 0; | |
} | |
@@ -350,9 +346,7 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long | |
sizeof data, NULL); | |
} | |
var_push_dtor(var_hash, &data); | |
- | |
- zval_dtor(key); | |
- FREE_ZVAL(key); | |
+ var_push_dtor_no_addref(var_hash, &key); | |
if (elements && *(*p-1) != ';' && *(*p-1) != '}') { | |
(*p)--; | |
@@ -484,7 +478,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) | |
-#line 488 "ext/standard/var_unserializer.c" | |
+#line 482 "ext/standard/var_unserializer.c" | |
{ | |
YYCTYPE yych; | |
static const unsigned char yybm[] = { | |
@@ -544,9 +538,9 @@ yy2: | |
yych = *(YYMARKER = ++YYCURSOR); | |
if (yych == ':') goto yy95; | |
yy3: | |
-#line 839 "ext/standard/var_unserializer.re" | |
+#line 833 "ext/standard/var_unserializer.re" | |
{ return 0; } | |
-#line 550 "ext/standard/var_unserializer.c" | |
+#line 544 "ext/standard/var_unserializer.c" | |
yy4: | |
yych = *(YYMARKER = ++YYCURSOR); | |
if (yych == ':') goto yy89; | |
@@ -589,13 +583,13 @@ yy13: | |
goto yy3; | |
yy14: | |
++YYCURSOR; | |
-#line 833 "ext/standard/var_unserializer.re" | |
+#line 827 "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 599 "ext/standard/var_unserializer.c" | |
+#line 593 "ext/standard/var_unserializer.c" | |
yy16: | |
yych = *++YYCURSOR; | |
goto yy3; | |
@@ -626,7 +620,7 @@ yy20: | |
yych = *++YYCURSOR; | |
if (yych != '"') goto yy18; | |
++YYCURSOR; | |
-#line 687 "ext/standard/var_unserializer.re" | |
+#line 681 "ext/standard/var_unserializer.re" | |
{ | |
size_t len, len2, len3, maxlen; | |
long elements; | |
@@ -772,7 +766,7 @@ yy20: | |
return object_common2(UNSERIALIZE_PASSTHRU, elements); | |
} | |
-#line 776 "ext/standard/var_unserializer.c" | |
+#line 770 "ext/standard/var_unserializer.c" | |
yy25: | |
yych = *++YYCURSOR; | |
if (yych <= ',') { | |
@@ -797,7 +791,7 @@ yy27: | |
yych = *++YYCURSOR; | |
if (yych != '"') goto yy18; | |
++YYCURSOR; | |
-#line 679 "ext/standard/var_unserializer.re" | |
+#line 673 "ext/standard/var_unserializer.re" | |
{ | |
INIT_PZVAL(*rval); | |
@@ -805,7 +799,7 @@ yy27: | |
return object_common2(UNSERIALIZE_PASSTHRU, | |
object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); | |
} | |
-#line 809 "ext/standard/var_unserializer.c" | |
+#line 803 "ext/standard/var_unserializer.c" | |
yy32: | |
yych = *++YYCURSOR; | |
if (yych == '+') goto yy33; | |
@@ -826,7 +820,7 @@ yy34: | |
yych = *++YYCURSOR; | |
if (yych != '{') goto yy18; | |
++YYCURSOR; | |
-#line 659 "ext/standard/var_unserializer.re" | |
+#line 653 "ext/standard/var_unserializer.re" | |
{ | |
long elements = parse_iv(start + 2); | |
/* use iv() not uiv() in order to check data range */ | |
@@ -846,7 +840,7 @@ yy34: | |
return finish_nested_data(UNSERIALIZE_PASSTHRU); | |
} | |
-#line 850 "ext/standard/var_unserializer.c" | |
+#line 844 "ext/standard/var_unserializer.c" | |
yy39: | |
yych = *++YYCURSOR; | |
if (yych == '+') goto yy40; | |
@@ -867,7 +861,7 @@ yy41: | |
yych = *++YYCURSOR; | |
if (yych != '"') goto yy18; | |
++YYCURSOR; | |
-#line 630 "ext/standard/var_unserializer.re" | |
+#line 624 "ext/standard/var_unserializer.re" | |
{ | |
size_t len, maxlen; | |
char *str; | |
@@ -896,7 +890,7 @@ yy41: | |
ZVAL_STRINGL(*rval, str, len, 0); | |
return 1; | |
} | |
-#line 900 "ext/standard/var_unserializer.c" | |
+#line 894 "ext/standard/var_unserializer.c" | |
yy46: | |
yych = *++YYCURSOR; | |
if (yych == '+') goto yy47; | |
@@ -917,7 +911,7 @@ yy48: | |
yych = *++YYCURSOR; | |
if (yych != '"') goto yy18; | |
++YYCURSOR; | |
-#line 602 "ext/standard/var_unserializer.re" | |
+#line 596 "ext/standard/var_unserializer.re" | |
{ | |
size_t len, maxlen; | |
char *str; | |
@@ -945,7 +939,7 @@ yy48: | |
ZVAL_STRINGL(*rval, str, len, 1); | |
return 1; | |
} | |
-#line 949 "ext/standard/var_unserializer.c" | |
+#line 943 "ext/standard/var_unserializer.c" | |
yy53: | |
yych = *++YYCURSOR; | |
if (yych <= '/') { | |
@@ -1033,7 +1027,7 @@ yy61: | |
} | |
yy63: | |
++YYCURSOR; | |
-#line 592 "ext/standard/var_unserializer.re" | |
+#line 586 "ext/standard/var_unserializer.re" | |
{ | |
#if SIZEOF_LONG == 4 | |
use_double: | |
@@ -1043,7 +1037,7 @@ use_double: | |
ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL)); | |
return 1; | |
} | |
-#line 1047 "ext/standard/var_unserializer.c" | |
+#line 1041 "ext/standard/var_unserializer.c" | |
yy65: | |
yych = *++YYCURSOR; | |
if (yych <= ',') { | |
@@ -1102,7 +1096,7 @@ yy73: | |
yych = *++YYCURSOR; | |
if (yych != ';') goto yy18; | |
++YYCURSOR; | |
-#line 577 "ext/standard/var_unserializer.re" | |
+#line 571 "ext/standard/var_unserializer.re" | |
{ | |
*p = YYCURSOR; | |
INIT_PZVAL(*rval); | |
@@ -1117,7 +1111,7 @@ yy73: | |
return 1; | |
} | |
-#line 1121 "ext/standard/var_unserializer.c" | |
+#line 1115 "ext/standard/var_unserializer.c" | |
yy76: | |
yych = *++YYCURSOR; | |
if (yych == 'N') goto yy73; | |
@@ -1144,7 +1138,7 @@ yy79: | |
if (yych <= '9') goto yy79; | |
if (yych != ';') goto yy18; | |
++YYCURSOR; | |
-#line 550 "ext/standard/var_unserializer.re" | |
+#line 544 "ext/standard/var_unserializer.re" | |
{ | |
#if SIZEOF_LONG == 4 | |
int digits = YYCURSOR - start - 3; | |
@@ -1171,7 +1165,7 @@ yy79: | |
ZVAL_LONG(*rval, parse_iv(start + 2)); | |
return 1; | |
} | |
-#line 1175 "ext/standard/var_unserializer.c" | |
+#line 1169 "ext/standard/var_unserializer.c" | |
yy83: | |
yych = *++YYCURSOR; | |
if (yych <= '/') goto yy18; | |
@@ -1179,24 +1173,24 @@ yy83: | |
yych = *++YYCURSOR; | |
if (yych != ';') goto yy18; | |
++YYCURSOR; | |
-#line 543 "ext/standard/var_unserializer.re" | |
+#line 537 "ext/standard/var_unserializer.re" | |
{ | |
*p = YYCURSOR; | |
INIT_PZVAL(*rval); | |
ZVAL_BOOL(*rval, parse_iv(start + 2)); | |
return 1; | |
} | |
-#line 1190 "ext/standard/var_unserializer.c" | |
+#line 1184 "ext/standard/var_unserializer.c" | |
yy87: | |
++YYCURSOR; | |
-#line 536 "ext/standard/var_unserializer.re" | |
+#line 530 "ext/standard/var_unserializer.re" | |
{ | |
*p = YYCURSOR; | |
INIT_PZVAL(*rval); | |
ZVAL_NULL(*rval); | |
return 1; | |
} | |
-#line 1200 "ext/standard/var_unserializer.c" | |
+#line 1194 "ext/standard/var_unserializer.c" | |
yy89: | |
yych = *++YYCURSOR; | |
if (yych <= ',') { | |
@@ -1219,7 +1213,7 @@ yy91: | |
if (yych <= '9') goto yy91; | |
if (yych != ';') goto yy18; | |
++YYCURSOR; | |
-#line 513 "ext/standard/var_unserializer.re" | |
+#line 507 "ext/standard/var_unserializer.re" | |
{ | |
long id; | |
@@ -1242,7 +1236,7 @@ yy91: | |
return 1; | |
} | |
-#line 1246 "ext/standard/var_unserializer.c" | |
+#line 1240 "ext/standard/var_unserializer.c" | |
yy95: | |
yych = *++YYCURSOR; | |
if (yych <= ',') { | |
@@ -1265,7 +1259,7 @@ yy97: | |
if (yych <= '9') goto yy97; | |
if (yych != ';') goto yy18; | |
++YYCURSOR; | |
-#line 492 "ext/standard/var_unserializer.re" | |
+#line 486 "ext/standard/var_unserializer.re" | |
{ | |
long id; | |
@@ -1286,9 +1280,9 @@ yy97: | |
return 1; | |
} | |
-#line 1290 "ext/standard/var_unserializer.c" | |
+#line 1284 "ext/standard/var_unserializer.c" | |
} | |
-#line 841 "ext/standard/var_unserializer.re" | |
+#line 835 "ext/standard/var_unserializer.re" | |
return 0; | |
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re | |
index abac77c..2b31f69 100644 | |
--- a/ext/standard/var_unserializer.re | |
+++ b/ext/standard/var_unserializer.re | |
@@ -308,24 +308,20 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long | |
ALLOC_INIT_ZVAL(key); | |
if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) { | |
- zval_dtor(key); | |
- FREE_ZVAL(key); | |
+ var_push_dtor_no_addref(var_hash, &key); | |
return 0; | |
} | |
if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) { | |
- zval_dtor(key); | |
- FREE_ZVAL(key); | |
+ var_push_dtor_no_addref(var_hash, &key); | |
return 0; | |
} | |
ALLOC_INIT_ZVAL(data); | |
if (!php_var_unserialize(&data, p, max, var_hash TSRMLS_CC)) { | |
- zval_dtor(key); | |
- FREE_ZVAL(key); | |
- zval_dtor(data); | |
- FREE_ZVAL(data); | |
+ var_push_dtor_no_addref(var_hash, &key); | |
+ var_push_dtor_no_addref(var_hash, &data); | |
return 0; | |
} | |
@@ -354,9 +350,7 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long | |
sizeof data, NULL); | |
} | |
var_push_dtor(var_hash, &data); | |
- | |
- zval_dtor(key); | |
- FREE_ZVAL(key); | |
+ var_push_dtor_no_addref(var_hash, &key); | |
if (elements && *(*p-1) != ';' && *(*p-1) != '}') { | |
(*p)--; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment