Skip to content

Commit 7327d5a

Browse files
committed
Use Memory Protection Keys to protect JIT buffer
1 parent 08c743e commit 7327d5a

File tree

2 files changed

+81
-17
lines changed

2 files changed

+81
-17
lines changed

configure.ac

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,7 @@ AC_CHECK_FUNCS(m4_normalize([
575575
mmap
576576
nice
577577
nl_langinfo
578+
pkey_mprotect
578579
poll
579580
pthread_jit_write_protect_np
580581
putenv

ext/opcache/jit/zend_jit.c

Lines changed: 80 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@
3333

3434
#ifdef HAVE_JIT
3535

36+
#if defined(HAVE_PKEY_MPROTECT) && defined(PKEY_DISABLE_WRITE)
37+
# define ZEND_JIT_USE_PKEYS
38+
# ifndef PKEY_DISABLE_EXECUTE
39+
# define PKEY_DISABLE_EXECUTE 0
40+
# endif
41+
#endif
42+
3643
#include "Optimizer/zend_func_info.h"
3744
#include "Optimizer/zend_ssa.h"
3845
#include "Optimizer/zend_inference.h"
@@ -88,6 +95,10 @@ static void **dasm_ptr = NULL;
8895

8996
static size_t dasm_size = 0;
9097

98+
#ifdef ZEND_JIT_USE_PKEYS
99+
static int pkey = 0; /* Memory Protection Key */
100+
#endif
101+
91102
static zend_long jit_bisect_pos = 0;
92103

93104
static zend_vm_opcode_handler_t zend_jit_runtime_jit_handler = NULL;
@@ -3519,6 +3530,21 @@ void zend_jit_unprotect(void)
35193530
{
35203531
#ifdef HAVE_MPROTECT
35213532
if (!(JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP))) {
3533+
# ifdef ZEND_JIT_USE_PKEYS
3534+
if (pkey) {
3535+
# ifdef ZTS
3536+
int restrictions = 0;
3537+
# else
3538+
int restrictions = PKEY_DISABLE_EXECUTE;
3539+
# endif
3540+
if (pkey_set(pkey, restrictions) != 0) {
3541+
fprintf(stderr, "pkey_set() failed [%d] %s\n", errno, strerror(errno));
3542+
} else {
3543+
return;
3544+
}
3545+
}
3546+
# endif
3547+
35223548
int opts = PROT_READ | PROT_WRITE;
35233549
#ifdef ZTS
35243550
#ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
@@ -3554,6 +3580,16 @@ void zend_jit_protect(void)
35543580
{
35553581
#ifdef HAVE_MPROTECT
35563582
if (!(JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP))) {
3583+
# ifdef ZEND_JIT_USE_PKEYS
3584+
if (pkey) {
3585+
if (pkey_set(pkey, PKEY_DISABLE_WRITE) != 0) {
3586+
fprintf(stderr, "pkey_set() failed [%d] %s\n", errno, strerror(errno));
3587+
} else {
3588+
return;
3589+
}
3590+
}
3591+
# endif
3592+
35573593
#ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
35583594
if (zend_write_protect) {
35593595
pthread_jit_write_protect_np(1);
@@ -3774,34 +3810,45 @@ int zend_jit_check_support(void)
37743810
return SUCCESS;
37753811
}
37763812

3777-
void zend_jit_startup(void *buf, size_t size, bool reattached)
3813+
static void zend_jit_startup_dasm_prot(void)
37783814
{
3779-
zend_jit_halt_op = zend_get_halt_op();
3780-
zend_jit_profile_counter_rid = zend_get_op_array_extension_handle(ACCELERATOR_PRODUCT_NAME);
3781-
3782-
#ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
3783-
zend_write_protect = pthread_jit_write_protect_supported_np();
3784-
#endif
3785-
3786-
dasm_buf = buf;
3787-
dasm_size = size;
3788-
dasm_ptr = dasm_end = (void*)(((char*)dasm_buf) + size - sizeof(*dasm_ptr) * 2);
3789-
37903815
#ifdef HAVE_MPROTECT
3791-
#ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
3816+
# ifdef ZEND_JIT_USE_PKEYS
3817+
pkey = pkey_alloc(0, PKEY_DISABLE_WRITE);
3818+
if (pkey < 0) {
3819+
pkey = 0;
3820+
}
3821+
# endif
3822+
# ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
37923823
if (zend_write_protect) {
37933824
pthread_jit_write_protect_np(1);
37943825
}
3795-
#endif
3826+
# endif
3827+
37963828
if (JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP)) {
37973829
if (mprotect(dasm_buf, dasm_size, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
37983830
fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
37993831
}
3800-
} else {
3801-
if (mprotect(dasm_buf, dasm_size, PROT_READ | PROT_EXEC) != 0) {
3802-
fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
3832+
return;
3833+
}
3834+
3835+
# if ZEND_JIT_USE_PKEYS
3836+
if (pkey) {
3837+
if (pkey_mprotect(dasm_buf, dasm_size, PROT_READ | PROT_WRITE | PROT_EXEC, pkey) != 0) {
3838+
fprintf(stderr, "pkey_mprotect() failed [%d] %s\n", errno, strerror(errno));
3839+
pkey = 0;
3840+
} else {
3841+
/* Fallback to mprotect(PROT_READ | PROT_EXEC) */
3842+
return;
38033843
}
38043844
}
3845+
3846+
# endif
3847+
3848+
if (mprotect(dasm_buf, dasm_size, PROT_READ | PROT_EXEC) != 0) {
3849+
fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
3850+
}
3851+
38053852
#elif defined(_WIN32)
38063853
if (JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP)) {
38073854
DWORD old;
@@ -3823,6 +3870,22 @@ void zend_jit_startup(void *buf, size_t size, bool reattached)
38233870
}
38243871
}
38253872
#endif
3873+
}
3874+
3875+
void zend_jit_startup(void *buf, size_t size, bool reattached)
3876+
{
3877+
zend_jit_halt_op = zend_get_halt_op();
3878+
zend_jit_profile_counter_rid = zend_get_op_array_extension_handle(ACCELERATOR_PRODUCT_NAME);
3879+
3880+
#ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
3881+
zend_write_protect = pthread_jit_write_protect_supported_np();
3882+
#endif
3883+
3884+
dasm_buf = buf;
3885+
dasm_size = size;
3886+
dasm_ptr = dasm_end = (void*)(((char*)dasm_buf) + size - sizeof(*dasm_ptr) * 2);
3887+
3888+
zend_jit_startup_dasm_prot();
38263889

38273890
if (!reattached) {
38283891
zend_jit_unprotect();

0 commit comments

Comments
 (0)