Skip site navigation (1)Skip section navigation (2)
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>