How might one set up a secure, efficient message-passing facility?

The Grey Wolf greywolf at unisoft.UUCP
Thu Feb 14 08:50:19 AEST 1991


In article <20186:Feb1103:17:5691 at kramden.acf.nyu.edu> brnstnd at kramden.acf.nyu.edu (Dan Bernstein) writes:
>I want to set up a library so that, e.g., a syslog message can be
>securely tagged with the userid of the logging process. I imagine that
>the library needs some way to create a descriptor with the right uid
>pointing to some sort of message-passing daemon. The daemon would then
>make sure that each message from a descriptor is tagged with the uid
>that created the descriptor. For definiteness, let's say the descriptor
>is a UNIX-domain socket (under BSD) or a stream (under System V) so that
>processes can shuttle descriptors to each other and talk efficiently
>rather than routing every message through the daemon.
>
>So far the library is perfectly straightforward. The problem is that
>creating the secure descriptor in the first place probably requires
>executing a program and having it shuttle the descriptor back. I want
>this library to be more efficient than that: while an extra
>fork()/exec() doesn't make a difference to long-running programs, short
>programs should be able to pass messages without doubling their runtime.
>
>First question: Is there any (practical) way of creating the descriptor
>securely, reliably, and without forking a process?

If you're mucking about with uids, then no, because once you change
real and effective uids to something other than zero, you're stuck.
Most programs with any sense of integrity whatsoever will not allow
the real uid and the effective uid to remain different.

If you're fiddling with descriptors, then no, unless you have a way
to restore them to their "original" state if something goes Wrong.

>
>One solution is to pass the secure descriptor from parent to child. In
>most cases, just one extra execution will suffice to give message
>passing to an entire user process tree. The library can check whether
>the descriptor is indeed an open UNIX-domain socket owned by the current
>userid, and create a new descriptor if not. (An environment variable can
>show the right descriptor if it's not the default of, say, 13.)
>
>Almost all existing setuid programs will have no problem with this
>scheme: they only execute programs as the original userid, and they
>don't use the library themselves, so the descriptor will just pass
>through unchanged. This rule will begin to break down when setuid
>programs start using the library (e.g., if syslog() is rewritten).
>A user must not be able to forge a descriptor that looks secure.

Compare the uid of the user with the uid of the descriptor with the effective
uid of the user -- if something is off, that's pretty obvious.  (Were
you looking for something more?)

It seems to me that your concern of setuid programs using the library
are only worth worrying about if you're implementing shared libs (which,
so far, have proven to be more trouble than they're worth -- at least
for me, and for the moment).

>
>Third question: What can the library do to make sure that a secure
>descriptor isn't accidentally passed out of a setuid program? Should it
>set close-on-exec on the descriptor inside any setuid program? Is this
>enough?

If the program is "established", that is, if the program is not just some
hack that a gullible sysadmin gave setuid privileges to (so the user
could re-create it with other calls, using other libes, etc. (in which
case this is a moot point anyway!)), then why the worry about a secure
descriptor being passed out of a setuid program?  I don't see how it
could be unless the program had some serious design flaws.  Or unless the
library is rewritten completely to subvert your efforts in which case,
again, the point is moot.

>
>The other problem case is a setuid program that executes programs as
>something other than the original userid. The classic examples of this
>are su and login. The library will somehow have to make sure that
>there's no chance of login starting with a root descriptor and passing
>it on to the user's shell.
>

In general, this doesn't happen anyway; I believe pains are taken to
ensure that descriptors 0, 1, and 2 are all that's passed to the user's
shell.  What the shell does after that is its own business (and quite
messy, too, if I read the shell code right).

>Fourth question: Is there any way to make sure of this other than
>requiring su and login (and any other programs that change uid) to close
>the descriptor? Is there any more efficient solution than setting
>close-on-exec for every root message-passing descriptor, so that every
>root process has to get a new descriptor? Are there any setuid programs
>that do anything like unset close-on-exec on every descriptor before an
>exec()?

4a:  I don't think there is.  Closing the descriptor is probably the
	best way that you're gonna insure that nobody else gets the thing.
4b:  Well, you could check to see who inherited the descriptor somehow
	(probably in the lib routines...).
4c:  I rather hope not.  I can see *not* setting FCLEX, but I can't
	see setting FNCLEX on every fd.

>
>Whoever gives me answers that I use will get appropriate credit in the
>package. Final question: Does anyone think a secure message-passing
>system will be useful? I think the inability to write a setuid library
>is one of the biggest problems with UNIX security: it convinces people
>that security can only come at a huge expense in efficiency, and they'd
>rather have the latter.

It would be useful, but I think there's a mechanism which would be
nice to have which might help your cause.  How about a FCSUID operation
in ioctl() or an added flag in the word returned by a fcntl(fd, F_GETFL, arg)
call which would cause the file descriptors to be closed on setre[ug]id
calls?

(Tangent:  Why don't they just implement all the setuid/setgid stuff
 into one setreugid() system call instead of two?)

>
>I don't want to hear that Mach and other UNIX variants do this already.
>I'm sure I'll be able to port the library to a Mach machine if I ever
>use one. I also don't want to hear that message queues are a solution;
>they do not report the remote userid reliably, they do not support basic
>operations like file descriptor passing, and some of their BSD ports are
>insecure. (Last I checked, any user under Ultrix could remove any other
>user's message queues, no matter what the permissions---and then
>substitute a message queue under his own control. How useful.)

Ack.  That last part does make a bit of a pinhole doesn't it?  Kind of a
hole you could fly a planet through.

>
>---Dan


-- 
thought:  I ain't so damb dumn! | Your brand new kernel just dump core on you
war: Invalid argument           | And fsck can't find root inode 2
                                | Don't worry -- be happy...
...!{ucbvax,acad,uunet,amdahl,pyramid}!unisoft!greywolf



More information about the Comp.unix.programmer mailing list