You also can't sandbox event and channel creation for the same reason. It looks like these can also DoS the kernel. In general, any operation you can perform without a handle tends to be subject to DoS and you can't virtualize it. They're also subject to a different access control policy than the rest of the system which is based around handles.
And it's not really necessary. Just reserve the first few handles in a process table for a clock handle, a channel constructor/factory handle and an event constructor/factory handle, and now these operations can be fully virtualized and they aren't subject to DoS because they can be rate-limited or at least traced back to specific handles which can be revoked.
Without tracing every operation to a handle, you have to pollute your model with more infrastructure to track this information, as with channels and events in Fuschia.
There are mechanisms in the works to allow the VDSO to be customized per-Job along similar lines (providing a way of addressing mx_time_get(), etc). mx_time_get() is actually provided entirely in userspace in the default VDSO, but of course we want to allow for runtime environments where we don't allow direct access to the TSC or equivalent.
There aren't any "known" handles in the Magenta design, as handles are not small integers nor aggressively reused (as fds are in unixen). The intention there is to make use-after-free errors with handles more difficult and to make guessing what handles a process has harder.
It's definitely not a "pure" capability design or a "pure" (read/write/exit) microkernel underneath. The goal is to try to be pragmatic and balance performance and api usability/convenience with the benefits of a capability system.
It's also a system in development and the shape of things has changed and almost certainly will change further before we're done.
Implicit handles are not explicit handles, and capability security requires explicit handles. You're obviously familiar with capabilities and the problems inherent to breaking capability properties, so why violate them in this instance?
You mention API usability, but mx_get_time() and mx_get_time(clock_sys), where clock_sys is a static variable initialized by the runtime library at start isn't really any more unusable. Like printf, you can even wrap it in more convenient procedures with no parameters, but you can't go the other way and reify to the clock if that's not how it's designed to begin with.
> There are mechanisms in the works to allow the VDSO to be customized per-Job along similar lines (providing a way of addressing mx_time_get(), etc). mx_time_get() is actually provided entirely in userspace in the default VDSO
This is exactly what I was talking about though: it's totally unnecessary if the clock were accessed via a handle. Why build all of this extra infrastructure when it's completely unnecessary?
Every process would get a set of handles for its basic services, like clock, scratch folder, what-have-you, and building an isolated process just replaces the system handles with wrapped ones. What's the deficiency in this approach that you'd decided to build a more complicated infrastructure instead?
> The intention there is [...] to make guessing what handles a process has harder.
I'm not sure what the point of this is. Are handles not partitioned/per-process like file descriptors? Knowing what file descriptors another process has doesn't give you access to them or yield any advantages. This is how object capabilities should work.
Having them be harder to guess provides some (minor) additional defense against attempting to remotely exploit bugs in another process.
This could be handled in user space without affecting kernel structures using opaque structs and some runtime bookkeeping.
Alternately, Kernel fds could use the low order 24-bits for the descriptor itself, with top 8-bits reserved as an allocation count. When a given fd is closed, increment the counter for the next time it's allocated. You've reduced the chance of already rare misuse by 256 fold with requiring some kind of sparse data structure in the kernel.
Perhaps the current handle design is even harder to misuse, but how defensive should you be for accidental misuse like this?
> Having them be harder to guess provides some (minor) additional defense against attempting to remotely exploit bugs in another process.
I've never heard of this kind of exploit. Do you have an example?