Skip to content

Commit 5577a9d

Browse files
committed
Use Memory Protection Keys for opcache.protect_memory
1 parent 7327d5a commit 5577a9d

File tree

2 files changed

+121
-70
lines changed

2 files changed

+121
-70
lines changed

ext/opcache/jit/zend_jit.c

Lines changed: 72 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
#include "Zend/zend_observer.h"
3131
#include "zend_smart_str.h"
3232
#include "jit/zend_jit.h"
33+
#if __has_include(<sys/mman.h>)
34+
# include <sys/mman.h>
35+
#endif
3336

3437
#ifdef HAVE_JIT
3538

@@ -115,6 +118,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV zend_runtime_jit(ZEND_O
115118
static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV zend_runtime_jit(ZEND_OPCODE_HANDLER_ARGS);
116119
#endif
117120

121+
static void zend_jit_protect_init(void);
122+
118123
static int zend_jit_trace_op_len(const zend_op *opline);
119124
static int zend_jit_trace_may_exit(const zend_op_array *op_array, const zend_op *opline);
120125
static uint32_t _zend_jit_trace_get_exit_point(const zend_op *to_opline, uint32_t flags ZEND_FILE_LINE_DC);
@@ -3526,6 +3531,62 @@ int zend_jit_script(zend_script *script)
35263531
return FAILURE;
35273532
}
35283533

3534+
static void zend_jit_protect_init(void)
3535+
{
3536+
#ifdef HAVE_MPROTECT
3537+
# ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
3538+
if (zend_write_protect) {
3539+
pthread_jit_write_protect_np(1);
3540+
}
3541+
# endif
3542+
3543+
if (JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP)) {
3544+
if (mprotect(dasm_buf, dasm_size, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
3545+
fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
3546+
}
3547+
return;
3548+
}
3549+
3550+
# ifdef ZEND_JIT_USE_PKEYS
3551+
pkey = pkey_alloc(0, PKEY_DISABLE_WRITE);
3552+
if (pkey < 0) {
3553+
zend_accel_error(ACCEL_LOG_DEBUG, "zend_jit_protect_init: pkey_alloc() failed [%d] %s", errno, strerror(errno));
3554+
pkey = 0;
3555+
} else if (pkey_mprotect(dasm_buf, dasm_size, PROT_READ | PROT_WRITE | PROT_EXEC, pkey) != 0) {
3556+
zend_accel_error(ACCEL_LOG_DEBUG, "zend_jit_protect_init: pkey_mprotect() failed [%d] %s", errno, strerror(errno));
3557+
pkey = 0;
3558+
} else {
3559+
return;
3560+
}
3561+
# endif
3562+
3563+
if (mprotect(dasm_buf, dasm_size, PROT_READ | PROT_EXEC) != 0) {
3564+
fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
3565+
}
3566+
3567+
#elif defined(_WIN32)
3568+
if (JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP)) {
3569+
DWORD old;
3570+
3571+
if (!VirtualProtect(dasm_buf, dasm_size, PAGE_EXECUTE_READWRITE, &old)) {
3572+
DWORD err = GetLastError();
3573+
char *msg = php_win32_error_to_msg(err);
3574+
fprintf(stderr, "VirtualProtect() failed [%lu] %s\n", err, msg);
3575+
php_win32_error_msg_free(msg);
3576+
}
3577+
} else {
3578+
DWORD old;
3579+
3580+
if (!VirtualProtect(dasm_buf, dasm_size, PAGE_EXECUTE_READ, &old)) {
3581+
DWORD err = GetLastError();
3582+
char *msg = php_win32_error_to_msg(err);
3583+
fprintf(stderr, "VirtualProtect() failed [%lu] %s\n", err, msg);
3584+
php_win32_error_msg_free(msg);
3585+
}
3586+
}
3587+
#endif
3588+
}
3589+
35293590
void zend_jit_unprotect(void)
35303591
{
35313592
#ifdef HAVE_MPROTECT
@@ -3538,10 +3599,9 @@ void zend_jit_unprotect(void)
35383599
int restrictions = PKEY_DISABLE_EXECUTE;
35393600
# endif
35403601
if (pkey_set(pkey, restrictions) != 0) {
3541-
fprintf(stderr, "pkey_set() failed [%d] %s\n", errno, strerror(errno));
3542-
} else {
3543-
return;
3602+
ZEND_UNREACHABLE();
35443603
}
3604+
return;
35453605
}
35463606
# endif
35473607

@@ -3583,10 +3643,9 @@ void zend_jit_protect(void)
35833643
# ifdef ZEND_JIT_USE_PKEYS
35843644
if (pkey) {
35853645
if (pkey_set(pkey, PKEY_DISABLE_WRITE) != 0) {
3586-
fprintf(stderr, "pkey_set() failed [%d] %s\n", errno, strerror(errno));
3587-
} else {
3588-
return;
3646+
ZEND_UNREACHABLE();
35893647
}
3648+
return;
35903649
}
35913650
# endif
35923651

@@ -3810,68 +3869,6 @@ int zend_jit_check_support(void)
38103869
return SUCCESS;
38113870
}
38123871

3813-
static void zend_jit_startup_dasm_prot(void)
3814-
{
3815-
#ifdef HAVE_MPROTECT
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
3823-
if (zend_write_protect) {
3824-
pthread_jit_write_protect_np(1);
3825-
}
3826-
# endif
3827-
3828-
if (JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP)) {
3829-
if (mprotect(dasm_buf, dasm_size, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
3830-
fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
3831-
}
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;
3843-
}
3844-
}
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-
3852-
#elif defined(_WIN32)
3853-
if (JIT_G(debug) & (ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF_DUMP)) {
3854-
DWORD old;
3855-
3856-
if (!VirtualProtect(dasm_buf, dasm_size, PAGE_EXECUTE_READWRITE, &old)) {
3857-
DWORD err = GetLastError();
3858-
char *msg = php_win32_error_to_msg(err);
3859-
fprintf(stderr, "VirtualProtect() failed [%lu] %s\n", err, msg);
3860-
php_win32_error_msg_free(msg);
3861-
}
3862-
} else {
3863-
DWORD old;
3864-
3865-
if (!VirtualProtect(dasm_buf, dasm_size, PAGE_EXECUTE_READ, &old)) {
3866-
DWORD err = GetLastError();
3867-
char *msg = php_win32_error_to_msg(err);
3868-
fprintf(stderr, "VirtualProtect() failed [%lu] %s\n", err, msg);
3869-
php_win32_error_msg_free(msg);
3870-
}
3871-
}
3872-
#endif
3873-
}
3874-
38753872
void zend_jit_startup(void *buf, size_t size, bool reattached)
38763873
{
38773874
zend_jit_halt_op = zend_get_halt_op();
@@ -3885,7 +3882,7 @@ void zend_jit_startup(void *buf, size_t size, bool reattached)
38853882
dasm_size = size;
38863883
dasm_ptr = dasm_end = (void*)(((char*)dasm_buf) + size - sizeof(*dasm_ptr) * 2);
38873884

3888-
zend_jit_startup_dasm_prot();
3885+
zend_jit_protect_init();
38893886

38903887
if (!reattached) {
38913888
zend_jit_unprotect();
@@ -3943,6 +3940,12 @@ void zend_jit_shutdown(void)
39433940
dasm_buf = NULL;
39443941
dasm_end = NULL;
39453942
dasm_size = 0;
3943+
3944+
#ifdef ZEND_JIT_USE_PKEYS
3945+
if (pkey) {
3946+
pkey_free(pkey);
3947+
}
3948+
#endif
39463949
}
39473950

39483951
static void zend_jit_reset_counters(void)

ext/opcache/zend_shared_alloc.c

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@
4444
# include "sys/mman.h"
4545
#endif
4646

47+
#if defined(HAVE_PKEY_MPROTECT) && defined(PKEY_DISABLE_WRITE)
48+
# define ZEND_ACCEL_USE_PKEYS
49+
#endif
50+
4751
#define SEM_FILENAME_PREFIX ".ZendSem."
4852
#define S_H(s) g_shared_alloc_handler->s
4953

@@ -79,6 +83,12 @@ static const zend_shared_memory_handler_entry handler_table[] = {
7983
{ NULL, NULL}
8084
};
8185

86+
#ifdef ZEND_ACCEL_USE_PKEYS
87+
static int pkey = 0; /* Memory Protection Key */
88+
#endif
89+
90+
static void zend_accel_shared_protect_init(void);
91+
8292
#ifndef ZEND_WIN32
8393
void zend_shared_alloc_create_lock(char *lockfile_path)
8494
{
@@ -260,6 +270,8 @@ int zend_shared_alloc_startup(size_t requested_size, size_t reserved_size)
260270
ZSMMG(shared_segments)[i]->end = ZSMMG(shared_segments)[i]->size;
261271
}
262272

273+
zend_accel_shared_protect_init();
274+
263275
shared_segments_array_size = ZSMMG(shared_segments_count) * S_H(segment_type_size)();
264276

265277
/* move shared_segments and shared_free to shared memory */
@@ -342,6 +354,13 @@ void zend_shared_alloc_shutdown(void)
342354
# ifdef ZTS
343355
tsrm_mutex_free(zts_lock);
344356
# endif
357+
358+
# ifdef ZEND_ACCEL_USE_PKEYS
359+
if (pkey) {
360+
pkey_free(pkey);
361+
}
362+
# endif
363+
345364
#endif
346365
}
347366

@@ -628,9 +647,38 @@ const char *zend_accel_get_shared_model(void)
628647
return g_shared_model;
629648
}
630649

650+
static void zend_accel_shared_protect_init(void)
651+
{
652+
#ifdef ZEND_ACCEL_USE_PKEYS
653+
pkey = pkey_alloc(0, 0);
654+
if (pkey < 0) {
655+
zend_accel_error(ACCEL_LOG_DEBUG, "zend_accel_shared_protect_init: pkey_alloc() failed [%d] %s", errno, strerror(errno));
656+
pkey = 0;
657+
return;
658+
}
659+
660+
for (int i = 0; i < ZSMMG(shared_segments_count); i++) {
661+
if (pkey_mprotect(ZSMMG(shared_segments)[i]->p, ZSMMG(shared_segments)[i]->end, PROT_READ | PROT_WRITE, pkey) != 0) {
662+
zend_accel_error(ACCEL_LOG_DEBUG, "zend_accel_shared_protect_init: pkey_mprotect() failed [%d] %s", errno, strerror(errno));
663+
pkey = 0;
664+
break;
665+
}
666+
}
667+
#endif
668+
}
669+
631670
void zend_accel_shared_protect(bool protected)
632671
{
633-
#ifdef HAVE_MPROTECT
672+
#ifdef ZEND_ACCEL_USE_PKEYS
673+
if (pkey) {
674+
if (pkey_set(pkey, protected ? PKEY_DISABLE_WRITE : 0) != 0) {
675+
ZEND_UNREACHABLE();
676+
}
677+
return;
678+
}
679+
#endif
680+
681+
#if defined(HAVE_MPROTECT)
634682
int i;
635683

636684
if (!smm_shared_globals) {

0 commit comments

Comments
 (0)