Why Your macOS EDR Solution Shouldn’t Be Running Under Rosetta 2

Last week, SentinelOne announced the early availability of its v5.0 agent, becoming the first endpoint security agent to natively support Apple’s new M1 (aka Apple silicon, aka arm64 Mac) architecture. With native support, the Sentinel agent is freed from having to run under Apple’s translation software layer, known as Rosetta 2, unlike other macOS EDR/XDR security solutions.

In this post, we explain what all the hot terms being thrown around in this space mean – from ‘Rosetta2’ and ‘Apple Silicon’ to ‘arm64 architecture’ and ‘Universal 2’ binaries – and explain why running security software natively on Apple silicon has clear performance and security benefits.

A New Architecture and…Names, Lots of Names

Apple made big news last year with the announcement that they would be building their own CPUs for Mac devices instead of relying on Intel for their processors. These new devices started shipping in late 2020 and are differentiated from Intel Macs by several designators.

The first term Apple coined to market their new devices was “Apple silicon”, by which they mean to refer to the CPU chip being based on a chip design created by ARM. Apple licenses the base design and produces their own take on it. Evidently, they didn’t want to brand their own take as “just an ARM chip”, preferring to take ownership of it through the distinctive brand name of “Apple silicon”.

Apple have, of course, been using their own custom-made ARM chips in iOS for years, designated with an ‘A’ and a numerical specifier, such as A10, A11, A12 and so on (current versions of iOS ship with the A14 chip). Presumably to maintain some parallelism with this convention, the first Mac ARM chip was designated ‘M1’. We expect to see M2 and M3 and so on over time as Apple iterates on the design. So, as well as being known as ‘Apple silicon Macs’, Apple’s first generation of non-Intel devices are also known as “M1 Macs”.

And that brings us to binaries – the executable file format that underlies both Apple and third-party software that can run on these new M1 chips. These must of course have a format that is compatible with the CPU architecture. On Intel machines, we have x86_64 Mach-O executables; for the M1/Apple silicon Macs, the native binary format is the arm64e Mach-O.

So, we have an ARM-based M1/Apple silicon processor architecture and arm64 binaries that run on it. That seems straightforward enough, but there’s a hitch: what about all the software that was written for Intel Macs over the last 15 years or more? And let’s not overlook the fact that Apple are still shipping – and still building – Intel Macs for at least another two years. It would be untenable to have two hardware product lines with two entirely incompatible software catalogs. Apple needed to find a way to allow software built on Intel machines to run on the new M1 machines.

Enter Rosetta 2 and the Universal 2 file format.

Intel, ARM and the Need for Translation Software

The name Rosetta is, of course, derived from the famous ‘Rosetta Stone’ that first allowed us to translate Egyptian hieroglyphics into modern language. Apple’s original Rosetta software actually helped the company translate an earlier architecture, PowerPC, to Intel when Apple made that transition in the mid-2000s.

At that time, they used a Universal file format that was a ‘FAT’ binary containing both the PowerPC and the Intel binaries within it. Regardless of whether the CPU was PowerPC or Intel, the OS extracted the correct file from the FAT, Universal binary and ran it natively on the CPU. However, if the Intel CPU came across software that only had the PowerPC binary, it would instead execute the Rosetta translator and pass the PowerPC binary off to Rosetta to execute.

With the M1 Macs, Apple took a similar approach: there’s a Universal 2 binary format that developers (like SentinelOne) use to ship both Intel and arm64 versions of their software in one release. With the Universal 2 binary, the OS checks to see what architecture it’s running on and automatically selects the appropriate arm64 (for M1 Macs) or Intel (for x86_64) slice to execute. However, if an M1 Mac encounters an Intel binary from developers who have not yet made the native transition, it passes the binary off to the Rosetta 2 translation mechanism to deal with.

That entire process should be ‘transparent’ to users, say Apple, where the word ‘transparent’ here means ‘invisible’ rather than ‘obvious’. However, Rosetta 2 doesn’t work in quite the same way as the original Rosetta, and this has both performance and security consequences users should be aware of.

A New Architecture Means New Challenges For Endpoint Security

The primary difference between the original Rosetta and Rosetta 2 is when translation takes place. With Rosetta 2, Apple wanted to avoid performance issues that affected some heavy resource-sapping software under the original Rosetta mechanism (Adobe CS2 was a particular complaint at the time).

The problem with the original Rosetta was that it translated the software each time it was run, taxing the CPU repeatedly through every launch. Apple’s approach with Rosetta 2 was to avoid that as much as possible by allowing an ‘Ahead-of-Time’ (AOT) translation to occur the first time the software launched and saving that translation for future launches.

While that is a great way to improve the performance of emulated software, there are downsides, particularly from the perspective of security software.

Native arm64 code has at least two performance advantages over translated code that are particularly relevant to large, complex programs such as EDR offerings.

The Ahead-of-Time translation we mentioned above is brokered by a helper program called oahd_helper. This program is responsible for creating the translated AOT binaries the first time the x86_64 binary is run. The larger the size of the x86_64 code to be translated, the longer the launch time. This in turn can result in heavy memory and CPU usage on the device when the oahd_helper is required to translate very large Intel executable files.

Secondly, complete AOT translation is not possible for parts of complex program code that need to be resolved at runtime. Exactly what code needs to be run can sometimes not be determined until runtime due to local environment variables and conditions. While theoretically (perhaps) a developer could compile all possible code branches ahead of time, that’s both inefficient and error prone. It’s far more efficient and bug-proof to determine, when necessary, what code needs to be run and compile it on the fly, a process known as Just-in-Time or JIT compilation.

Other things being equal, JIT compilation is fine when you’re running native code on a native processor, but when that code has to be translated through Rosetta it means that some amount of Just-in-Time compilation has to occur despite the AOT compilation. When this condition occurs, the kernel transfers control to a special Rosetta translation stub that takes care of the work. In short, any sufficiently complex program (such as an EDR solution) is going to need to have at least some of its Intel code translated via Rosetta on the fly, and that translation is going to incur a performance penalty compared to a security solution that’s running native arm64 code.

This fact is noted in Apple’s own documentation: “the translation process takes time, so users might perceive that translated apps launch or run more slowly at times”.

Native M1 Software Is More Secure By Design

But performance isn’t the only thing to worry about. More importantly, native M1 code is simply safer than running Intel code through Rosetta translation. That’s because one of the changes Apple brought in with Big Sur that only applies to Apple silicon Macs is that native arm64 code cannot execute on an M1 Mac unless it has a valid code signature.

An Apple silicon Mac doesn’t permit native arm64 code execution under any conditions unless a valid signature is attached. Translated x86_64 code, however, is not subject to this restriction: translated x86_64 code is permitted to execute through Rosetta with no signature information at all.

You can easily verify this on an M1 Mac with a simple ‘hello world’ program. If we first compile the program below as arm64e, note how the OS kills it when we try to execute, but once we re-compile the same source file as an x86_64 executable, we can run our hello.out without a code signature and without hindrance:

This allows for the possibility of software tampering: a piece of software running only as an Intel binary through Rosetta translation could have its code signature removed, its code altered, and the program executed through Rosetta without the valid developer’s code signature.

Although there are other barriers to clear for an attacker trying to carry out such an attack, it nevertheless remains the case that native arm64 code is inherently safer on an M1 Mac than translated Intel code, which can run without any code signing checks at all.

This naturally leads to the question of whether Rosetta itself could be used as an attack vector. Although all the components are locked down via System Integrity Protection, Rosetta is a multi-faceted and complicated mechanism consisting of many interlocking parts, each of which presents a potential attack surface.

Some initial, excellent reverse engineering on some of Rosetta’s components has been done here, but there is still much more to be learned about this translation layer and research is ongoing.

Conclusion

There is no question that Apple has made great strides with Rosetta 2 over the original Rosetta and this may account for why some software developers have yet to make the transition, perhaps not understanding the advantages of native M1 support. Other developers may prefer to leave their solutions running under Rosetta to take advantage of legacy Intel modules that they have not or cannot translate to ARM.

Yet as we’ve explained above, the benefits of running security software natively on Apple silicon are clear for both performance and security reasons. And as we have noted elsewhere, there is some suggestion that Apple may disable Rosetta 2 in some regions with little notice. Finally, it is also inevitable that – just as the original Rosetta reached EOL a few years after Apple had finally transitioned entirely off the PowerPC architecture for Intel – Apple will eventually drop support for translated software on the Apple silicon platform. Let’s hope, though, that other security software developers don’t wait that long to bring the performance and security benefits to their users.