> I think apple (maybe as just an arm feature?) can do encrypted pointers, with a per application key tracked by the kernel.

ARM has added both pointer authentication codes and memory tagging extensions to their ISA, from (I think) ARMv8.5-A. Apple are the only ones to implement silicon that supports PAC that anyone can buy today but a) this will change fast and b) I might've missed something else.

I wouldn't say "encrypt". You can still read what the pointer is, you just can't forge it. It is more like a message authentication code, or keyed hash. Confusingly, the ARM ISA suggests you use the block cipher QARMA, a lightweight block cipher of their design. This is not a mistake - from a crypto academic's perspective the distinction between block cipher and hash is not so easy to draw as it tends to be communicated: you can get a block cipher out of the SHA family of hash functions (called SHACAL) and so on. There was a line of work on finding a suitable family of permutations (e.g. Gimli) that could be hardware-accelerated and appropriate constructions built from that.

tl;dr it is kinda a "signed pointer", and if you forge the pointer but get it wrong you don't get another chance because the CPU triggers a fault, so you can use lower security lightweight ciphers and still make exploitation very unreliable.

Now Fuchsia:

As to how Fuchsia does it, we can just look at the source:

1) https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/z...
2) https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/z...
3) https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/z...

For example. I don't think there's any magic here: the kernel maintains some structure to reference jobs, tasks or whatever we are calling our isolated privilege boundaries, in which the capabilities are described. On the face of it this "looks" a lot like the traditional permission-style system, but the key difference is that the root job will hand out capabilities to processes it has created. An example is probably the best way to proceed: on a linux system, you might decide your process needs to read `/system/sensitive_file`. To allow this to happen, you might grant access to the user using some other command: chown .../chmod ..., or you might set an selinux policy, semanage fcontext -a -t myprocess_t /system/sensitive_file. In a capability-based system, chmod/chown and even running the process as a user don't exist as concepts. You would need to use a process authorized to transfer a capability to your target process to access this file. In some ways, this is closer to selinux, in the sense that semanage fcontext updates policy, except that the policy is somewhat dynamic here: if your controlling process provides the capability, then the child process gets it.

In a microkernel-based architecture, the idea is that "servers" (jobs that are arguably part of the system, but don't need to be in kernel) are similarly userspace processes subject to said capabilities also.

Of course, some part of the code still needs to be privileged here, let's call it the "executive". This code is doing the capability enforcement, and if that code contains bugs, all bets are off, as always. You can't defend such code from itself, even with capabilities.

The real disappointment is that Zircon is written in C++. Granted it was probably started before Rust was a thing, but while Ada/SPARK might be considered a bit unfashionable, it has some formal verification available, and if you're going for a software solution this should help reduce exploitable bugs. Personally I also wonder what about seL4 made it unsuitable for this: granted, it is not complete as a system, but neither is Zircon alone.