Skip to content

Commit f283455

Browse files
committed
Poison VM stack
1 parent 659f55a commit f283455

File tree

9 files changed

+108
-19
lines changed

9 files changed

+108
-19
lines changed

Zend/zend_asan.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| Zend Engine |
4+
+----------------------------------------------------------------------+
5+
| Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
6+
+----------------------------------------------------------------------+
7+
| This source file is subject to version 2.00 of the Zend license, |
8+
| that is bundled with this package in the file LICENSE, and is |
9+
| available through the world-wide-web at the following url: |
10+
| http://www.zend.com/license/2_00.txt. |
11+
| If you did not receive a copy of the Zend license and are unable to |
12+
| obtain it through the world-wide-web, please send a note to |
13+
| [email protected] so we can mail you a copy immediately. |
14+
+----------------------------------------------------------------------+
15+
*/
16+
17+
#ifndef ZEND_ASAN_H
18+
#define ZEND_ASAN_H
19+
20+
#include "zend_portability.h"
21+
22+
#ifdef __SANITIZE_ADDRESS__
23+
# include <sanitizer/asan_interface.h>
24+
#else
25+
# define ASAN_POISON_MEMORY_REGION(_ptr, _size)
26+
# define ASAN_UNPOISON_MEMORY_REGION(_ptr, _size)
27+
#endif
28+
29+
#define ZEND_POISON_MEMORY_REGION(_ptr, _size) do { \
30+
ZEND_ASSERT(!(((uintptr_t) (_ptr)) & 7)); \
31+
ASAN_POISON_MEMORY_REGION((_ptr), (_size)); \
32+
} while (0);
33+
34+
#define ZEND_UNPOISON_MEMORY_REGION(_ptr, _size) do { \
35+
ZEND_ASSERT(!(((uintptr_t) (_ptr)) & 7)); \
36+
ASAN_UNPOISON_MEMORY_REGION((_ptr), (_size)); \
37+
} while (0);
38+
39+
#endif /* ZEND_ASAN_H */

Zend/zend_execute.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4480,6 +4480,7 @@ zend_execute_data *zend_vm_stack_copy_call_frame(zend_execute_data *call, uint32
44804480

44814481
/* copy call frame into new stack segment */
44824482
new_call = zend_vm_stack_extend(used_stack * sizeof(zval));
4483+
ZEND_UNPOISON_MEMORY_REGION(new_call, used_stack * sizeof(zval));
44834484
*new_call = *call;
44844485
ZEND_ADD_CALL_FLAG(new_call, ZEND_CALL_ALLOCATED);
44854486

@@ -5607,11 +5608,13 @@ static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame_ex(u
56075608
if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) {
56085609
EX(opline) = opline; /* this is the only difference */
56095610
call = (zend_execute_data*)zend_vm_stack_extend(used_stack);
5611+
ZEND_UNPOISON_MEMORY_REGION(call, used_stack);
56105612
ZEND_ASSERT_VM_STACK_GLOBAL;
56115613
zend_vm_init_call_frame(call, call_info | ZEND_CALL_ALLOCATED, func, num_args, object_or_called_scope);
56125614
return call;
56135615
} else {
56145616
EG(vm_stack_top) = (zval*)((char*)call + used_stack);
5617+
ZEND_UNPOISON_MEMORY_REGION(call, used_stack);
56155618
zend_vm_init_call_frame(call, call_info, func, num_args, object_or_called_scope);
56165619
return call;
56175620
}

Zend/zend_execute.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@
2424
#include "zend_compile.h"
2525
#include "zend_hash.h"
2626
#include "zend_operators.h"
27+
#include "zend_types.h"
2728
#include "zend_variables.h"
2829
#include "zend_constants.h"
30+
#include "zend_asan.h"
2931

3032
#include <stdint.h>
3133

@@ -322,6 +324,7 @@ static zend_always_inline zend_vm_stack zend_vm_stack_new_page(size_t size, zend
322324
page->top = ZEND_VM_STACK_ELEMENTS(page);
323325
page->end = (zval*)((char*)page + size);
324326
page->prev = prev;
327+
ZEND_POISON_MEMORY_REGION(page->top, (uintptr_t)page->end - (uintptr_t)page->top);
325328
return page;
326329
}
327330

@@ -342,11 +345,13 @@ static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame_ex(ui
342345

343346
if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) {
344347
call = (zend_execute_data*)zend_vm_stack_extend(used_stack);
348+
ZEND_UNPOISON_MEMORY_REGION(call, used_stack);
345349
ZEND_ASSERT_VM_STACK_GLOBAL;
346350
zend_vm_init_call_frame(call, call_info | ZEND_CALL_ALLOCATED, func, num_args, object_or_called_scope);
347351
return call;
348352
} else {
349353
EG(vm_stack_top) = (zval*)((char*)call + used_stack);
354+
ZEND_UNPOISON_MEMORY_REGION(call, used_stack);
350355
zend_vm_init_call_frame(call, call_info, func, num_args, object_or_called_scope);
351356
return call;
352357
}
@@ -370,6 +375,21 @@ static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame(uint3
370375
func, num_args, object_or_called_scope);
371376
}
372377

378+
static zend_always_inline zend_execute_data *zend_vm_stack_pop_call_frame(zend_execute_data *execute_data)
379+
{
380+
#ifdef __SANITIZE_ADDRESS__
381+
zend_execute_data *prev_execute_data = execute_data->prev_execute_data;
382+
383+
ZEND_POISON_MEMORY_REGION(execute_data, (uintptr_t)EG(vm_stack_top) - (uintptr_t)execute_data);
384+
EG(vm_stack_top) = (zval*)execute_data;
385+
386+
return prev_execute_data;
387+
#else
388+
EG(vm_stack_top) = (zval*)execute_data;
389+
return execute_data->prev_execute_data;
390+
#endif
391+
}
392+
373393
static zend_always_inline void zend_vm_stack_free_extra_args_ex(uint32_t call_info, zend_execute_data *call)
374394
{
375395
if (UNEXPECTED(call_info & ZEND_CALL_FREE_EXTRA_ARGS)) {
@@ -415,6 +435,7 @@ static zend_always_inline void zend_vm_stack_free_call_frame_ex(uint32_t call_in
415435
EG(vm_stack) = prev;
416436
efree(p);
417437
} else {
438+
ZEND_POISON_MEMORY_REGION(call, (uintptr_t)EG(vm_stack_top) - (uintptr_t)call);
418439
EG(vm_stack_top) = (zval*)call;
419440
}
420441

@@ -433,6 +454,7 @@ static zend_always_inline void zend_vm_stack_extend_call_frame(
433454
zend_execute_data **call, uint32_t passed_args, uint32_t additional_args)
434455
{
435456
if (EXPECTED((uint32_t)(EG(vm_stack_end) - EG(vm_stack_top)) > additional_args)) {
457+
ZEND_UNPOISON_MEMORY_REGION(EG(vm_stack_top), additional_args * sizeof(zval));
436458
EG(vm_stack_top) += additional_args;
437459
} else {
438460
*call = zend_vm_stack_copy_call_frame(*call, passed_args, additional_args);

Zend/zend_fibers.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "zend_compile.h"
3131
#include "zend_closures.h"
3232
#include "zend_generators.h"
33+
#include "zend_asan.h"
3334

3435
#include "zend_fibers.h"
3536
#include "zend_fibers_arginfo.h"
@@ -583,6 +584,7 @@ static ZEND_STACK_ALIGNED void zend_fiber_execute(zend_fiber_transfer *transfer)
583584
EG(vm_stack_page_size) = ZEND_FIBER_VM_STACK_SIZE;
584585

585586
fiber->execute_data = (zend_execute_data *) stack->top;
587+
ZEND_UNPOISON_MEMORY_REGION(stack->top, sizeof(zend_execute_data));
586588
fiber->stack_bottom = fiber->execute_data;
587589

588590
memset(fiber->execute_data, 0, sizeof(zend_execute_data));

Zend/zend_vm_def.h

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2976,8 +2976,7 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY)
29762976
} else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
29772977
OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
29782978
}
2979-
EG(vm_stack_top) = (zval*)execute_data;
2980-
execute_data = EX(prev_execute_data);
2979+
execute_data = zend_vm_stack_pop_call_frame(execute_data);
29812980

29822981
if (UNEXPECTED(EG(exception) != NULL)) {
29832982
zend_rethrow_exception(execute_data);
@@ -4145,7 +4144,7 @@ ZEND_VM_HOT_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL,OBSERVER))
41454144
}
41464145
zend_vm_stack_free_call_frame_ex(call_info, call);
41474146
} else {
4148-
EG(vm_stack_top) = (zval*)call;
4147+
zend_vm_stack_pop_call_frame(call);
41494148
}
41504149

41514150
if (!RETURN_VALUE_USED(opline)) {
@@ -4281,7 +4280,7 @@ ZEND_VM_C_LABEL(fcall_by_name_end):
42814280
}
42824281
zend_vm_stack_free_call_frame_ex(call_info, call);
42834282
} else {
4284-
EG(vm_stack_top) = (zval*)call;
4283+
zend_vm_stack_pop_call_frame(call);
42854284
}
42864285

42874286
if (!RETURN_VALUE_USED(opline)) {
@@ -4701,8 +4700,7 @@ ZEND_VM_HANDLER(139, ZEND_GENERATOR_CREATE, ANY, ANY)
47014700
call_info = EX_CALL_INFO();
47024701
EG(current_execute_data) = EX(prev_execute_data);
47034702
if (EXPECTED(!(call_info & (ZEND_CALL_TOP|ZEND_CALL_ALLOCATED)))) {
4704-
EG(vm_stack_top) = (zval*)execute_data;
4705-
execute_data = EX(prev_execute_data);
4703+
execute_data = zend_vm_stack_pop_call_frame(execute_data);
47064704
LOAD_NEXT_OPLINE();
47074705
ZEND_VM_LEAVE();
47084706
} else if (EXPECTED(!(call_info & ZEND_CALL_TOP))) {
@@ -6162,7 +6160,7 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO
61626160
}
61636161

61646162
bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED;
6165-
if (UNEXPECTED(is_constant_deprecated) && !CONST_IS_RECURSIVE(c)) {
6163+
if (UNEXPECTED(is_constant_deprecated) && !CONST_IS_RECURSIVE(c)) {
61666164
if (c->ce->type == ZEND_USER_CLASS) {
61676165
/* Recursion protection only applied to user constants, GH-18463 */
61686166
CONST_PROTECT_RECURSION(c);

Zend/zend_vm_execute.h

Lines changed: 9 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/opcache/jit/zend_jit_helpers.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818

1919
#include "Zend/zend_API.h"
20+
#include "Zend/zend_asan.h"
2021

2122
static ZEND_COLD void undef_result_after_exception(void) {
2223
const zend_op *opline = EG(opline_before_exception);
@@ -306,6 +307,18 @@ static zend_execute_data* ZEND_FASTCALL zend_jit_int_extend_stack_helper(uint32_
306307
return call;
307308
}
308309

310+
#ifdef __SANITIZE_ADDRESS__
311+
static void ZEND_FASTCALL zend_jit_poison_memory_region_helper(void *addr, size_t size)
312+
{
313+
ZEND_POISON_MEMORY_REGION(addr, size);
314+
}
315+
316+
static void ZEND_FASTCALL zend_jit_unpoison_memory_region_helper(void *addr, size_t size)
317+
{
318+
ZEND_UNPOISON_MEMORY_REGION(addr, size);
319+
}
320+
#endif
321+
309322
static zval* ZEND_FASTCALL zend_jit_symtable_find(HashTable *ht, zend_string *str)
310323
{
311324
zend_ulong idx;

ext/opcache/jit/zend_jit_ir.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3117,6 +3117,10 @@ static void zend_jit_setup_disasm(void)
31173117
REGISTER_HELPER(zend_jit_uninit_static_prop);
31183118
REGISTER_HELPER(zend_jit_rope_end);
31193119
REGISTER_HELPER(zend_fcall_interrupt);
3120+
# ifdef __SANITIZE_ADDRESS__
3121+
REGISTER_HELPER(zend_jit_poison_memory_region_helper);
3122+
REGISTER_HELPER(zend_jit_unpoison_memory_region_helper);
3123+
# endif
31203124

31213125
#ifndef ZTS
31223126
REGISTER_DATA(EG(current_execute_data));
@@ -8485,6 +8489,11 @@ static int zend_jit_push_call_frame(zend_jit_ctx *jit, const zend_op *opline, co
84858489
#endif
84868490
ir_STORE(ref, ir_ADD_A(top, used_stack_ref));
84878491

8492+
#ifdef __SANITIZE_ADDRESS__
8493+
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_unpoison_memory_region_helper),
8494+
rx, used_stack_ref);
8495+
#endif
8496+
84888497
// JIT: zend_vm_init_call_frame(call, call_info, func, num_args, called_scope, object);
84898498
if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || opline->opcode != ZEND_INIT_METHOD_CALL) {
84908499
// JIT: ZEND_SET_CALL_INFO(call, 0, call_info);
@@ -11046,6 +11055,11 @@ static int zend_jit_leave_func(zend_jit_ctx *jit,
1104611055
may_throw = 1;
1104711056
}
1104811057

11058+
#ifdef __SANITIZE_ADDRESS__
11059+
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_poison_memory_region_helper),
11060+
jit_FP(jit), ir_SUB_A(ir_LOAD_A(jit_EG(vm_stack_top)), jit_FP(jit)));
11061+
#endif
11062+
1104911063
// JIT: EG(vm_stack_top) = (zval*)execute_data
1105011064
ir_STORE(jit_EG(vm_stack_top), jit_FP(jit));
1105111065

ext/zend_test/fiber.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ static ZEND_STACK_ALIGNED void zend_test_fiber_execute(zend_fiber_transfer *tran
8989
EG(vm_stack_page_size) = ZEND_FIBER_VM_STACK_SIZE;
9090

9191
execute_data = (zend_execute_data *) stack->top;
92+
ZEND_UNPOISON_MEMORY_REGION(execute_data, sizeof(zend_execute_data));
9293

9394
memset(execute_data, 0, sizeof(zend_execute_data));
9495
execute_data->func = (zend_function *) &zend_pass_function;

0 commit comments

Comments
 (0)