From: Bob Weinand Date: Sat, 20 Jun 2015 16:28:51 +0000 (+0200) Subject: Fix potential writes into wrong memory, ensure vm_stack integrity X-Git-Tag: php-7.0.0alpha2~2^2~43 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7adc0ae631213c7abc0e4102531b273866322ecf;p=php Fix potential writes into wrong memory, ensure vm_stack integrity Fixes also a segfault on stack frames > 1 << 18 bytes Stack frames, when reallocated, need to be marked as top frame of current stack page --- diff --git a/Zend/tests/vm_stack_with_arg_extend.phpt b/Zend/tests/vm_stack_with_arg_extend.phpt new file mode 100644 index 0000000000..6789830f5d --- /dev/null +++ b/Zend/tests/vm_stack_with_arg_extend.phpt @@ -0,0 +1,17 @@ +--TEST-- +Ensure valid vm_stack even when it needed to be copied to a new page +--FILE-- +valid(); + +?> +--EXPECT-- +1024 diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index a62ff55c69..39a8fb242d 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -142,7 +142,7 @@ static const zend_internal_function zend_pass_function = { ((ZEND_VM_STACK_PAGE_SLOTS(gen) - ZEND_VM_STACK_HEADER_SLOTS) * sizeof(zval)) #define ZEND_VM_STACK_PAGE_ALIGNED_SIZE(gen, size) \ - (((size) + (ZEND_VM_STACK_FREE_PAGE_SIZE(gen) - 1)) & ~ZEND_VM_STACK_PAGE_SIZE(gen)) + (((size) + (ZEND_VM_STACK_FREE_PAGE_SIZE(gen) - 1)) & ~(ZEND_VM_STACK_PAGE_SIZE(gen) - 1)) static zend_always_inline zend_vm_stack zend_vm_stack_new_page(size_t size, zend_vm_stack prev) { zend_vm_stack page = (zend_vm_stack)emalloc(size); @@ -2330,6 +2330,8 @@ static zend_execute_data *zend_vm_stack_copy_call_frame(zend_execute_data *call, /* copy call frame into new stack segment */ new_call = zend_vm_stack_extend(used_stack * sizeof(zval)); *new_call = *call; + ZEND_SET_CALL_INFO(new_call, ZEND_CALL_INFO(new_call) | ZEND_CALL_ALLOCATED); + if (passed_args) { zval *src = ZEND_CALL_ARG(call, 1); zval *dst = ZEND_CALL_ARG(new_call, 1); diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 8430fc8499..3d470a9e81 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -148,6 +148,9 @@ struct _zend_vm_stack { #define ZEND_VM_STACK_ELEMETS(stack) \ (((zval*)(stack)) + ZEND_VM_STACK_HEADER_SLOTS) +#define ZEND_ASSERT_VM_STACK(stack) ZEND_ASSERT(stack->top > (zval *) stack && stack->end > (zval *) stack && stack->top <= stack->end) +#define ZEND_ASSERT_VM_STACK_GLOBAL ZEND_ASSERT(EG(vm_stack_top) > (zval *) EG(vm_stack) && EG(vm_stack_end) > (zval *) EG(vm_stack) && EG(vm_stack_top) <= EG(vm_stack_end)) + ZEND_API void zend_vm_stack_init(void); ZEND_API void zend_vm_stack_destroy(void); ZEND_API void* zend_vm_stack_extend(size_t size); @@ -156,6 +159,8 @@ static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame_ex(ui { zend_execute_data *call = (zend_execute_data*)EG(vm_stack_top); + ZEND_ASSERT_VM_STACK_GLOBAL; + if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) { call = (zend_execute_data*)zend_vm_stack_extend(used_stack); ZEND_SET_CALL_INFO(call, call_info | ZEND_CALL_ALLOCATED); @@ -163,6 +168,9 @@ static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame_ex(ui EG(vm_stack_top) = (zval*)((char*)call + used_stack); ZEND_SET_CALL_INFO(call, call_info); } + + ZEND_ASSERT_VM_STACK_GLOBAL; + call->func = func; Z_OBJ(call->This) = object; ZEND_CALL_NUM_ARGS(call) = num_args; @@ -236,6 +244,8 @@ static zend_always_inline void zend_vm_stack_free_args(zend_execute_data *call) static zend_always_inline void zend_vm_stack_free_call_frame_ex(uint32_t call_info, zend_execute_data *call) { + ZEND_ASSERT_VM_STACK_GLOBAL; + if (UNEXPECTED(call_info & ZEND_CALL_ALLOCATED)) { zend_vm_stack p = EG(vm_stack); @@ -245,9 +255,12 @@ static zend_always_inline void zend_vm_stack_free_call_frame_ex(uint32_t call_in EG(vm_stack_end) = prev->end; EG(vm_stack) = prev; efree(p); + } else { EG(vm_stack_top) = (zval*)call; } + + ZEND_ASSERT_VM_STACK_GLOBAL; } static zend_always_inline void zend_vm_stack_free_call_frame(zend_execute_data *call)