Current state of trace mode?
Jordan K. Hubbard
jkh at apple.com
Sun Sep 9 01:18:44 PDT 2012
On Sep 3, 2012, at 9:15 AM, Joshua Root <jmr at macports.org> wrote:
> At a high level, this is what MacPorts wants:
> * to deny write access to everything outside ${workpath} for most
> phases, excepting also a handful of other places on a per-phase basis
> (like ${distpath} for fetch).
> * to deny read access to any file installed by a port that is not a
> direct or indirect dependency of the port being built -- ideally it
> looks to the build system like the files don't even exist.
> * to deny read access to everything else that isn't part of the base OS
> (e.g. /usr/local, /Library/Frameworks).
Hmm. That could be done entirely by sandboxing, actually. If all you're trying to do is deny filesystem operations and/or execution outside certain paths, all of that can be done with custom SBPL (sandbox profile language) code, numerous examples of which exist in /usr/share/sandbox. sandbox-exec will also read this profile and apply it to a hierarchy of processes, so you don't even need to call any of the sandbox SPI calls to put the "current process" in a sandbox if what's being traced is already a sub-process (which I believe it is).
Figuring out the filesystem access needs of the direct/indirect dependency graph is a harder problem unless every macport also (programmatically) creates a .sb file that expresses its own needs and can then be included by any ports which need it, which could be useful for other reasons (like actually sandboxing the port itself). There are sandbox rule files like system.sb that can be (and frequently are) included to encapsulate all of the system requirements, so that part is easy.
> We don't actually need to *know* what is being attempted, the OS just
> has to allow or disallow it according to the rules we set up. Having the
> info available on request would be good for debugging though. That said,
> we definitely care about stat and exec.
All of which can be done by sandboxing, including the reporting part "(debug deny)". It would be trivial to prototype this with sandbox-exec in any case, since all the mechanism is already there and it's easy to sandbox-exec a shell for interactive testing of the sandbox parameters. You would probably need to do a substitution pass over a boilerplate sandbox profile file to expand things like ${workpath} and ${distpath} for that specific port before doing the sandbox-exec on it, but again, that's trivial to do.
> For port(1) itself we ideally want the permissions to be dynamically
> modifiable, i.e. we can get back permissions that we gave up while
> running a phase in the portfile. But for the child processes it should
> be locked in for the lifetime of the process. If we have to, I guess we
> could use helper processes instead of changing the access of port(1),
> but that's a fair bit of extra work.
Well, that's the sticky part. Once a child is in a specific sandbox, it can't break out / modify its own rules since that would obviously defeat the purpose of sandboxing. If you were willing (perhaps only when using trace mode) to invoke each phase of port as a separate fork/exec then, of course, it would be easy and also let you customize the boilerplate for each phase (only granting access to ${distpath} for fetch, for example). Alternately, you could stick to the single port(1) process for all phases but be sure to invoke the tools which actually do the work (${fetch.cmd} for example) with the appropriate sandbox profiles, accomplishing much the since it's obviously not port(1) which is doing the filesystem munging, it's shell commands like make(1), curl(1) and so on!
Perhaps most beneficially about the sandboxing approach is the fact that SBCL is so expressive and powerful, being a dialect of scheme which also has the ability to restrict access to any sort of file access, process creation, mach port lookup, you name it and with just a couple of lines of scheme code. At that point, trace mode doesn't just become a safety belt, it becomes an intrinsic part of macports' security model which allows it to run as root (which it already does) without necessarily letting it, or a malformed / malicious / buggy port from running amuck on a user's system. I think we've just gone a lot further than tracing!
- Jordan
More information about the macports-dev
mailing list