Disclaimer: while I'm a fan of capabilities / object capabilities / capability-based security, and also a "Unix person", I (obviously) wasn't among those who have designed Mach, or Hurd, or Unix. So I cannot speak authoritatively, I can only attempt to share what my understanding is.
On Fri, Nov 5, 2021 at 3:52 PM William ML Leslie <william.leslie....@gmail.com> wrote: > > On Fri, 5 Nov 2021 at 22:17, Sergey Bugaev <buga...@gmail.com> wrote: >> The Hurd is a capability system, but not a *pure* capability system: >> it implements Unix semantics on top of Mach/capabilities. File >> descriptors, exec, setuid, etc. are all Unix concepts. > > > Indeed, and the reason I ask is because I'd like to enable more capability > patterns, even though Mach and The HURD don't protect ports like they are > capabilities (c.f. hurd/utils/msgport.c for some really cool and impressive > "look at how much power you have!" moments). I don't think I understand what you mean by "don't protect ports like they are capabilities". Surely Mach ports are capabilities! You can get the ports that a task has if you have its task port, but in that case you already have full control over the task, so you could make it send the ports to you explicitly. msg_get_init_port () alternatively lets you specify the auth port as a credential, but if you have that you could trivially get the task port too. Capabilities can grant different access to the actual object they reference. In _object_ capability environments (think E or Java), this is not true, you either have a capability to the object or not. But then there are objects/capabilities whose only purpose is to provide limited access to another object/capability, so it's effectively the same thing. In Apple's Mach, there's a "task info port", task_info_t, that only grants you basic inspect-only access to a task. But actual Mach task ports (and the only kind that GNU Mach has) grant you complete, full access to the task. And if you have full access to the task, there's nothing insecure about getting the ports that the task has. > One wonderful property of capabilities is that delegating them works. You > should be able to weaken them deliberately, but having them weakened for you > is a bit weird. The stranger thing is having them become more powerful > without an explicit action. Implicitly gaining more power on what is > supposed to be a capability sounds like a new way to introduce a confused > deputy vulnerability. Well, yes, sure, setuid is the textbook example of how to get confused deputies: a setuid executable serves two masters (the invoker and the file owner), most of its context is set up by the invoker, so it needs to ignore things like LD_LIBRARY_PATH, but you can never remember all the things you have to ignore, and so on. But setuid is also the only way in Unix to raise privileges! Plan 9, for instance, has /dev/capuse, which lets you raise your privileges at run time (after authenticating). The Hurd does the same — you can authenticate to the password server and get a new auth port; and using the msg.defs you can even change auth of other processes this way, without them having to do anything explicitly. But the Hurd still has to keep support for the (arguably inferior) Unix setuid mechanism too. If strict Unix compatibility was not a concern, could addauth & friends replace setuid completely? I believe this would require converting all sorts of setuid utilities into privileged servers. The password server is essentially 'su' turned into a server; all the other setuid utilities would need similar treatment too. So for instance there'd be a ping server that does the privileged operation (using raw sockets) at the request of unprivileged clients. > Or alternatively, ignore glibc exec() and talk to the exec and proc servers > directly. Sure, you could do that, but then you wouldn't get the actual setuid behavior. /bin/su would still run as your user, and would not be able to give you a root shell. Sergey