Date: Sun, 18 Jun 2000 12:21:27 -0400 (EDT) From: Robert Watson <rwatson@FreeBSD.org> To: posix1e@cyrus.watson.org Cc: trustedbsd-discuss@trustedbsd.org, linux-privs-discuss@sourceforge.net Subject: Capabilities workshop, followup questions Message-ID: <Pine.NEB.3.96L.1000617135941.1435G-100000@fledge.watson.org>
next in thread | raw e-mail | index | archive | help
First I'd like to report that the recent capabilities workshop held by SGI was a great success, at least from my perspective. A number of wrinkles were worked out, and it looks like the resulting implementations will be consistent and highly interoperable from an application perspective, as well as from the perspective of analysis for evaluation. I'd like to publically thank Casey and the others at SGI who made the event work so well :-). There are a few followup questions in my mind. First, for the purposes of a record (as it was pointed out at the meeting that for POSIX.1e discussions, there really hasn't been a record), I think it would be useful for us to write up our conclusions. In particular, conclusions as to what the correct interaction between uid-based models and capability-based models should be, and rationale for that. Additionally, what we concluded as correct behavior for environments where (a) no on-disk capabilities are available, (b) situations where capabilities are available but undefined for an executable. Finally, we reached some conclusions about inheritence properties over exec(), and probably ought to describe rationale for that also. I didn't take notes during the meeting, so I'll just address the ones that I come to off the top of my head. We concluded that the superuser security model and capability-based models should be, wherever possible, independent. We found it difficult to reason effectively about the variety of "emulation" options, and found that the interactions often resulted in what was generally agreed to be in violation of POLA. One important aspect to the discussion was migration path: all parties seemed to be in agreement that the eventual goal was removal of a privileged uid 0, but that the migration path would be long and painful :-). The stepping stones appeared to be: - Capabilities support without file system backing, privileged uid0 - Capabilities support with file backing, privileged uid0 - Capabiltiies support with file backing There was fairly heated debate on the topic of the merged uid/capability implementation in Linux, with objections to it including complexity and interoperability. Positive considerations for the model included a possibly easier migration path with the opportunity to use capabilities to improve security in the short term, prior to file system backing. The eventual pseudo-code for the authorization check looked something like the following (with a slightly bsd-esque twist) int capable(credential, capability) { if (cap_check(credential, capability) && optional_capability_mask(capability)) { /* audit() */ return (1); } if (suser(credential) && optional_suser_mask(capability) && suser_enabled()) { /* audit() */ return (1); } return (0); } There was discussion of introducing both a global capability mask at inheritence time and runtime, as well as a per-process bound inherited and modifiable only with privilege. There did seem to be general support for a global bound, not unlike BSD secure-levels, disabling specific capabilities for all processes. There was also discussion of whether or not the same bound should apply to super-user authorization, and that sounded good to many also. There was an objection (mine) to conditionalizing suser behavior on whether or not capabilities were present on a proces -- generally that this caused more interaction between the two mechanisms, which would limit extensible authorization techniques such as Poligraph. Per-process bounds, we concluded, had to be thought through. It did seem to be the case that such behavior might be useful (jail-like), but that it would open the door to more attacks like the sendmail attack if permitted for unprivileged processs (not unlike chroot). There was general discussion about whether jail techniques should or should not be integrated with capabilities. I don't think there was concensus about introducing per-process capability bounds, but that there was for global bounds, and that the global bounds would be instituted at authorization, not inheritence. Given that different systems have different ways of managing kernel configuration at run time, and that global bounds are likely part of system bootup, I don't think there was consideration of an API for doing that. At least in the FreeBSD implementation, this is managed using a sysctl(), but /proc in Linux-land might be a good way. Monotonicity for a global bound sounds useful. One issue that was discussed is behavior on file systems supporting capabilities, but with capability sets undefined for a binary. Two prevailing views seemed to hold: James Buster argued that POLA requires that these binaries inherit capabilities from the parent process, if the parent permits it. Casey believed that they should only be inherited if the binary was explicitely configured to accept them. The second appealed due to security, but is counter-intuitive for many uses. One possibility is to assign appropriate capability acceptence on all binaries in the TCB, allowing audited system binaries to accept capabilities, but not custom binaries that haven't been vetted by the system administrator. As one potential use of capabilities is assigning a shell CAP_DAC_READ, it would indeed be violating POLA if shell-built-in functions worked to read files, but external programs didn't :-). Finally, I had a few questions about things we did not resolve. First, in the setuid world, modifications to the setuid binary result in removal of the setuid bit. Should modifications to a capabilities binary result in capabilities being removed? Richard Offer and I discussed issues of threading and capabilities in the morning, and brought it up again briefly in the afternoon. Ted Ts'o noted that the Linux uid handling for POSIX threads is currently not correct according to spec (which might break things in an m:n threading model), and I was interested in whether or not the same problems will occur with capabilities. In the POSIX world, privilege and credentials are bound to processes, and not threads; this is how it is in FreeBSD currently as we don't support kernel threads except under emulation. Will the Linux implementation bind capabilities to individual threads? As I don't have a copy of D16, I can't comment on the rule set differences, but it sounded to me like we firmly concluded the D16 inheritence rules were the way to go. Could someone post the conclusions on that? I've presumably missed some stuff here, and would welcome comments and criticisms. I've set the Relpy-To to the POSIX.1e cross-platform mailing list, as the resolution to these issues is relevant to all platforms, especially in the name of application portability. I've CC'd it to the two capabilities implementation mailing lists I know of -- the TrustedBSD discussion list, and the linux-privs list. Robert N M Watson robert@fledge.watson.org http://www.watson.org/~robert/ PGP key fingerprint: AF B5 5F FF A6 4A 79 37 ED 5F 55 E9 58 04 6A B1 TIS Labs at Network Associates, Safeport Network Services To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-security" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.NEB.3.96L.1000617135941.1435G-100000>