It is error only, and not truth, that shrinks from inquiry” – Thomas Paine
Sometimes security is just for show and sometimes it’s the real thing. You can get a retiree to put on a blue uniform and stand outside a suburban bank to provide a bit of security theater. Or you can have a team of armed Navy SEALs infiltrate a beach on a moonless night. Just depends how much security you really want.
If you’re hardcore about your system’s security, then you’ll want to talk to Dover Microsystems about their hard core.
Called CoreGuard, it’s a licensed IP core that SoC developers can implement alongside their normal CPU core. CoreGuard is part bodyguard, part debug probe, and part T-800 Terminator. Its aim is to check, cycle-by-cycle and instruction-by-instruction, to make sure that your system is doing exactly what it’s supposed to do. It prevents network-based attacks like code injection, buffer overflows, data exfiltration, and other forms of malware. It’s military-grade protection for developers who don’t trust programmers – or anyone else, really.
CoreGuard works by attaching itself to the processor’s buses and trace port and monitoring everything the CPU does. If it detects something untoward, it will stop the offending activity and pull a nonmaskable interrupt. It can prevent buffer over- and under-runs before they happen, stop the CPU from jumping to a bad return address, and keep it from executing code from data structures, either deliberately or accidentally.
But aren’t these all standard programming failures? If the root problem is bad code, maybe we should just write better code.
Not possible, says Dover’s founder and CEO, Jothy Rosenberg. First of all, there’s never going to be such a thing as bug-free code. Ain’t gonna happen. You can take all the classes you want and apply all the code-quality tools you want, but there will always be flaws that the bad guys can exploit. Second, eliminating bugs is beside the point. Even (theoretically) bug-free systems have been exploited in the wild. It’s impossible to anticipate every attack angle and plug as-yet-unimagined holes. There are just too many ways that a functional system can go wrong, some of them accidental and some of them malicious. Simply flipping a single bit in a return address can cause havoc. The only solution is to watch over your processor and make sure it’s doing exactly what you told it to do.
That’s easier said than done, of course, but Dover applied some mighty DARPA-funded research to the problem. Among its many tricks is CoreGuard’s ability to detect a hijacked return address, a favorite tactic of malware writers. If Function A calls Function B, then when B is finished it should return to A, and specifically to the instruction immediately following the call – and nowhere else. CoreGuard monitors each instruction as it is executed and ensures that this is what happens. If Function B returns, but the return address is anything other than the expected one, CoreGuard halts processing and raises an interrupt. It doesn’t matter how or why the return address was corrupted – it could be through malicious code, or just a dumb mistake – but CoreGuard will trap it and stop it.
Another example is buffer overflow. When C programs allocate a buffer using the malloc function, CoreGuard notes the start and end addresses of the buffer. It also assigns a “tag” to that buffer, which it keeps internally. All future references to that buffer must be within its boundaries, or CoreGuard will trap them. What’s more, CoreGuard also ensures that the program, function, or routine accessing the buffer has enough privilege to do so. Illegal accesses, even if they’re in-bounds, are also prevented.
How does it know? CoreGuard relies on compile-time information that’s normally discarded in the binaries. It uses this information to create the identifiable meta-data needed to enforce its policies. The meta-data is then downloaded to each CoreGuard instantiation and kept in its own private local memory.
CoreGuard also protects against sneaking data out of a system, such as passwords or credit-card numbers. For this, it relies on the concept of “tainting” secure data. Any data that’s deemed sensitive (by the programmer) is notionally tainted, and arithmetic or logical operations between tainted and untainted data always produce a tainted result. Secure “taint” is sticky and can’t be washed off, even after mixing it with untainted data. CoreGuard won’t allow a processor to export tainted data to a public memory address or I/O port, even if that would otherwise be a legal CPU operation.
The one and only function that can remove the taint is the one that does encryption, meaning you can swap taint for encryption, but you can’t simply un-taint sensitive data. Only encrypted data can be exported.
Going the other way, CoreGuard tags any data coming in through I/O ports as “data,” in the sense of, “not code.” Such imported data can never be executed, no matter where or how it’s moved around. Imported data is tainted from birth and cannot be trusted.
Part of CoreGuard’s magic comes from its intimate relationship with the host processor, monitoring and evaluating every operation, clock-by-clock. On one hand, it needs to be as fast as the processor it’s protecting and stay out of the way 99.99% of the time. On the other hand, it needs to step in quickly to prevent the processor from doing any damage. That might be a recipe for a slow-down, and, in a few cases, it is.
Dover says CoreGuard runs as fast as the processor it’s monitoring, so its operation is invisible. That makes sense, given that CoreGaurd is simpler than any 32-bit CPU it’s likely to encounter. (CoreGuard is currently compatible with ARM, MIPS, RISC-V, and Tensilica, with others to come.) But some security checks take longer to evaluate than others, so CoreGuard does occasionally stall the host processor for a cycle or two. Dover says a 1% performance hit overall is pretty typical.
Hardware security features are nothing new. Don’t x86 processors already have NX (no execute) bits, four privilege levels, and extensive memory management? And don’t ARM processors all have TrustZone now? What does CoreGuard add that these chips don’t already provide for free?
Dover doesn’t see CoreGuard as a replacement for any of these technologies, but as a complement to them. By all means, use NX, PL0, TEE, segment descriptors, and all the other hardware hooks available. These all have their place, but they’re all limited to narrow problems and require OS-level software support. For example, privileged/unprivileged divisions are great for avoiding simple forms of privilege escalation, but they don’t stop problems within each region. NX bits can stop the CPU from blindly fetching data as if it were code, but only if it’s enforced religiously and hasn’t been hacked itself.
CoreGuard is not without its drawbacks. It’s an extra 250,000 gates of logic in your SoC, it requires re-linking code, and, of course, there’s the small matter of licensing fees and royalties to discuss with Dover. But do you want the rent-a-cop or the elite forces?