Skip to content

Commit d5ce0d8

Browse files
committed
Fix use-after-free during lazy object initialization
1 parent 090b53b commit d5ce0d8

File tree

2 files changed

+32
-0
lines changed

2 files changed

+32
-0
lines changed

Zend/zend_lazy_objects.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,9 @@ static zend_object *zend_lazy_object_init_proxy(zend_object *obj)
429429
ZEND_ASSERT(zend_object_is_lazy_proxy(obj));
430430
ZEND_ASSERT(!zend_lazy_object_initialized(obj));
431431

432+
/* Prevent object from being released during initialization */
433+
GC_ADDREF(obj);
434+
432435
zend_lazy_object_info *info = zend_lazy_object_get_info(obj);
433436

434437
/* prevent reentrant initialization */
@@ -447,6 +450,7 @@ static zend_object *zend_lazy_object_init_proxy(zend_object *obj)
447450

448451
if (UNEXPECTED(EG(exception))) {
449452
OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY;
453+
GC_DELREF(obj);
450454
return NULL;
451455
}
452456

@@ -456,6 +460,7 @@ static zend_object *zend_lazy_object_init_proxy(zend_object *obj)
456460
ZSTR_VAL(obj->ce->name),
457461
zend_zval_value_name(&retval));
458462
zval_ptr_dtor(&retval);
463+
GC_DELREF(obj);
459464
return NULL;
460465

461466
}
@@ -466,13 +471,15 @@ static zend_object *zend_lazy_object_init_proxy(zend_object *obj)
466471
zend_zval_value_name(&retval),
467472
ZSTR_VAL(obj->ce->name));
468473
zval_ptr_dtor(&retval);
474+
GC_DELREF(obj);
469475
return NULL;
470476
}
471477

472478
if (UNEXPECTED(Z_OBJ(retval) == obj || zend_object_is_lazy(Z_OBJ(retval)))) {
473479
OBJ_EXTRA_FLAGS(obj) |= IS_OBJ_LAZY_UNINITIALIZED|IS_OBJ_LAZY_PROXY;
474480
zend_throw_error(NULL, "Lazy proxy factory must return a non-lazy object");
475481
zval_ptr_dtor(&retval);
482+
GC_DELREF(obj);
476483
return NULL;
477484
}
478485

@@ -495,6 +502,14 @@ static zend_object *zend_lazy_object_init_proxy(zend_object *obj)
495502
}
496503
}
497504

505+
if (UNEXPECTED(GC_DELREF(obj) == 0)) {
506+
zend_throw_error(NULL, "Object was released during initialization");
507+
zend_objects_store_del(obj);
508+
return NULL;
509+
} else {
510+
gc_check_possible_root((zend_refcounted*) obj);
511+
}
512+
498513
return Z_OBJ(retval);
499514
}
500515

@@ -529,6 +544,9 @@ ZEND_API zend_object *zend_lazy_object_init(zend_object *obj)
529544
return zend_lazy_object_init_proxy(obj);
530545
}
531546

547+
/* Prevent object from being released during initialization */
548+
GC_ADDREF(obj);
549+
532550
zend_fcall_info_cache *initializer = zend_lazy_object_get_initializer_fcc(obj);
533551

534552
/* Prevent reentrant initialization */
@@ -569,13 +587,15 @@ ZEND_API zend_object *zend_lazy_object_init(zend_object *obj)
569587

570588
if (EG(exception)) {
571589
zend_lazy_object_revert_init(obj, properties_table_snapshot, properties_snapshot);
590+
GC_DELREF(obj);
572591
return NULL;
573592
}
574593

575594
if (Z_TYPE(retval) != IS_NULL) {
576595
zend_lazy_object_revert_init(obj, properties_table_snapshot, properties_snapshot);
577596
zval_ptr_dtor(&retval);
578597
zend_type_error("Lazy object initializer must return NULL or no value");
598+
GC_DELREF(obj);
579599
return NULL;
580600
}
581601

@@ -598,6 +618,14 @@ ZEND_API zend_object *zend_lazy_object_init(zend_object *obj)
598618
* zend_lazy_object_has_stale_info() check */
599619
zend_lazy_object_del_info(obj);
600620

621+
if (UNEXPECTED(GC_DELREF(obj) == 0)) {
622+
zend_throw_error(NULL, "Object was released during initialization");
623+
zend_objects_store_del(obj);
624+
return NULL;
625+
} else {
626+
gc_check_possible_root((zend_refcounted*) obj);
627+
}
628+
601629
return obj;
602630
}
603631

Zend/zend_object_handlers.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,6 +1189,10 @@ found:;
11891189
variable_ptr = &EG(error_zval);
11901190
goto exit;
11911191
}
1192+
/* value may have changed during initialization */
1193+
if (UNEXPECTED(Z_ISREF_P(value))) {
1194+
value = Z_REFVAL_P(value);
1195+
}
11921196
return zend_std_write_property(zobj, name, value, cache_slot);
11931197
}
11941198
/* }}} */

0 commit comments

Comments
 (0)