Skip to content

Commit 25e9619

Browse files
chen-hu-97sdp
authored and
sdp
committed
JIT: Add IBT support
Indirect Branch Tracking (IBT) is part of Intel's Control-Flow Enforcement Technology (CET). IBT is hardware based, forward edge Control-Flow-Integrity mechanism where any indirect CALL/JMP must target an ENDBR instruction or suffer #CP. This commit adds IBT support for JIT: 1. Add endbr32/64 instruction in Dynasm. 2. Insert endbr32/64 in indirect branch target for jitted code. gcc support CET since v8.1 and set it to default since gcc 11. With this commit, endbr is inserted in jitted code if PHP is compiled with "gcc -fcf-protection=full/branch". Signed-off-by: Chen, Hu <hu1.chen@intel.com>
1 parent df98edb commit 25e9619

File tree

2 files changed

+54
-7
lines changed

2 files changed

+54
-7
lines changed

ext/opcache/jit/dynasm/dasm_x86.lua

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,6 +1147,8 @@ local map_op = {
11471147
rep_0 = "F3",
11481148
repe_0 = "F3",
11491149
repz_0 = "F3",
1150+
endbr32_0 = "F30F1EFB",
1151+
endbr64_0 = "F30F1EFA",
11501152
-- F4: *hlt
11511153
cmc_0 = "F5",
11521154
-- F6: test... mb,i; div... mb

ext/opcache/jit/zend_jit_x86.dasc

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1623,6 +1623,16 @@ static size_t tsrm_tls_offset;
16231623
|| }
16241624
|.endmacro
16251625

1626+
|.macro ENDBR
1627+
||#if defined (__CET__) && (__CET__ & 1) != 0
1628+
| .if X64
1629+
| endbr64
1630+
| .else
1631+
| endbr32
1632+
| .endif
1633+
||#endif
1634+
|.endmacro
1635+
16261636
static bool reuse_ip = 0;
16271637
static bool delayed_call_chain = 0;
16281638
static uint32_t delayed_call_level = 0;
@@ -1690,6 +1700,7 @@ static void zend_jit_stop_reuse_ip(void)
16901700
static int zend_jit_interrupt_handler_stub(dasm_State **Dst)
16911701
{
16921702
|->interrupt_handler:
1703+
| ENDBR
16931704
| SAVE_IP
16941705
| //EG(vm_interrupt) = 0;
16951706
| MEM_STORE_ZTS byte, executor_globals, vm_interrupt, 0, r0
@@ -1739,6 +1750,7 @@ static int zend_jit_interrupt_handler_stub(dasm_State **Dst)
17391750
static int zend_jit_exception_handler_stub(dasm_State **Dst)
17401751
{
17411752
|->exception_handler:
1753+
| ENDBR
17421754
if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
17431755
const void *handler = zend_get_opcode_handler_func(EG(exception_op));
17441756

@@ -1771,6 +1783,7 @@ static int zend_jit_exception_handler_stub(dasm_State **Dst)
17711783
static int zend_jit_exception_handler_undef_stub(dasm_State **Dst)
17721784
{
17731785
|->exception_handler_undef:
1786+
| ENDBR
17741787
| MEM_LOAD_ZTS r0, aword, executor_globals, opline_before_exception, r0
17751788
| test byte OP:r0->result_type, (IS_TMP_VAR|IS_VAR)
17761789
| jz >1
@@ -1786,6 +1799,7 @@ static int zend_jit_exception_handler_undef_stub(dasm_State **Dst)
17861799
static int zend_jit_exception_handler_free_op1_op2_stub(dasm_State **Dst)
17871800
{
17881801
|->exception_handler_free_op1_op2:
1802+
| ENDBR
17891803
| UNDEF_OPLINE_RESULT_IF_USED
17901804
| test byte OP:RX->op1_type, (IS_TMP_VAR|IS_VAR)
17911805
| je >9
@@ -1806,6 +1820,7 @@ static int zend_jit_exception_handler_free_op1_op2_stub(dasm_State **Dst)
18061820
static int zend_jit_exception_handler_free_op2_stub(dasm_State **Dst)
18071821
{
18081822
|->exception_handler_free_op2:
1823+
| ENDBR
18091824
| MEM_LOAD_ZTS RX, aword, executor_globals, opline_before_exception, r0
18101825
| UNDEF_OPLINE_RESULT_IF_USED
18111826
| test byte OP:RX->op2_type, (IS_TMP_VAR|IS_VAR)
@@ -1821,6 +1836,7 @@ static int zend_jit_exception_handler_free_op2_stub(dasm_State **Dst)
18211836
static int zend_jit_leave_function_stub(dasm_State **Dst)
18221837
{
18231838
|->leave_function_handler:
1839+
| ENDBR
18241840
| mov FCARG1d, dword [FP + offsetof(zend_execute_data, This.u1.type_info)]
18251841
if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
18261842
| test FCARG1d, ZEND_CALL_TOP
@@ -1854,6 +1870,7 @@ static int zend_jit_leave_function_stub(dasm_State **Dst)
18541870
static int zend_jit_leave_throw_stub(dasm_State **Dst)
18551871
{
18561872
|->leave_throw_handler:
1873+
| ENDBR
18571874
| // if (opline->opcode != ZEND_HANDLE_EXCEPTION) {
18581875
if (GCC_GLOBAL_REGS) {
18591876
| cmp byte OP:IP->opcode, ZEND_HANDLE_EXCEPTION
@@ -1887,6 +1904,7 @@ static int zend_jit_leave_throw_stub(dasm_State **Dst)
18871904
static int zend_jit_icall_throw_stub(dasm_State **Dst)
18881905
{
18891906
|->icall_throw_handler:
1907+
| ENDBR
18901908
| // zend_rethrow_exception(zend_execute_data *execute_data)
18911909
| mov IP, aword EX->opline
18921910
| // if (EX(opline)->opcode != ZEND_HANDLE_EXCEPTION) {
@@ -1909,6 +1927,7 @@ static int zend_jit_icall_throw_stub(dasm_State **Dst)
19091927
static int zend_jit_throw_cannot_pass_by_ref_stub(dasm_State **Dst)
19101928
{
19111929
|->throw_cannot_pass_by_ref:
1930+
| ENDBR
19121931
| mov r0, EX->opline
19131932
| mov ecx, dword OP:r0->result.var
19141933
| SET_Z_TYPE_INFO RX+r1, IS_UNDEF
@@ -1936,6 +1955,7 @@ static int zend_jit_throw_cannot_pass_by_ref_stub(dasm_State **Dst)
19361955
static int zend_jit_undefined_offset_ex_stub(dasm_State **Dst)
19371956
{
19381957
|->undefined_offset_ex:
1958+
| ENDBR
19391959
| SAVE_IP
19401960
| jmp ->undefined_offset
19411961

@@ -1945,6 +1965,7 @@ static int zend_jit_undefined_offset_ex_stub(dasm_State **Dst)
19451965
static int zend_jit_undefined_offset_stub(dasm_State **Dst)
19461966
{
19471967
|->undefined_offset:
1968+
| ENDBR
19481969
|.if X64WIN
19491970
| sub r4, 0x28
19501971
|.elif X64
@@ -1996,6 +2017,7 @@ static int zend_jit_undefined_offset_stub(dasm_State **Dst)
19962017
static int zend_jit_undefined_index_ex_stub(dasm_State **Dst)
19972018
{
19982019
|->undefined_index_ex:
2020+
| ENDBR
19992021
| SAVE_IP
20002022
| jmp ->undefined_index
20012023

@@ -2005,6 +2027,7 @@ static int zend_jit_undefined_index_ex_stub(dasm_State **Dst)
20052027
static int zend_jit_undefined_index_stub(dasm_State **Dst)
20062028
{
20072029
|->undefined_index:
2030+
| ENDBR
20082031
|.if X64WIN
20092032
| sub r4, 0x28
20102033
|.elif X64
@@ -2060,6 +2083,7 @@ static int zend_jit_undefined_index_stub(dasm_State **Dst)
20602083
static int zend_jit_cannot_add_element_ex_stub(dasm_State **Dst)
20612084
{
20622085
|->cannot_add_element_ex:
2086+
| ENDBR
20632087
| SAVE_IP
20642088
| jmp ->cannot_add_element
20652089

@@ -2069,6 +2093,7 @@ static int zend_jit_cannot_add_element_ex_stub(dasm_State **Dst)
20692093
static int zend_jit_cannot_add_element_stub(dasm_State **Dst)
20702094
{
20712095
|->cannot_add_element:
2096+
| ENDBR
20722097
|.if X64WIN
20732098
| sub r4, 0x28
20742099
|.elif X64
@@ -2107,6 +2132,7 @@ static int zend_jit_cannot_add_element_stub(dasm_State **Dst)
21072132
static int zend_jit_undefined_function_stub(dasm_State **Dst)
21082133
{
21092134
|->undefined_function:
2135+
| ENDBR
21102136
| mov r0, aword EX->opline
21112137
|.if X64
21122138
| xor CARG1, CARG1
@@ -2131,6 +2157,7 @@ static int zend_jit_undefined_function_stub(dasm_State **Dst)
21312157
static int zend_jit_negative_shift_stub(dasm_State **Dst)
21322158
{
21332159
|->negative_shift:
2160+
| ENDBR
21342161
| mov RX, EX->opline
21352162
|.if X64
21362163
|.if WIN
@@ -2160,6 +2187,7 @@ static int zend_jit_negative_shift_stub(dasm_State **Dst)
21602187
static int zend_jit_mod_by_zero_stub(dasm_State **Dst)
21612188
{
21622189
|->mod_by_zero:
2190+
| ENDBR
21632191
| mov RX, EX->opline
21642192
|.if X64
21652193
|.if WIN
@@ -2189,6 +2217,7 @@ static int zend_jit_mod_by_zero_stub(dasm_State **Dst)
21892217
static int zend_jit_invalid_this_stub(dasm_State **Dst)
21902218
{
21912219
|->invalid_this:
2220+
| ENDBR
21922221
| UNDEF_OPLINE_RESULT
21932222
|.if X64
21942223
| xor CARG1, CARG1
@@ -2208,6 +2237,7 @@ static int zend_jit_invalid_this_stub(dasm_State **Dst)
22082237
static int zend_jit_double_one_stub(dasm_State **Dst)
22092238
{
22102239
|->one:
2240+
| ENDBR
22112241
|.dword 0, 0x3ff00000
22122242
return 1;
22132243
}
@@ -2219,6 +2249,7 @@ static int zend_jit_hybrid_runtime_jit_stub(dasm_State **Dst)
22192249
}
22202250

22212251
|->hybrid_runtime_jit:
2252+
| ENDBR
22222253
| EXT_CALL zend_runtime_jit, r0
22232254
| JMP_IP
22242255
return 1;
@@ -2231,6 +2262,7 @@ static int zend_jit_hybrid_profile_jit_stub(dasm_State **Dst)
22312262
}
22322263

22332264
|->hybrid_profile_jit:
2265+
| ENDBR
22342266
| // ++zend_jit_profile_counter;
22352267
| .if X64
22362268
| LOAD_ADDR r0, &zend_jit_profile_counter
@@ -2258,6 +2290,7 @@ static int zend_jit_hybrid_hot_code_stub(dasm_State **Dst)
22582290
}
22592291

22602292
|->hybrid_hot_code:
2293+
| ENDBR
22612294
| mov word [r2], ZEND_JIT_COUNTER_INIT
22622295
| mov FCARG1a, FP
22632296
| GET_IP FCARG2a
@@ -2322,7 +2355,7 @@ static int zend_jit_hybrid_func_hot_counter_stub(dasm_State **Dst)
23222355
}
23232356

23242357
|->hybrid_func_hot_counter:
2325-
2358+
| ENDBR
23262359
return zend_jit_hybrid_hot_counter_stub(Dst,
23272360
((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1) / JIT_G(hot_func)));
23282361
}
@@ -2334,7 +2367,7 @@ static int zend_jit_hybrid_loop_hot_counter_stub(dasm_State **Dst)
23342367
}
23352368

23362369
|->hybrid_loop_hot_counter:
2337-
2370+
| ENDBR
23382371
return zend_jit_hybrid_hot_counter_stub(Dst,
23392372
((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop)));
23402373
}
@@ -2346,6 +2379,7 @@ static int zend_jit_hybrid_hot_trace_stub(dasm_State **Dst)
23462379
}
23472380

23482381
|->hybrid_hot_trace:
2382+
| ENDBR
23492383
| mov word [r2], ZEND_JIT_COUNTER_INIT
23502384
| mov FCARG1a, FP
23512385
| GET_IP FCARG2a
@@ -2379,7 +2413,7 @@ static int zend_jit_hybrid_func_trace_counter_stub(dasm_State **Dst)
23792413
}
23802414

23812415
|->hybrid_func_trace_counter:
2382-
2416+
| ENDBR
23832417
return zend_jit_hybrid_trace_counter_stub(Dst,
23842418
((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1) / JIT_G(hot_func)));
23852419
}
@@ -2391,7 +2425,7 @@ static int zend_jit_hybrid_ret_trace_counter_stub(dasm_State **Dst)
23912425
}
23922426

23932427
|->hybrid_ret_trace_counter:
2394-
2428+
| ENDBR
23952429
return zend_jit_hybrid_trace_counter_stub(Dst,
23962430
((ZEND_JIT_COUNTER_INIT + JIT_G(hot_return) - 1) / JIT_G(hot_return)));
23972431
}
@@ -2403,14 +2437,15 @@ static int zend_jit_hybrid_loop_trace_counter_stub(dasm_State **Dst)
24032437
}
24042438

24052439
|->hybrid_loop_trace_counter:
2406-
2440+
| ENDBR
24072441
return zend_jit_hybrid_trace_counter_stub(Dst,
24082442
((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop)));
24092443
}
24102444

24112445
static int zend_jit_trace_halt_stub(dasm_State **Dst)
24122446
{
24132447
|->trace_halt:
2448+
| ENDBR
24142449
if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
24152450
| ADD_HYBRID_SPAD
24162451
| EXT_JMP zend_jit_halt_op->handler, r0
@@ -2431,7 +2466,7 @@ static int zend_jit_trace_halt_stub(dasm_State **Dst)
24312466
static int zend_jit_trace_exit_stub(dasm_State **Dst)
24322467
{
24332468
|->trace_exit:
2434-
|
2469+
| ENDBR
24352470
| // Save CPU registers
24362471
|.if X64
24372472
| sub r4, 16*8+16*8-8 /* CPU regs + SSE regs */
@@ -2564,6 +2599,7 @@ static int zend_jit_trace_exit_stub(dasm_State **Dst)
25642599
static int zend_jit_trace_escape_stub(dasm_State **Dst)
25652600
{
25662601
|->trace_escape:
2602+
| ENDBR
25672603
|
25682604
if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
25692605
| ADD_HYBRID_SPAD
@@ -2606,6 +2642,7 @@ static int zend_jit_trace_exit_group_stub(dasm_State **Dst, uint32_t n)
26062642
static int zend_jit_context_threaded_call_stub(dasm_State **Dst)
26072643
{
26082644
|->context_threaded_call:
2645+
| ENDBR
26092646
| pop r0
26102647
if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
26112648
| ADD_HYBRID_SPAD
@@ -2635,6 +2672,7 @@ static int zend_jit_assign_const_stub(dasm_State **Dst)
26352672
uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN;
26362673

26372674
|->assign_const:
2675+
| ENDBR
26382676
|.if X64WIN
26392677
| sub r4, 0x28
26402678
|.elif X64
@@ -2667,6 +2705,7 @@ static int zend_jit_assign_tmp_stub(dasm_State **Dst)
26672705
uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN;
26682706

26692707
|->assign_tmp:
2708+
| ENDBR
26702709
|.if X64WIN
26712710
| sub r4, 0x28
26722711
|.elif X64
@@ -2699,6 +2738,7 @@ static int zend_jit_assign_var_stub(dasm_State **Dst)
26992738
uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF;
27002739

27012740
|->assign_var:
2741+
| ENDBR
27022742
|.if X64WIN
27032743
| sub r4, 0x28
27042744
|.elif X64
@@ -2731,6 +2771,7 @@ static int zend_jit_assign_cv_noref_stub(dasm_State **Dst)
27312771
uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN/*|MAY_BE_UNDEF*/;
27322772

27332773
|->assign_cv_noref:
2774+
| ENDBR
27342775
|.if X64WIN
27352776
| sub r4, 0x28
27362777
|.elif X64
@@ -2763,6 +2804,7 @@ static int zend_jit_assign_cv_stub(dasm_State **Dst)
27632804
uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF/*|MAY_BE_UNDEF*/;
27642805

27652806
|->assign_cv:
2807+
| ENDBR
27662808
|.if X64WIN
27672809
| sub r4, 0x28
27682810
|.elif X64
@@ -3044,6 +3086,7 @@ static int zend_jit_align_func(dasm_State **Dst)
30443086
track_last_valid_opline = 0;
30453087
jit_return_label = -1;
30463088
|.align 16
3089+
| ENDBR
30473090
return 1;
30483091
}
30493092

@@ -3065,6 +3108,7 @@ static int zend_jit_prologue(dasm_State **Dst)
30653108
static int zend_jit_label(dasm_State **Dst, unsigned int label)
30663109
{
30673110
|=>label:
3111+
| ENDBR
30683112
return 1;
30693113
}
30703114

@@ -3824,10 +3868,11 @@ static int zend_jit_context_threaded_call(dasm_State **Dst, const zend_op *oplin
38243868
{
38253869
if (!zend_jit_handler(Dst, opline, 1)) return 0;
38263870
if (opline->opcode == ZEND_DO_UCALL) {
3871+
| ENDBR
38273872
| call ->context_threaded_call
38283873
} else {
38293874
const zend_op *next_opline = opline + 1;
3830-
3875+
| ENDBR
38313876
| CMP_IP next_opline
38323877
| je =>next_block
38333878
| call ->context_threaded_call

0 commit comments

Comments
 (0)