Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 12 Nov 2001 18:52:45 -0500 (EST)
From:      Robert Watson <rwatson@FreeBSD.org>
To:        Terry Lambert <tlambert2@mindspring.com>
Cc:        freebsd-arch@FreeBSD.org
Subject:   Re: cur{thread/proc}, or not.
Message-ID:  <Pine.NEB.3.96L.1011112183454.36592A-100000@fledge.watson.org>
In-Reply-To: <3BF05241.74F895EF@mindspring.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Mon, 12 Nov 2001, Terry Lambert wrote:

> Robert Watson wrote:
> > There are a number of uses of curproc in the netinet code, used to
> > retrieve credentials for authorization somewhere down the stack, when no
> > proc or thread pointer has been passed down.
> 
> I think that the majority of the netinet code can be handled by using
> the socket credential, instead of the process credential. 

The majority, yes, but not all.  In particular, there are a number of
desirable behaviors where you *do* want to use the process credential.  In
particular, relating to binding activities, where current semantics permit
a 'privileged process' to create and bind sockets such that they have
access to otherwise restricted ports, transfer them to unprivileged
processes, but not grant the full scope of privilege to those processes. A
primary example of this in use in practice might be a situation where an
I/O socket is handed off from a network daemon to an unprivileged process,
such as inetd handing off to fingerd: fingerd should not retain inetd's
privileges regarding many aspects of the socket's behavior.  This argument
might be seen more convincingly from the perspective of UDP sockets.  Yes,
it is true that in most cases use of the socket credential is desirable,
but in a number of important cases, it is not.

There are some related cases in VFS, where we consider a per-jail
securelevel based on the acting process, not the file-opening process. 
Similarly, there are some ioctl's on tty devices that are subject
(process)  credential authorized: these are in general present to handle
the case where descriptors to these objects are (and must be) inherited.
There are some related cases, such as fd passing via unix domain sockets,
where the same properties can prove very useful: the ability to transfer
access to sockets/files via LPC as 'rights' rather than delegating all
rights. 

> > With the eventual addition
> > of td->td_ucred, it will be desirable to use the credential for the
> > current thread, rather than the proc, which will require locking to use.
> 
> I think locking credential instances is bad.

That is not what we're talking about.  We're talking about locking the
process structure.  No one is suggesting this.

> The real question you want to answer is whether or not the credential
> instance that was used to acquire a socket should be used continuously
> from there on out (i.e. it is a grant), or whether it should change when
> the process credential changes (i.e. it is a lease).  You seem to be
> arguing for a lease.  I would argue for a grant. 
> 
> One issue is that there are cases where write permission is tested
> before each write.  There are also cases, where you obtain a privileged
> socket, and then relinquish privileges after obtaining it; such cases
> are explicitly modelled on a grant model rather than a lease model. 
> 
> The point is that if the credentials are granted, then a change in
> credential is not a change of the credential itself, but is instead a
> copy-on-write proposition.  In other words, credentials, once granted,
> are priviledge stable. 
> 
> If this is the case, then they are written when they are instanced,
> cloned before they are modified (indeed, it seems that the clone/modify
> operation must be made atomic), and thus are never written once
> instanced -- only destroyed on the 1->0 reference transition. 

Everyone agrees that the ucred semantics are copy-on-write.  This is
well-documented, and not something we're currently interested in changing
(although some platforms have opted to sacrifice memory in order to reduce
locking/atomic operations, and that's something we might eventually want
to consider if we move to very fine-grained and highly parallel
operation). 

> If so, then no locking is required, since the LCK CMPXCHG can be
> utilized to do atomic increment and decrement on the reference counting,
> without needing locks.

There is some disagreement on the topic of atomic operations due to
portability issues (among other things), but that's not what we're talking
about. 

> > As I
> > understand it, use of curproc was branded 'undesirable' at some point in
> > the semi-distant past, and since that time, a reference to 'proc' has been
> > passed down the stack.  With a change to KSE, this has been translated to
> > references the thread, but the issue remains the same.  This comes up in
> > particular because I have a tree where I have propagated the thread
> > pointer down if_ioctl in the network stack: the normal ioctl call carries
> > a thread pointer now, but when it is translated into if_ioctl by the
> > network stack, that pointer is lost.  This raises the question: should we
> > (in practice) be adding process or thread pointers to many more of the
> > function arguments, or should we switch to using curproc/curthread
> > instead.
> 
> The "curproc" undesirability stems primarily from credentials
> enforcement during interrupt processing.  I think that this is not an
> insurmountable issue, but I would argue that these are more appropriate
> for object credentials, where the objects in question are not threads or
> processes. 
> 
> For example, if we were to process incoming TCP connections up through
> the "accept" code at interrupt time, one might naievely assume that,
> since the current socket code down through the accept processing code
> off the queue filled in at NETISR seems to require a proc credential,
> that it is therefore necessary to have a proc credential at interrupt
> time in order to do this processing.
> 
> The answer is that this is a false assumption, and is predicated on
> historical code, and nothing more.
> 
> Specifically, if I need a credential for a newly accepted socket that I
> am now creating, I can add a reference to the listen socket credential
> -- I //do not need// a process credential in order to do an accept. 
> 
> There is a lot of this type of fuzzy thinking, asking "how can I
> propagate the process credential that I used to use for this operation
> down to the underlying code?", when the real question should be "what is
> the appropriate credential to use for this operation, and is the process
> credential really what I want to use in this case?".

I agree there has been a lot of fuzzy thinking.  I also agree that, in
every case, we need to carefully consider the credential used.  In
particular, this is true in the 'new world order' of td_ucred, where we'll
now often have three credentials to decide from:

(1) Mutable p_ucred (requires proc lock)
(2) Cached td_ucred (requires no lock)
(3) Cached so->so_cred, file->f_cred, et al.

In most cases, (2) or (3) will be appropriate.  In some situations,
particularly when it comes to credential update, (1) will be appropriate. 

> I think it's possible to get rid of most of the process credential
> references -- and therefore, most of the proc references -- at all
> points below the /sys/kern/uipc_socket*.c level. 

No, it's not, in a number of very important cases, of which I've
identified at least three above.

Structuring code to have a notion of "but the kernel asked" vs. "but a
user asked" is difficult, and something I'm not sure we have a grasp on
how to approach.  Sometimes, for example, FSCRED or NOCRED is used as a
"special-case" credential to say "do it anyway".  This is often broken
when it comes to distributed file systems where a client system may not
simply be able to assert "because I said so", and probably reflects
unclear thinking on the topic.

> > I don't pretend to have a grasp of all the issues here, so the purpose of
> > this message is to raise the issues so that I can understand them.  I have
> > a tree where I've eliminated many references to curproc; however, I'm now
> > wondering if it wouldn't simply be more useful to eliminate many of the
> > references to struct proc in the function arguments, and use curproc
> > instead, and add references to ucred (and related ref-counted structures)
> > as needed for delegation types of situations.  In particular, that would
> > suggest the following changes:
> 
> I think this is the wrong direction, but if you wanted to do this, I
> think that you would need to put the cur* symbols into the per CPU
> private pages.  This is problematic in the extreme, because it means
> that you must set these values each time going down, in order to be able
> to substitute a per CPU global for the stack reference. 
> 
> I think this is a bad thing, in general, and will lead only to trouble
> later. 
> 
> I would much rather that the credentials be object referenced off of
> non-process, non-thread objects, based on whatever the correct scoping
> really is, for the security model you want to enforce.  My "accept"
> example is only one of a class of changes that could facilitate this. 

I think everyone agrees that the 'cached credential' model is the right
approach for many of these cases, but I think it's over-reaching to claim
it's appropriate in all cases.  The question then becomes, how do we
access the relevant 'subject' credential to authorize the operation: is it
something that is passed down via the call stack (possibly via 'struct
thread *td'), or is it something implicit to the run-time environmenta
('curproc'/'curthread'), which is precisely the question I was trying to
resolve through my post.  If 'curproc'/'curthread' is truly undesirable,
then we can simply eliminate its use, and replace that with almost
universal passing of 'struct thread' (for the purposes of authorization,
but also for other purposes: target of copyin/copyout/aio, scheduling,
ktrace, ...).  If it is acceptable to maintain the use of curproc, we may
want to change some of our primitives to represent it being available. 

Right now, we're in a state of limbo: the official policy (if you will) is
'XXX'.  We should either eliminate it from general use, or we should use
it where it's appropriate :-). 

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.1011112183454.36592A-100000>