Subject: Towards a capabilities system
To: None <tech-security@netbsd.org, tech-kern@netbsd.org>
From: Elad Efrat <elad@NetBSD.org>
List: tech-security
Date: 08/01/2006 18:49:33
Hi,

We recently integrated the kauth(9) interface, but that was only the
first step in preparing the ground for the more interesting stuff; for
example, capabilities.

This post details the work needed to be done, and more importantly,
lists who can participate in the work -- that includes not only
developers, but also the NetBSD user-base. In fact, the reason I am
posting this to a public list is that I'm interested more in the
latter.. :)

People who just want to get to the summary of how they can help with
each task can simply scroll to its (the task's) bottom.

Task list

  The goal is to classify the authorization requests so that we know
  why and what access is requested.

  Here's what needs to be done:

  1. Making sure all authorization requests really go through kauth(9)

     The traditional Unix security model says "superuser can do
     everything", more or less. Unfortunately, not all NetBSD kernel
     code used to check that fact with suser(9); some code uses
     hard-coded comparisons against zero.

     For example, from sys/ufs/ufs/ufs_lookup.c:WRITE():

	[...]
	/*
	 * If we successfully wrote any data, and we are not the
	 * superuser we clear the setuid and setgid bits as a precaution
	 * against tampering.
	 */
	[...]
	if (resid > uio->uio_resid && ap->a_cred &&
	    kauth_cred_geteuid(ap->a_cred) != 0) {
		ip->i_mode &= ~(ISUID | ISGID);
		DIP_ASSIGN(ip, mode, ip->i_mode);
	}
	[...]

     The comment says we care if we are (or are not) the superuser; the
     code checks if the effective user-id is zero; what we really want
     to know is if we should clear the setuid and setgid bits.

     TASK: Locate occurences in the code where any of the following is
           used to grant or deny access:

		kauth_cred_geteuid() /* <-- jackpot */
		kauth_cred_getuid()
		kauth_cred_getsvuid()
		kauth_cred_getegid()
		kauth_cred_getgid()
		kauth_cred_getsvgid()

  2. Replace KAUTH_GENERIC_ISSUSER with something more specific

     Most authorization requests right now use KAUTH_GENERIC_ISSUSER,
     which simply checks if the user is the superuser. However, what we
     really care about is what operation needs to be done.

     For example, from sys/netinet/raw_ip.c:rip_usrreq():

	[...]
	switch (req) {
	case PRU_ATTACH:
	[...]
		if (l == 0 ||
		    (error = kauth_authorize_generic(l->l_cred,
		    KAUTH_GENERIC_ISSUSER, &l->l_acflag))) {
			error = EACCES;
			break;
		}
	[...]

     According to the context of the code, we can tell that it is
     really a request to open a raw socket.

     TASK: Locate calls to kauth_authorize_generic(), examine their
           context, and mark what the real request is.


Any feedback should be sent to me, preferably off-list. You don't have
to send code patches to help! lists such as this one will help
tremendously:

 ufs/ufs/ufs_readwrite.c:486: zerocmp: retain setuid/setgid bit on move
 netinet/raw_ip.c:544: issuser: can open raw socket

Note, that these are very easy tasks that can be easiy accomplished
using grep(1) and some common sense. :) The problem is that there are so
many of them that we'll accomplish things faster if we work together.
The more people help hunt these down, the faster we can move on to with
*really* allowing the choice of a security model.

The above is *mandatory* before we can implement capabilities, user
roles, program roles, etc.


Thank you,

-e.

-- 
Elad Efrat