Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 24 Nov 1996 16:22:57 -0500 (EST)
From:      Bill Paul <wpaul@skynet.ctr.columbia.edu>
To:        hackers@freebsd.org
Subject:   looking for an idea
Message-ID:  <199611242122.QAA02399@skynet.ctr.columbia.edu>

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

Okay, here's a small problem: you have two processes, A and B, running
on the same machine. Process A is a server and B is a client. A and B
communicate via an AF_UNIX socket. B contacts A and sends it a message, 
which includes B's UID, however there is the possibility that B may lie
about its identity, so A would like very much to be able to learn the
UID of B without any possibility of deception on B's part.

Now, the problem is to find a way for A to verify B's UID without
resorting to grovelling in /dev/kmem. This is necessary since A would
need privileges to open /dev/kmem, and A and B might not be run by
privileged users.

The specific problem I'm trying to solve here has to do with keyserv(8)
from the Secure RPC distribution. The original way this problem was
'solved' by Sun in RPCSRC 4.0 was to use a program called keyenvoy(8).
The keyserv daemon would refuse any connections from clients which a)
did not originate on a port >= IPPORT_RESERVED and b) did not originate
from INADDR_LOOPBACK. Meanwhile, the keyenvoy program was suid-root,
and would be exec()ed as part of the key_call() procedure in the RPC
library. The keyenvoy program would do a getuid() to learn the real
UID of the caller and pass this on to keyserv. Keyserv would accept
the supplied UID as valid since, supposedly, only keyenvoy could have
sent the message and the caller could not coerce keyenvoy into lying.

This approach is flawed mainly because RPC 4.0 only supports IP-based
transports (tcp and udp) which can be spoofed: although keyserv may
be able to determine that it received a request from 127.0.0.1, it
can't be sure that the request really arrived via the loopback interface
(unless it performs some system-dependent mucking about inside kernel
memory). Also, keyenvoy is invoked using vfork()/exec() which results
in a performance hit for processes that need to make many calls to
keyserv.

(Aside: if you're thinking of suggesting that I use identd, forget
it. Maybe Linux developers would be satisfied with that; I'm not.)

In TI-RPC, which is what's in Slowlaris 2.x, this problem was solved
in a different way by taking advantage of the fact that the underlying
code now uses STREAMS/TLI rather than sockets. There is apparently some
way when using the loopback transport for keyserv to learn the UID of
the process on the other side of the TLI endpoint.

Duplicating this in BSD is hard. One thing I've done is to implement
a third transport for the RPC library called "unix" which uses AF_UNIX
stream sockets rather than AF_INET sockets. (This can be done pretty
easily just by copying the clnt_tcp.c and svc_tcp.c modules and making
some relatively minor changes.) When keyserv starts, it now creates
three transport handles: one for tcp, one for udp and one for unix.
Creating the unix transport also creates a socket special file called
/var/run/keyservsock, which is owned by root and mode 000. The keyenvoy
program uses this socket to communicate witht he server. The keyserv
program can get the sockaddr structure for the connection and check
the family type: if it's AF_UNIX, the connection is local and can be
trusted; if it's AF_INET, the server logs a message and discards the 
request. This makes the keyenvoy mechanism work as intended: IP spoofing 
is no longer an issue, and local users _must_ use keyenvoy to contact 
keyserv.

However I want to eliminate keyenvoy entirely. When the mechanism
I have now, it's possible for processes with UID 0 to bypass keyenvoy
and contact keyserv directly. This means that system servers that
require AUTH_DES authentication (like, say, rpc.nisd) can avoid the
performance hit, but unprivileged client programs are still forced
to use keyenvoy.

So far I've only found one potential solution to this problem, but
it's not pretty. It occured to me that if process A can learn the
PID of process B, then it can map that into a UID by examining the
/proc filesystem (/proc/<PID>/status). One way to do this is to use
SysV IPC. If A creates a message queue, and B sends A a message with
msgsnd() just before sending its usual RPC, then A can read the
message and then do a msgctl(msgid, IPC_STAT, &mqid) and examine
the mqid.msg_lspid member, which should tell it the PID of the last
process to call msgsnd() on this particular message queue. This, in
concert with /proc/<PID>/status gets you the UID. (This can also
be embedded in the RPC library and keyserv code so that it's invisible
to the user.)

But this will only work if PROCFS and SysV IPC are configured into
the kernel and /proc is mounted. Its also possible that there may
be a race condition involved (maybe I could solve that with a
semaphore -- Gaaahhh!!). Previously, I also experimented with
sending a file descriptor over the AF_UNIX socket from the client
to the server using sendmsg()/revcmsg(), but this doesn't provide
any useful (i.e. trustworthy) information either. I thought about
having the client do an fcntl(s, F_SETOWN, getpid()) on the descriptor
and then passing it to the server, which could then read the PID
back with fcntl(s, F_GETOWN, 0), but this doesn't work because fcntl()
basically allows you to specify any number as a PID.

Of course, it's possible to hack the kernel such that it will copy
the UID of the sending process into the message somewhere if you
supply the right flag, but I'd like to avoid that; having the code
fail on other *BSD systems would be bad.

So: I'm open to suggestions. Is there any nice and easy way for
a server process on one side of an AF_UNIX socket to learn the
UID of the process on the other side? I really want to toss
keyenvoy in the dumper.

-Bill

-- 
=============================================================================
-Bill Paul            (212) 854-6020 | System Manager, Master of Unix-Fu
Work:         wpaul@ctr.columbia.edu | Center for Telecommunications Research
Home:  wpaul@skynet.ctr.columbia.edu | Columbia University, New York City
=============================================================================
 "If you're ever in trouble, go to the CTR. Ask for Bill. He will help you."
=============================================================================



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199611242122.QAA02399>