-
Notifications
You must be signed in to change notification settings - Fork 8k
[PoC] Use Memory Protection Keys to manage memory permissions of opcache SHM and JIT buffer #20461
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
8077fec to
5577a9d
Compare
dstogov
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for checking this.
I wouldn't merge this without an improvement.
Probably, mprotect() overhead is invisible part of PHP/JIT compiler cost.
| # ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP | ||
| if (zend_write_protect) { | ||
| pthread_jit_write_protect_np(1); | ||
| } | ||
| # endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure how pthread_jit_write_protect_np() works together with mprotect() and PKEYS.
| # ifndef PKEY_DISABLE_EXECUTE | ||
| # define PKEY_DISABLE_EXECUTE 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems we can't disable EXECUTE permission on x86_64. I didn't found a solution.
| # ifdef ZTS | ||
| int restrictions = 0; | ||
| # else | ||
| int restrictions = PKEY_DISABLE_EXECUTE; | ||
| # endif | ||
| if (pkey_set(pkey, restrictions) != 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need #ifdef ZTS? I assume this us for AArch64. Linux or MacOS?
May be we should prefer pthread_jit_write_protect_np()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the existing code, we avoid removing the PROT_EXEC in zend_jit_unprotect(), in ZTS, because other threads may be executing. I wanted to reproduce the same logic here: with restrictions = 0, we only remove PKEY_DISABLE_WRITE, thus allowing write without disallowing execute.
My understanding is that pthread_jit_write_protect_np() is MacOS only, while pkeys are Linux only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the existing code, we avoid removing the
PROT_EXECinzend_jit_unprotect(), inZTS, because other threads may be executing. I wanted to reproduce the same logic here: withrestrictions = 0, we only removePKEY_DISABLE_WRITE, thus allowing write without disallowing execute.
- I understood that PKEYs are thread specific (may be I'm wrong).
- PKEY_DISABLE_EXECUTE is zero on x86_64. So this should affect only Arrach64/Linux. I didn't test this on real hardware.
My understanding is that
pthread_jit_write_protect_np()is MacOS only, while pkeys are Linux only.
I understood the same.
I agree. I will give it another look, and eventually close the PR. |
This follows dstogov/ir@fe83fdf.
Opcache uses mprotect() to flip the writeable flag when
opcache.protect_memoryis on. JIT uses mprotect() to exchange the writeable and executable flags.Here I use pkeys to replace the mprotect() calls.
Unfortunately I didn't see notable improvements in benchmarks.
IIRC
opcache.protect_memoryhas a considerable impact on CI (maybe fuzzer too), so this may profit that.See
cc @dstogov