Skip to content

Handle errors from mmap and mprotect due to Apple Hardened Runtime.#82

Closed
gareth-rees wants to merge 3 commits intomasterfrom
75-hardened-runtime
Closed

Handle errors from mmap and mprotect due to Apple Hardened Runtime.#82
gareth-rees wants to merge 3 commits intomasterfrom
75-hardened-runtime

Conversation

@gareth-rees
Copy link
Copy Markdown
Member

@gareth-rees gareth-rees commented Dec 22, 2022

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.

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.

@gareth-rees gareth-rees force-pushed the 75-hardened-runtime branch 2 times, most recently from 363adf4 to e8f820a Compare December 22, 2022 21:54
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.
Copy link
Copy Markdown
Contributor

@thejayps thejayps left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@gareth-rees
Copy link
Copy Markdown
Member Author

gareth-rees commented Jan 4, 2023

This fundamentally changes the MPS' behaviour for the user on the Apple platform

I think there has been a misunderstanding about the nature of the problem and the purpose of this pull request.

  1. The MPS does not support the XCA6LL platform: the latest release is 1.117.0 which does not compile or run on this platform. So there is no behaviour to change. This pull request is one step towards implementing support for that platform, so that when you make release 1.118.0 you can announce that it supports XCA6LL.
  2. This pull request does not prevent developers on XCA6LL from implementing dynamically allocated code in the MPS. These developers have a couple of other options: they can disable Hardened Runtime or add the Allow Unsigned Executable Memory Entitlement.
  3. This pull request enables the MPS to work in the common case where Hardened Runtime is enabled (as it is by default), the Allow Unsigned Executable Memory Entitlement is not configured (as it is not by default) and code does not need to be dynamically allocated (as in many or most programs).

Since this has been misunderstood, I will add some documentation to clarify these points.

@rptb1
Copy link
Copy Markdown
Member

rptb1 commented Jan 4, 2023

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.

@rptb1
Copy link
Copy Markdown
Member

rptb1 commented Jan 4, 2023

The MPS generally supports executable code on the heap.

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.

@NickBarnes
Copy link
Copy Markdown
Member

NickBarnes commented Jan 4, 2023 via email

@NickBarnes
Copy link
Copy Markdown
Member

NickBarnes commented Jan 4, 2023 via email

@rptb1
Copy link
Copy Markdown
Member

rptb1 commented Jan 4, 2023

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.)

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.

@rptb1
Copy link
Copy Markdown
Member

rptb1 commented Jan 4, 2023

See https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_cs_allow-jit and specifically MAP_JIT. I can't read all of this now, but the requirement for executable memory raises some issues that might affect this code. In particular, this change uses global static variables to quietly and irreversibly change the nature of allocated memory. Should the MPS have a proper interface declaring the intention to do JIT-like stuff on the heap? Can restrictions change at run-time? Other platforms might start introducing similar restrictions.

@thejayps
Copy link
Copy Markdown
Contributor

thejayps commented Jan 4, 2023 via email

@gareth-rees gareth-rees requested a review from thejayps January 4, 2023 21:14
@gareth-rees
Copy link
Copy Markdown
Member Author

I've addressed most of the review comments in the fixup commit. Still thinking about where to put the user documentation.

@NickBarnes
Copy link
Copy Markdown
Member

NickBarnes commented Jan 4, 2023 via email

@NickBarnes
Copy link
Copy Markdown
Member

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.

@gareth-rees
Copy link
Copy Markdown
Member Author

I added a "Limitations" section to the "Platforms" chapter of the Reference Manual, which seems like a plausible place people might look.

Copy link
Copy Markdown
Contributor

@thejayps thejayps left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2nd review with @rptb1, @UNAA008 & @thejayps:

We think this all looks good but we are currently unable to approve because we can't build on all target platforms. Watch this space.

@rptb1
Copy link
Copy Markdown
Member

rptb1 commented Jan 6, 2023

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.

@gareth-rees gareth-rees closed this Jan 6, 2023
@gareth-rees
Copy link
Copy Markdown
Member Author

GitHub automatically closed the pull request when I renamed the branch. I made pull request #93 to replace this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants