Skip to content

Instantly share code, notes, and snippets.

@smalyshev
Last active August 29, 2015 14:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save smalyshev/272028a9e8be40530d0c to your computer and use it in GitHub Desktop.
Save smalyshev/272028a9e8be40530d0c to your computer and use it in GitHub Desktop.
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(&current, (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(&current);
+ var_push_dtor_no_addref(&var_hash, &current);
}
PS_ADD_VARL(name, namelen);
efree(name);
@@ -947,8 +952,13 @@ PS_SERIALIZER_DECODE_FUNC(php) /* {{{ */
ALLOC_INIT_ZVAL(current);
if (php_var_unserialize(&current, (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, &current);
+ efree(name);
+ PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+ return FAILURE;
}
- zval_ptr_dtor(&current);
+ var_push_dtor_no_addref(&var_hash, &current);
}
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