On Sat, Jan 03, 2009 at 01:23:02PM -0800, Roman V. Shaposhnik wrote: > [ I took a liberty to merge two of your emails together for the ease of commenting ] Thanks. :) > On Thu, 2009-01-01 at 18:57 -0500, Nathaniel W Filardo wrote: > > That is, the claim that "a process spawned without access to your home > > directory cannot get it" is flawed if that process runs as your user. > > (Even if I can't mount it, I can attach a debugger to a process that > > can and make it make system calls for me. You now have to > > intermediate my #p (/proc) service. You have to ensure that I can't > > dial it and authenticate with factotum. It's a mess!) > > It would seem to me that none of the issues that you've mentioned here > are insurmountable. As far as #p and #s are concerned the good news > under Plan9 is that they are supposed to be 'just servers' (the reality > of the situation is a bit more grim -- but I'd would like to discuss > this in the separate thread). As such, if the default implementation > seems too open, you can always harden its security semantics by > providing proxying user-level servers (well, that plus fixing all the > smart-ass apps -- more on that in a separate thread). > > All in all, I don't see the above example as a fundamental obstacle to > what you're trying to accomplish. Agreed. I think the kernel modifications necessary are small and tastefully doable. > > I may be tainted by the capability microkernel koolaid, > > but I don't like the idea that users are the sole security > > domain objects > > How does your ideal world look like? What else, besides users and groups > of users would you like to have as security domain objects? Namespaces are containers, if the objects bound in to the namespace are well behaved. That is, if I cannot refer to an object in my namespace and no server I can refer to will grant access, then I have achieved isolation of that object and any process running in my namespace. Users make sense for remote services -- it's an excellent mechanism for reconnecting a principle with its capabilties (nabable objects and permissions) on a remote server. Perhaps in local cases they make sense as well, but in Plan 9 the only "local" services are kernel provided. Most of these, AFAIK, only differentiate between hostowner and not. The few that leap to mind that have more advanced permissions schemes, '#p', '#s', and the servers backing /net, have, IMHO, dubious models backing them. '#p' allows any of my namespaces to debug processess in any other, '#s' is too global, and /net seems to allow any of my processes to manipulate any of my other processes' network connections (though I've not tested in detail to see what's possible.) Groups are woefully problematic in almost every system I can think of (NIS, LDAP, AFS's PTS) and Plan 9 is no exception. Groups are left to interpretation by the server, and in most cases are ignored. Perhaps SPKI will solve some of this. > > I really dislike that I can build stronger security constructs when > > using multiple kernels rather than just one. Especially in a system > > like Plan 9, where namespaces are cheap and capabilties exist in the > > form of file descriptors. > [....] > > That is, I want, essentially, to run multiple Plan 9 systems on one > > Plan 9 kernel without needing to get my whole domain to know about > > multiple instances of my user > > The above two seem to be the most crucial statements in all of this > thread. If I were to interpret them, I would say that what you're really > after is being able to provide an OS-level virtualization solution > under Plan9. "OS-level virtualization" is only a meaningful concept because, traditionally, our kernels were not. I want there to be no distinction between the security guarantees that can be made when one or many kernels are in flight. >[snip] > Now, under Plan9, #1-3 come for free. I'm not sure how #5 is possible > (anybody?). And thus #4 is the only are that needs work. That work, > is really all about teaching things like #s and #p to only disclose > information about processes running within the same "zone". Whether > "same zone" means "same process group" or an extra level of process > grouping is needed remains to be seen. Run with me for a moment to see how this might work without the extra level of grouping. Let's introduce an fdbind() call which takes a fd and a path, and binds the fd's chan on the path in the current namespace. This is essentially an optimization around spawning a billion exportfs processes and mount()ing the resulting descriptors. Now, suppose '#s' and '#p' -- the kernel services -- expose only the current process group (==namespace). If I want different behavior, when I construct the new namespace, I ensure that I have open fds to my /proc and /srv and fdbind() these in the new namespace along with '#s' and '#p'. If desired, the new namespaces' '#s' and '#p' can be posted (or sendfd()'d; see below) to the parent process, doing the inverse kind of exposure. > > > > supposing that you have a fully jailed process. if it has a connection > > > > to the fileserver, which does do security by user id, the jailed process > > > > can still mess with you. say by deleting all your files. > > > > Yes, exactly. I don't understand the question? > > The question, as I understood it, was about the practicality of such > attack. For every fully jailed process that belongs to the user Foo, > the following holds true: either it has no existing channels to the > external file servers and no means to create them, or it can obtain > a channel (either existing or a new one). From the point it connects > *and* passes the auth process, you are constrained by the security > model of 9P. Users and user groups are the only thing that is there. I think perhaps this attack was a figment of my imagination. The descriptors posted in /srv posted by default are the connections not the result of Tattach messages. As long as this is observed, it suffices to remove access to the user's factotum and not otherwise give the namespace so constructed access to the user's secret. > > > > i think the real question here is why don't you trust your > > > > processes? is it because someone else is running them > > > > > > That was, essentially, my original question. Nathaniel, could you, > > > please answer it? > > > > I'm looking at a system like 9gridchan > > What is 9gridchan? http://www.9gridchan.org/. Perhaps a better example of where I might not trust my processes would be Firefox. :) > > where an essentialy autonomous agent publishes services. > > How does that publishing happen? If the system is distributed, > I'd presume that the publishing happens in a network-friendly > manner, thus making the whole discussion around #s pretty much > moot. The agents post and access resources via the local /srv. > > Further, 9gridchan pollutes the namespace of /srv for everybody > > else on the system, and its current naming scheme makes it impossible to run > > two 9gridchan agents (w/o modification) even as different users. > > I have to know more about 9gridchan agents in order to reason about > this intelligently. So far it seems to me that your general issue > with a global nature of /srv can be somewhat mitigated by following > a particular naming convention for files under /srv. More on that > later. The same holds for /tmp. > > I also want, I think, an extension to 9gridchan where I can publish a > > service which relays for other 9gridchan nodes, which essentially means that > > remote machines are directing the contents of my /srv. (I want this so that > > I can bounce around NATs or loss of direct connectivity in the 9gridchan > > mesh... other proposals for solving this problem welcome.) > > Again, I have to know more about 9gridchan and how the publishing works. > > > However, /srv is currently the only mechanism (AFAIK) for a fd in a pgrp A > > to be given to a process in pgrp B. Therefore, if /srv is to be virtualized > > (made a property of namespaces) ala /tmp, then something like sendfd() seems > > to be necessary to replace this functionality when required. > > Now, just to be clear: this requirement is quite different from > your earlier OS-level virtualization, since you're trying to > introduce an IPC between processes which were specifically told > to behave as though the only IPC available to them is networking. It's a little more related... the observation is that global '#s' makes sense in some cases, but it is not a "virtualizable" interface. Therefore, the question becomes how one would build something like it on top of a virtualiable interface. > That said, the requirement itself makes sense. Although, even with > sendfd() you have to have a socket connection established before you can > pass fd's around. Except for the case where such socket connection > was created using socketpair() the sockets are *named* objects. > And that should present all the same problems that naming files > under /srv presents, shouldn't it? sendfd() is a little special since it uses "out of band structured ancillary data" (or something like that?) to do its magic. See below. > IOW, I'd be very curious to see a proposal from you on how the > channel for this imaginary sendfd() is supposed to be managed so that > it gets rid of all the issues you've identified with /srv. It's a bad answer, but notes are at least one way of sending messages to processes you can name (e.g. exist in your /proc bindings) but with which you have no common namespace elements. More realistically, the plumber is an excellent example of a (virtualizable) message passing and routing service which suffices to allow processes in properly constructed namespaces to send textual information. '#|' is another. I've been imaginging sendfd() to be based on a non-enumerable /srv replacement, where possession of the file name and able to walk to it suffices to prove access rights to the posted descriptor. Let's say the protocol is that this magical device serves a ctl file, into which one writes a fd number and reads back a long, guaranteed unique, string. This string names a file beside the aforementioned ctl file. Despite being a global service, this can be safely mounted in every namespace with no information exposure (non-enumerable). Like /srv, it's even possible and sane to exportfs this (assuming that the clients are willing to trust the exportfs process). It's possible to emulate /srv atop this by publishing a list of file names somewhere. Here's another example of where something like sendfd() might be useful, if it helps: suppose the plumber has an active acme client which is in a different namespace from the shell I'm about to plumb a path in. If I could open() that path, post it to the imaginary non-enumerable /srv, and send the name to the plumber, then acme could open() and fdbind() that file, allowing me to work with it, even without giving acme the rest of the namespace. If you trust acme, consider instead Firefox. ;) > > Does that help answer the question? > > Well, it definitely helped me understand what is it that you're after. Glad. Thanks for discussion. :) --nwf;