File php-CVE-2016-7124.patch of Package php7.7220
http://git.php.net/?p=php-src.git;a=commitdiff;h=2135fdef9b588a34f8805b2bbf10704e36163d5a
http://git.php.net/?p=php-src.git;a=commitdiff;h=61f2f5a0f760157f9c9d32d7d3df2be47a73e74d
http://git.php.net/?p=php-src.git;a=commitdiff;h=e0f9fbdfa61012101de7f4a8653ca5538c404a71
Index: php-7.0.7/ext/session/session.c
===================================================================
--- php-7.0.7.orig/ext/session/session.c 2016-09-08 13:55:14.746632823 +0200
+++ php-7.0.7/ext/session/session.c 2016-09-08 13:55:25.810821404 +0200
@@ -905,12 +905,19 @@ PS_SERIALIZER_DECODE_FUNC(php_serialize)
const char *endptr = val + vallen;
zval session_vars;
php_unserialize_data_t var_hash;
+ int result;
zend_string *var_name = zend_string_init("_SESSION", sizeof("_SESSION") - 1, 0);
ZVAL_NULL(&session_vars);
PHP_VAR_UNSERIALIZE_INIT(var_hash);
- php_var_unserialize(&session_vars, (const unsigned char **)&val, (const unsigned char *)endptr, &var_hash);
+ result = php_var_unserialize(
+ &session_vars, (const unsigned char **)&val, (const unsigned char *)endptr, &var_hash);
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
+ if (!result) {
+ zval_ptr_dtor(&session_vars);
+ ZVAL_NULL(&session_vars);
+ }
+
if (!Z_ISUNDEF(PS(http_session_vars))) {
zval_ptr_dtor(&PS(http_session_vars));
}
Index: php-7.0.7/ext/standard/var_unserializer.re
===================================================================
--- php-7.0.7.orig/ext/standard/var_unserializer.re 2016-05-25 15:14:08.000000000 +0200
+++ php-7.0.7/ext/standard/var_unserializer.re 2016-09-08 13:55:14.746632823 +0200
@@ -305,6 +305,8 @@ static inline size_t parse_uiv(const uns
#define UNSERIALIZE_PARAMETER zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash, HashTable *classes
#define UNSERIALIZE_PASSTHRU rval, p, max, var_hash, classes
+static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER);
+
static zend_always_inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, int objprops)
{
while (elements-- > 0) {
@@ -313,7 +315,7 @@ static zend_always_inline int process_ne
ZVAL_UNDEF(&key);
- if (!php_var_unserialize_ex(&key, p, max, NULL, classes)) {
+ if (!php_var_unserialize_internal(&key, p, max, NULL, classes)) {
zval_dtor(&key);
return 0;
}
@@ -369,7 +371,7 @@ string_key:
}
}
- if (!php_var_unserialize_ex(data, p, max, var_hash, classes)) {
+ if (!php_var_unserialize_internal(data, p, max, var_hash, classes)) {
zval_dtor(&key);
return 0;
}
@@ -459,23 +461,32 @@ static inline int object_common2(UNSERIA
zval retval;
zval fname;
HashTable *ht;
+ zend_bool has_wakeup;
if (Z_TYPE_P(rval) != IS_OBJECT) {
return 0;
}
+ has_wakeup = Z_OBJCE_P(rval) != PHP_IC_ENTRY
+ && zend_hash_str_exists(&Z_OBJCE_P(rval)->function_table, "__wakeup", sizeof("__wakeup")-1);
+
ht = Z_OBJPROP_P(rval);
zend_hash_extend(ht, zend_hash_num_elements(ht) + elements, (ht->u.flags & HASH_FLAG_PACKED));
if (!process_nested_data(UNSERIALIZE_PASSTHRU, ht, elements, 1)) {
+ if (has_wakeup) {
+ ZVAL_DEREF(rval);
+ GC_FLAGS(Z_OBJ_P(rval)) |= IS_OBJ_DESTRUCTOR_CALLED;
+ }
return 0;
}
ZVAL_DEREF(rval);
- if (Z_OBJCE_P(rval) != PHP_IC_ENTRY &&
- zend_hash_str_exists(&Z_OBJCE_P(rval)->function_table, "__wakeup", sizeof("__wakeup")-1)) {
+ if (has_wakeup) {
ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1);
BG(serialize_lock)++;
- call_user_function_ex(CG(function_table), rval, &fname, &retval, 0, 0, 1, NULL);
+ if (call_user_function_ex(CG(function_table), rval, &fname, &retval, 0, 0, 1, NULL) == FAILURE || Z_ISUNDEF(retval)) {
+ GC_FLAGS(Z_OBJ_P(rval)) |= IS_OBJ_DESTRUCTOR_CALLED;
+ }
BG(serialize_lock)--;
zval_dtor(&fname);
zval_dtor(&retval);
@@ -486,7 +497,6 @@ static inline int object_common2(UNSERIA
}
return finish_nested_data(UNSERIALIZE_PASSTHRU);
-
}
#ifdef PHP_WIN32
# pragma optimize("", on)
@@ -498,9 +508,35 @@ PHPAPI int php_var_unserialize(zval *rva
return php_var_unserialize_ex(UNSERIALIZE_PASSTHRU);
}
-
PHPAPI int php_var_unserialize_ex(UNSERIALIZE_PARAMETER)
{
+ var_entries *orig_var_entries = (*var_hash)->last;
+ zend_long orig_used_slots = orig_var_entries ? orig_var_entries->used_slots : 0;
+ int result;
+
+ result = php_var_unserialize_internal(UNSERIALIZE_PASSTHRU);
+
+ if (!result) {
+ /* If the unserialization failed, mark all elements that have been added to var_hash
+ * as NULL. This will forbid their use by other unserialize() calls in the same
+ * unserialization context. */
+ var_entries *e = orig_var_entries;
+ zend_long s = orig_used_slots;
+ while (e) {
+ for (; s < e->used_slots; s++) {
+ e->data[s] = NULL;
+ }
+
+ e = e->next;
+ s = 0;
+ }
+ }
+
+ return result;
+}
+
+static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER)
+{
const unsigned char *cursor, *limit, *marker, *start;
zval *rval_ref;