1

For example considering that ARM has TrustZone technology, and a potential reduced attack vector because it is based on a simpler RISC (Reduced Instruction Set Computing) based architecture instead of the CISC (Complex Instruction Set Computing) based architecture used by x86 and x64.

2
  • 1
    X86 CPU's have concept of TEE's as well.
    – vidarlo
    Commented Mar 4 at 18:18
  • x86 and x64 is basically CISC being emulated on RISC by now.
    – ThoriumBR
    Commented Mar 25 at 19:19

2 Answers 2

5

If Spectre and Meltdown have proven one thing, then this: the entire industry has an extremely cavalier attitude towards piling ever more complex optimizations with ever more complex interactions on top of each other to a point where those interactions can no longer be understood.

Spectre was a single security flaw that affected most x86/AMD64 processors by both Intel and AMD, several PowerPC processors as well as POWER6–POWER9 by IBM, multiple MIPS processors, multiple SPARC processors, and several ARM CPUs, including some Nvidia Tegra and Qualcomm Snapdragon models as well as all Apple SoCs at the time.

Meltdown affected practically all Intel CPUs since 1995 (minus Atom), PowerPC 970, POWER, and Arm Cortex-A75.

There have been a whole string of similar vulnerabilities found since then, many of them in CPUs from several different manufacturers using several different architectures.

As long as the industry as a whole has such a liberal attitude towards security, it doesn't really matter which CPU you choose.

When I say "the industry", I don't just mean the manufacturers. I also mean the customers, i.e., you and me: these, and similar, vulnerabilities strike at the very heart of what makes modern CPUs fast. It is fundamentally impossible to fix these vulnerabilities without customers accepting significant drops in performance. All we can do is play catchup.

Case in point: the latest vulnerability in this family is SLAM. It was found in a security feature that was added to AMD, Intel, and ARM CPUs.


As-if to prove my point, there was a new vulnerability disclosed recently which affects Apple's M1, M2, and M3: https://gofetch.fail/.

An optimization called data-dependent memory prefetching (DMP) scans the working memory of processes for bit patterns that look like pointers, then prefetches these memory addresses under the assumption that, if a process keeps a pointer around in memory, it probably will want to use that address soon. The problem is that machine code is untyped, so there is no way to distinguish whether a bit pattern that looks like a pointer is actually a pointer or maybe just part of some internal state that should be kept secret.

This creates a micro-architectural cache-timing side-channel attack whereby other processes can determine whether or not certain bit patterns exist in another process' working memory.

An optimization similar to the vulnerable one also exists in Intel's Raptor Lake CPUs, but – at least for now – it seems that Intel is doing more validation on the data and is thus not vulnerable to this attack.

On Raptor Lake and M3, this optimization can be turned off with a CPU flag, but on M1 and M2 it can't.

3

While there's no clear security benefit or cost from CISC vs. RISC, it may in practice be slightly harder to achieve return-oriented programming (ROP) chains for arbitrary execution on ARM. ROP generally relies on the ability to interpret the binary instructions in a different way than the developer intended, typically by accessing them misaligned.

On x86/x64, this works because those instructions can have a wide range of lengths, and are byte-addressable. Thus in many cases a long instruction, or two (or more) sequential instructions, may produce completely different behavior (representing different instructions of shorter total length and ending in a RET or similar control-flow change) if you aim the instruction pointer somewhere after the start of the instruction(s). These snippets of machine code that produce behavior (potentially behavior not present anywhere in the actual binary, if interpreted correctly, especially not in full sequence) are called "ROP gadgets". Return, jump, call, and other control-flow-changing operations are used (combined with an attacker-controlled forged stack, typically consisting of many short stack frames that are returned through in sequence) to stitch these disparate gadgets together without ever rejoining the normal flow of program execution or attempting an illegal operation (e.g. an instruction that doesn't exist).

32-bit ARM makes this somewhat harder, because unlike x86, ARM instructions are all at least mostly aligned. That is, every ARM instruction always starts on a two-byte-aligned boundary, and there's only two possible lengths (two and four bytes) for an instruction. However, ARM does offer multiple ways to interpret a given instruction, depending on whether the least significant bit is set in an address (this tells the CPU to interpret the instruction as "thumb" code, which interprets the same bytes of machine code differently than if the LSB is not set (also, only thumb mode supports 16-bit instructions). This presents less opportunity for finding ROP gadgets than x86/x64, but it's often still possible.

64-bit ARM (AArch64) makes ROP much harder, though. AArch64 only supports a single execution set (A64, no thumb mode), which only has a single instruction size (32 bits, always aligned). While some AArch64 processors still support 32-bit operation mode (AArch32) with its thumb instructions, you can't switch a single process between modes, and in any case many AArch64 processors do not, in fact, support AArch32. Thus, ROP with an AArch64 program is only possible if the program (including its libraries) already contains the full gadgets you want to execute. You can still potentially use ROP to chain together lots of small gadgets - e.g. if there's some function that ends with "write the value of register X to the address in register Y, then return", and two other functions end with "read the value at some offset from the stack pointer/frame pointer into register X [or Y, for the second one], then return", you can use those three gadgets (together with a large forged sequence of stack frames) to write arbitrary values to arbitrary addresses in (writable) memory. However, the programmer (or at least the compiler) needs to have actually emitted those exact sequences of instructions, and unlike x86 (where RET is a single-byte instruction that is reasonably likely to be embedded within other instructions if you read them misaligned), there's going to be relatively few possible instruction sequences ending in a return.


Some ARM processors also support "big-endian" mode, where multi-byte values are stored in most-sigificant to least-significant byte order. In some cases this may be safer than the (far more common, though it looks backwards to humans) little-endian format, because a common cause of memory corruption is off-by-one errors, and corrupting the least significant byte of a pointer is often easier to exploit (you only have a range of 256 locations you can aim at, but they're all contiguous around the original target) than the most significant byte (which gives you 256 specific addresses evenly spaced across the whole address space, most of which will either be kernel-mode addresses that you can't access or not mapped at all), but sometimes the MSB is the one you need to change so honestly this can be a bit of a wash. Besides, basically nothing uses big-endian mode on ARM and I'm not even sure if newer CPUs support it.


Any other differences in security are going to come down to the specific features of each processor, rather than each instruction set architecture, and I don't know of any ISA where you can expect the processors to have significantly better security features than others. If you're creating a hardware product that needs to be highly secure, it makes sense to consider those features when picking the CPU for your hardware, but if you're writing pure software products then at best you can test - using different code for each ISA you target, and often for each CPU manufacturer - whether various hardware security features are present and, if so, use them (which again will take different code per platform). Sometimes the OS will provide an abstraction layer for you to check for / use these features, but even then, each OS would have a different API for it.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .