Bugtraq mailing list archives
Re: Why you should avoid world-writable directories
From: wpaul () CTR COLUMBIA EDU (Bill Paul)
Date: Sat, 26 Dec 1998 17:19:25 -0500
Of all the gin joints in all the towns in all the world, Jason Thorpe had to walk into mine and say:
On Thu, 24 Dec 1998 00:50:48 -0800 Jason Thorpe <thorpej () nas nasa gov> wrote: > On Wed, 23 Dec 1998 09:28:35 +1100 > Darren Reed <avalon () coombs anu edu au> wrote: > > > In a way, that is exactly the type of thing he is referring to, BUT, > > LOCAL_CREDS must be supplied to be received as opposed to just "looked up" > > with getpeeruid() (my understanding anyway). > > Yes, they are a control message. This works well for SOCK_DGRAM, but > not as well for SOCK_STREAM, since w/ SOCK_STREAM you can connect and > then never send any data, thus the task wanting the credentials never > gets them. Actually, let me clarify this just a little. I was pretty tired when I wrote that reply :-) The credentials are supplied by the kernel. The kernel prevents the sender from supplying them, for obvious reasons. Upon reception of any datagram on a LOCAL_CREDS-enabled socket, the credentials are available in a control message. There is one credentials message per datagram if the option is enabled. For stream sockets, the credentials are supplied only once, when the sender first sends data. If the sender never sends data, the receiver never recieves the credentials.
When I tried to implement this for FreeBSD (mainly so that I could get keyserv to work without keyenvoy), I took something of a shortcut by having the credentials filled in by unp_internalize() in uipc_usrreq.c. This has the side effect of requiring the caller to use sendmsg() if it wants to send credentials to the process on the other side (which also needs to use recvmsg() to receive them). You can use sendmsg() with either a SOCK_DGRAM or SOCK_STREAM socket, so you end up with credentials sent every time the caller transmits data regardless of the socket type. This requires some extra work on the part of the caller: it must set up the msghdr struct to use with sendmsg() and it has to pretend to send its credentials as a control message, however the actual credentials are filled in by the kernel regardless of what the caller tries to send (i.e. it can try to lie about its identity, but the kernel will blow its cover). A properly written receiving process will always use recvmsg() to read data from the caller and will insist that control message of type CMSG_CREDS be present with each transmission, otherwise it will drop the data on the floor. This means that if the caller tries to send data using write() the receiver will ignore it since, while the data will get through, there will be no ancillary data with it.
In any case, if you (the receiver) enable LOCAL_CREDS on the socket, the only work you have to do is the receive of the control message and parsing of it. The sending application does no additional work. It is out of the loop as far as the sending of credentials is concerned.
The version I wrote doesn't require a socket option to be set, however it does require the sender to do additional work by using sendmsg() and sending an empty creds structure to be filled in by the kernel each time that it transmits data. I'm sure somebody will take great pleasure in explaining to me why I was an idiot to make it work like this, however it seemed like the best approach at the time, given that I was trying to implement something that would work well with RPC. I was also trying to keep the kernel modifications as small as possible.
I don't really see any value in getpeeruid() since it can _only_ apply to Unix domain sockets. Why invent a system call with no other use when you can just use existing general-purpose interfaces?
A getpeeruid() syscall wouldn't perform the same function as the LOCAL_CREDS option anyway, since it does not allow you to perform access checks on a per-message basis, which is important given that UNIX allows multiple processes to have descriptors pointing at the same socket. Getpeeruid() would (at best) tell you who created a socket, but it wouldn't tell you who sent a particular message over it. -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 ============================================================================= "Mulder, toads just fell from the sky!" "I guess their parachutes didn't open." =============================================================================
Current thread:
- Re: Why you should avoid world-writable directories, (continued)
- Re: Why you should avoid world-writable directories Darren Reed (Dec 22)
- Re: Why you should avoid world-writable directories Rich Burroughs (Dec 22)
- Re: Why you should avoid world-writable directories Wietse Venema (Dec 22)
- Re: Why you should avoid world-writable directories Nick Maclaren (Dec 22)
- Re: Why you should avoid world-writable directories Jason Thorpe (Dec 24)
- Re: Why you should avoid world-writable directories Alan Cox (Dec 24)
- Administrivia Aleph One (Dec 26)
- Nlog 1.1b released - security holes fixed HD Moore (Dec 26)
- referer problems... Spencer Portee - Yard Productions (Dec 26)
- Re: Why you should avoid world-writable directories Jason Thorpe (Dec 24)
- Re: Why you should avoid world-writable directories Bill Paul (Dec 26)
- Re: Why you should avoid world-writable directories Robert Watson (Dec 27)
- Re: Why you should avoid world-writable directories Bill Paul (Dec 26)