Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 2 Oct 2001 10:11:51 -0400 (EDT)
From:      Robert Watson <rwatson@FreeBSD.org>
To:        arch@FreeBSD.org
Subject:   nfs_lock.c and rpc.lockd: request for enlightenment on apparent evil
Message-ID:  <Pine.NEB.3.96L.1011002095551.98303A-100000@fledge.watson.org>

next in thread | raw e-mail | index | archive | help

As part of the on-going capabilities development work, all kernel access
control checks are being reviewed for correctness and consistency.  Right
now, there's some un-pretty code in the new NFS locking code:

        /*
         * XXX Hack to temporarily allow this process (regardless of it's creds)
         * to open the fifo we need to write to. vn_open() really should
         * take a ucred (and once it does, this code should be fixed to use
         * proc0's ucred.
         */
        saved_uid = p->p_ucred->cr_uid;
        p->p_ucred->cr_uid = 0;         /* temporarly run the vn_open as root */

That's pretty ugly (especially because that ucred is shared).  As the
comment indicates, that's probably relatively fixable -- either we can
make vn_open.c use a more appropriate credential (perhaps cred0, perhaps
one cached from the source of the fifo, or perhaps even keeping the fifo
open so that it doesn't have to be reopened -- we can find something). 

But it gets worse:

        /* Let root, or someone who once was root (lockd generally
         * switches to the daemon uid once it is done setting up) make  
         * this call.
         *
         * XXX This authorization check is probably not right.
         */
        if ((error = suser(p)) != 0 && p->p_ucred->cr_svuid != 0)
                return (error);

It should be noted that this is probably entirely the wrong approach to
the problem.  In general, only the effective uid should be used for
authorization.  If the process has an svuid set to something other than
its ruid or euid, it can always swap them around -- probably rpc.lockd
should simply set its effective uid back to 0 when it wants to perform
this action, rather than remaining using daemon_uid.  There are certainly
advantages to running as 'daemon', including reducing the risk of using
root privilege in an un-anticipated way.  However, if the goal was to
prevent a compromise of rpc.lockd from resulting in root compromise, that
fails, since the saved uid is set (and relied on :-).

However, I'm not very familiar with the implementation here, and am only
just starting to get a grasp on it.  It would be much faster for someone
whos familiar with it (Alfred?) to look at my comments and tell me if
they're off-mark.  Specifically, is the following proposal going to cause
problems due to other use of credentials: 

  Remove the above svuid clause, relying purely on suser() (or in the
  capabilities case, appropriate privilege), and modify rpc.lockd to
  restore the saved uid using seteuid(), and then restore the daemon uid
  using setuid() on either side of the call.

For the other case above, I have do do a bit more reading before
suggesting a course of action, but in general, setting root privileges on
a ucred to perform an action in this way is a bad idea.  It's even worse
because it's a shared ucred, which sets root privilege for all other
processes sharing the ucred for the duration of the call, as well as any
open files with that ucred cached.

(people really need to figure out that ucred's are shared, or just learn
not to touch ucreds)

Robert N M Watson             FreeBSD Core Team, TrustedBSD Project
robert@fledge.watson.org      NAI Labs, Safeport Network Services


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-arch" 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.1011002095551.98303A-100000>