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);