Handle errors from mmap and mprotect due to Apple Hardened Runtime.#82
Handle errors from mmap and mprotect due to Apple Hardened Runtime.#82gareth-rees wants to merge 3 commits intomasterfrom
Conversation
2fed2cf to
4be1af4
Compare
363adf4 to
e8f820a
Compare
On Apple Silicon, when Hardened Runtime is in force and the application lacks the "Allow Unsigned Executable Memory Entitlement", mmap and mprotect return EACCES when an attempt is made to create or modify memory so that it is simultaneously writable and executable. This commit handles these cases by retrying the operation without the PROT_EXEC flag, and setting global variables so that future operations omit the flag.
e8f820a to
136b2b6
Compare
thejayps
left a comment
There was a problem hiding this comment.
Joint review with @rptb1, @UNAA008 & @thejayps:
This fundamentally changes the MPS' behaviour for the user on the Apple platform and this needs to be documented. Code should reference this documentation.
A requirement exists to support dynamically allocated code. If we can't fulfil this requirement on a hardened runtime platform or otherwise we must make sure this is clearly explained
I think there has been a misunderstanding about the nature of the problem and the purpose of this pull request.
Since this has been misunderstood, I will add some documentation to clarify these points. |
I believe we understood everything you say, except the details about Unsigned Executable Memory Entitlement. The MPS generally supports executable code on the heap. The majority of MPS deployments rely on it (though not on XCA6LL of course). If we introduce a platform where that spec is not met, we need to document that we have done that, even if briefly, and ensure that statement is traceable from the code. I'm sure you're on it. |
As far as I can tell (well, as far as I can grep) we don't state this in the manual or design. This pull request has raised the issue for the first time, because Apple's Hardened Runtime is the first platform where it's not trivial. |
|
What could support for executable code on the heap look like? Can we sketch that out?
As I understand it, these Apple security changes don’t entirely prevent it, they simply outlaw W&X. So could we provide an API to do W -> X ? What might that look like?
… On 4 Jan 2023, at 18:31, Richard Brooksby ***@***.***> wrote:
I think there has been a misunderstanding about the nature of the problem and the purpose of this pull request.
I believe we understood everything you say, except the details about Unsigned Executable Memory Entitlement.
The MPS generally supports executable code on the heap. The majority of MPS deployments rely on it (though not on XCA6LL of course). If we introduce a platform where that spec is not met, we need to document that we have done that, even if briefly, and ensure that statement is traceable from the code. I'm sure you're on it.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
|
|
E.g. a pool class in which one allocates W & !X, and may force W -> X on an allocated object. MPS has to abandon (whatever that’s called; I’m rusty) any buffer on the same page, and of course the OS prohibits further writes so wouldn’t work for any language runtime or implementation which likes to write to fields in code objects, but presumably this is the sort of thing that language implementors are doing on W^X platforms.
Or am I completely misunderstanding?
… On 4 Jan 2023, at 18:42, Nick Barnes ***@***.***> wrote:
What could support for executable code on the heap look like? Can we sketch that out?
As I understand it, these Apple security changes don’t entirely prevent it, they simply outlaw W&X. So could we provide an API to do W -> X ? What might that look like?
>> On 4 Jan 2023, at 18:31, Richard Brooksby ***@***.***> wrote:
>>
>
> I think there has been a misunderstanding about the nature of the problem and the purpose of this pull request.
>
> I believe we understood everything you say, except the details about Unsigned Executable Memory Entitlement.
>
> The MPS generally supports executable code on the heap. The majority of MPS deployments rely on it (though not on XCA6LL of course). If we introduce a platform where that spec is not met, we need to document that we have done that, even if briefly, and ensure that statement is traceable from the code. I'm sure you're on it.
>
> —
> Reply to this email directly, view it on GitHub, or unsubscribe.
> You are receiving this because you are subscribed to this thread.
|
I'm not sure I understand this question. Configura, for example, allocate objects on the heap in the AMC pool containing code compiled on-the-fly, which they then call. Any JIT would need it. (I'm not sure how Apple's system copes with JITs etc.) EDIT: Oh, do you mean on this platform? Well, I'd have a look at what any other dynamic compiler or JIT does about it, for a start. Those are probably the requirements we might possibly need to meet. I'm curious about whether you can W to a page, then -W it, then X. It would seem to defeat the object of the hardening. But does the Hardened Runtime go so far as to keep track of data from pages that were once W and prevent any Xing of them? Maybe it's documented. But we don't need to spend a huge budget on XCA6LL, just make sure we've noted clearly how it might go wrong for people, and where the code is, and connected that up, so that future devs know. |
|
See https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_cs_allow-jit and specifically |
|
I understood NB's question to be assuming the hardened runtime scenario or
similar...
…On Wed, 4 Jan 2023, 18:42 Nick Barnes, ***@***.***> wrote:
What could support for executable code on the heap look like? Can we
sketch that out?
As I understand it, these Apple security changes don’t entirely prevent
it, they simply outlaw W&X. So could we provide an API to do W -> X ? What
might that look like?
> On 4 Jan 2023, at 18:31, Richard Brooksby ***@***.***> wrote:
>
>
> I think there has been a misunderstanding about the nature of the
problem and the purpose of this pull request.
>
> I believe we understood everything you say, except the details about
Unsigned Executable Memory Entitlement.
>
> The MPS generally supports executable code on the heap. The majority of
MPS deployments rely on it (though not on XCA6LL of course). If we
introduce a platform where that spec is not met, we need to document that
we have done that, even if briefly, and ensure that statement is traceable
from the code. I'm sure you're on it.
>
> —
> Reply to this email directly, view it on GitHub, or unsubscribe.
> You are receiving this because you are subscribed to this thread.
—
Reply to this email directly, view it on GitHub
<#82 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/ARN4DQKD34MILMX2KYK43IDWQXAB7ANCNFSM6AAAAAATHBKAIE>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
|
I've addressed most of the review comments in the fixup commit. Still thinking about where to put the user documentation. |
|
On 4 Jan 2023, at 18:52, Richard Brooksby wrote:
> What could support for executable code on the heap look like? Can we
sketch that out?
I'm not sure I understand this question. Configura, for example,
allocate objects on the heap in the AMC pool containing code compiled
on-the-fly, which they then call. Any JIT would need it. (I'm not
sure how Apple's system copes with JITs etc.)
I mean, in the context of the Apple Hardened Runtime. There are clearly
several ways to get chosen byte sequences into memory and execute them
on W^X systems. For example, one could write code to a file (whether on
a real filesystem or not - see also memfd_create() on Linux) and then
map it in with MAP_EXEC. I'm a little curious about how the dynamic
linker works on macOS with the Hardened Runtime, but I imagine it's
similar to the way it does on Linux these days. Of course some programs
will use MAP_JIT (for which they will have the necessary "entitlement" -
I wonder what was wrong with the word "capability").
I approve of the general rule enforced by this aspect of the Hardened
Runtime: "executable pages shouldn't be writable", also known as "W^X".
There are ways of enforcing this general policy on loads of different
OSes including Linuxes, BSDs, and Windows. So what I'm wondering is
whether the MPS should offer some sort of support for clients who want
to allocate objects in the arena which contain code which is
subsequently executed, even on such W^X platforms.
For example, under the Apple Hardened Runtime, can one map anonymous
pages for writing, write code to them, and then switch them from
writable to executable before executing the code? (maybe one could even
do this switch in the signal handler invoked when the
not-actually-executable code is called, although that could be really
messy if happening asynchronously with some other thread writing to the
same page). If that is possible, as I believe it is on some other W^X
systems, then a future MPS could potentially offer support for systems
which want to do it (for example, a pool class which supports this
behaviour somehow). There are a million details. For instance, you'd
have to invalidate any buffer allocating on the page (segment?) in
question.
This wouldn't work for language implementations which like to write to
code objects which are already executable, but those design choices can,
and probably should, be revisited (IIRC our LLVM backend does this or
something like it for UNWIND_INFO, but I'm very rusty about all that).
—
Nick B
|
|
W^X was mainly developed to defend against attackers who are able (due to vulnerabilities) to write to some parts of memory which are executable (and which are then executed), but not able to make arbitrary calls to mmap(). Such attackers can't switch W -> X. This is believed, with some reason, to account for quite a lot of past security vulnerabilities. |
|
I added a "Limitations" section to the "Platforms" chapter of the Reference Manual, which seems like a plausible place people might look. |
36b47cd to
f66d805
Compare
|
The branch attached to this pull request doesn't fit with the MPS's durable branch naming scheme of branch/DATE/TOPIC. This is an opportunity to figure out how renaming the branch affects the infrastructure (GitHub, Travis, etc.). Please attempt it and say how you did it. |
|
GitHub automatically closed the pull request when I renamed the branch. I made pull request #93 to replace this one. |
On Apple Silicon, when Hardened Runtime is in force and the application lacks the "Allow Unsigned Executable Memory Entitlement",
mmapandmprotectreturnEACCESwhen an attempt is made to create or modify memory so that it is simultaneously writable and executable.This commit handles these cases by retrying the operation without the
PROT_EXECflag, and setting global variables so that future operations omit the flag.Work towards #75 (Issue with Apple silicon write-xor-execute memory requirements)
Note that this doesn't completely address #75 because there is no provision for
MAP_JIT. However, in the absence of a clear customer requirement it's difficult for me to pick a good solution. This commit is a self-contained change that allows developers to work with the MPS on Apple Silicon without having to configure the Allow Unsigned Executable Memory Entitlement.