File php-CVE-2016-7479.patch of Package php7.8192

Index: php-7.0.7/ext/standard/var_unserializer.re
===================================================================
--- php-7.0.7.orig/ext/standard/var_unserializer.re	2017-01-16 16:32:01.842652977 +0100
+++ php-7.0.7/ext/standard/var_unserializer.re	2017-01-16 16:33:17.751895627 +0100
@@ -26,6 +26,9 @@
 #define VAR_ENTRIES_MAX 1024
 #define VAR_ENTRIES_DBG 0
 
+/* VAR_FLAG used in var_dtor entries to signify an entry on which __wakeup should be called */
+#define VAR_WAKEUP_FLAG 1
+
 typedef struct {
 	zval *data[VAR_ENTRIES_MAX];
 	zend_long used_slots;
@@ -94,6 +97,7 @@ PHPAPI zval *var_tmp_var(php_unserialize
         (*var_hashx)->last_dtor = var_hash;
     }
     ZVAL_UNDEF(&var_hash->data[var_hash->used_slots]);
+	Z_VAR_FLAGS(var_hash->data[var_hash->used_slots]) = 0;
     return &var_hash->data[var_hash->used_slots++];
 }
 
@@ -141,6 +145,10 @@ PHPAPI void var_destroy(php_unserialize_
 	zend_long i;
 	var_entries *var_hash = (*var_hashx)->first;
 	var_dtor_entries *var_dtor_hash = (*var_hashx)->first_dtor;
+	zend_bool wakeup_failed = 0;
+	zval wakeup_name;
+	ZVAL_UNDEF(&wakeup_name);
+
 #if VAR_ENTRIES_DBG
 	fprintf(stderr, "var_destroy(%ld)\n", var_hash?var_hash->used_slots:-1L);
 #endif
@@ -153,15 +161,40 @@ PHPAPI void var_destroy(php_unserialize_
 
 	while (var_dtor_hash) {
 		for (i = 0; i < var_dtor_hash->used_slots; i++) {
+			zval *zv = &var_dtor_hash->data[i];
 #if VAR_ENTRIES_DBG
 			fprintf(stderr, "var_destroy dtor(%p, %ld)\n", var_dtor_hash->data[i], Z_REFCOUNT_P(var_dtor_hash->data[i]));
 #endif
-			zval_ptr_dtor(&var_dtor_hash->data[i]);
+
+			/* Perform delayed __wakeup calls */
+			if (Z_VAR_FLAGS_P(zv) == VAR_WAKEUP_FLAG) {
+				if (!wakeup_failed) {
+					zval retval;
+					if (Z_ISUNDEF(wakeup_name)) {
+						ZVAL_STRINGL(&wakeup_name, "__wakeup", sizeof("__wakeup") - 1);
+					}
+
+					BG(serialize_lock)++;
+					if (call_user_function_ex(CG(function_table), zv, &wakeup_name, &retval, 0, 0, 1, NULL) == FAILURE || Z_ISUNDEF(retval)) {
+						wakeup_failed = 1;
+						GC_FLAGS(Z_OBJ_P(zv)) |= IS_OBJ_DESTRUCTOR_CALLED;
+					}
+					BG(serialize_lock)--;
+
+					zval_ptr_dtor(&retval);
+				} else {
+					GC_FLAGS(Z_OBJ_P(zv)) |= IS_OBJ_DESTRUCTOR_CALLED;
+				}
+			}
+
+			zval_ptr_dtor(zv);
 		}
 		next = var_dtor_hash->next;
 		efree_size(var_dtor_hash, sizeof(var_dtor_entries));
 		var_dtor_hash = next;
 	}
+
+	zval_ptr_dtor(&wakeup_name);
 }
 
 /* }}} */
@@ -481,19 +514,11 @@ static inline int object_common2(UNSERIA
 	}
 
 	ZVAL_DEREF(rval);
-       if (has_wakeup) {
-		ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1);
-		BG(serialize_lock)++;
-               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);
-	}
-
-	if (EG(exception)) {
-		return 0;
+	if (has_wakeup) {
+		/* Delay __wakeup call until end of serialization */
+		zval *wakeup_var = var_tmp_var(var_hash);
+		ZVAL_COPY(wakeup_var, rval);
+		Z_VAR_FLAGS_P(wakeup_var) = VAR_WAKEUP_FLAG;
 	}
 
 	return finish_nested_data(UNSERIALIZE_PASSTHRU);
openSUSE Build Service is sponsored by