Issue 4893 - ldapi security issues
Summary: ldapi security issues
Status: VERIFIED FIXED
Alias: None
Product: OpenLDAP
Classification: Unclassified
Component: slapd (show other issues)
Version: unspecified
Hardware: All All
: --- normal
Target Milestone: ---
Assignee: OpenLDAP project
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2007-03-24 23:06 UTC by Hallvard Furuseth
Modified: 2014-08-01 21:06 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Hallvard Furuseth 2007-03-24 23:06:59 UTC
Full_Name: Hallvard B Furuseth
Version: Many...
OS: HPUX
URL: 
Submission from: (NULL) (129.240.202.105)
Submitted by: hallvard


Indented text is copied from Howard's mail to openldap-committers,
mostly for completeness.

  [There are] security issues with the implementation of ldapi on
  platforms that don't explicitly provide for passing the socket peer's
  credentials. On those platforms we create a pipe and use descriptor
  passing to send the pipe descriptor to the server, which then fstat's
  the descriptor to obtain the uid and gid of the client.

Users can give away file ownership on HPUX (at least the box I am using,
I don't know HP in general).  fchown(pipe descriptor, 0, 0) lets me Bind
as root.

There is a slight escape: fchown(regular file) resets the setuid bit, so
the server could require a regular file with the setuid bit.

It does not reset a pipe's setuid bit.  And I think resetting the setuid
bit is an OS feature which differs between OSes, so at the very best
we'd need some research, and I think it'll take a tmpfile() call and 7-8
system calls to create a regular file and descriptor just right.

Note: The current server code requires (a) that the descriptor is a
pipe, and (b) that group/other permissions are 0, so the user cannot use
a descriptor from opening someone else's named pipe.

Anyway, maybe this is the place to stop reading and skip to "Server-side
descriptor handling bugs" below.  I'd already written up this ITS when I
noticed the fchown issue, so I'm sending it all off anyway.

  The first issue is that it's possible for a user program to inherit
  root-owned descriptors from a number of sources. cron on Linux is an
  example of this case (although since Linux provides explicit identity
  passing, it is not vulnerable for that example). Another more pressing
  problem is on HPUX: the ssh daemon spawns non-interactive children with
  root-owned pipes for their stdio descriptors. So it's possible to write
  an ldapi client on HPUX that allows any user to authenticate as Unix root.

  The second issue is that the credentials can be reused indefinitely by
  the server to talk to another ldapi server. If the directories leading
  up to the ldapi socket are not adequately protected, this could allow a
  man-in-the-middle to receive credentials from any number of users and
  then connect to another ldapi service using any of those credentials.

Or a user could provide some info/service at an ldapi socket of his own,
announce it, and collect credentials.  Others are not supposed to need
to know or trust him just for browsing his server.

  Another issue is that it's possible for a client to use a gid for groups
  that it doesn't actually belong to. This requires the existence of a
  world-writable directory in the filesystem, with its setgid bit set.

Or that a root person gives the user a directory (presumably under a
directory the user cannot write), but forgets to change the gid.

  I think the probability of this situation arising is pretty low, and
  the risk exposure is probably pretty low too. Just mentioning it for
  completeness.


  For the first issue, we can fix this by requiring that unusual,
  non-default permission bits be set on the passed descriptor. That will
  distinguish pipes explicitly created for this authentication purpose
  from pipes arbitrarily inherited from other programs.

  For the second issue, we can fix this by requiring that the client
  perform a stat of the Unix domain socket, and send the stat result
  buffer over the pipe. The server will then read this buffer and compare
  the results to its own stat of the socket. If the stat data is missing
  or doesn't match, we know that the credentials were sent by a
  man-in-the-middle.

This one gets a bit complicated.

We must use stat(socket filename) and not fstat(socket descriptor).  The
latter returns different inodes for server socket, server connection and
client connection - at least on HPUX and Linux.  That does leave a
window where the naughty server's owner can swap a hard link to his
server socket for a hard link to the server he attacks, maybe back and
forth in a loop.  A client can detect it by doing fstat(connection) as
well and compare the uid and gid of the stat results.  Unless there are
systems where the connection will have uid 0, like HPUX's socketpair()s?

We can send st_ino and st_dev (and st_rdev?).  Do not send st_uid,
st_gid and st_mode, since the admin might do chown/chmod at just the
wrong time.  It won't hurt to #define a magic number (or rather magic
octet string) and send that as well while we are at it, in case some
other application also uses descriptor passing tricks for
authentication.

One can run programs in 32-bit and 64-bit mode on the same machine, and
(at least on PowerPC) with different endianness too.  So the data should
be sent in a host-independent format.  Network byte order, maybe 64-bit
integers in these 64-bit days.  How big can an inode/device number get?

The client should to write the stat data before passing the descriptor,
so the server can read it in non-blocking mode and not worry about
clients that do not write send any stat data.  Besides, write() can
cancel the setuid bit, so it should be done before the fchmod().


  At present we haven't come up with any resolution for the 3rd issue.

Some options:

- Do nothing.

- Remove gidNumber from the DN.  Loses some functionality and causes
  version compatibility problems for programs that use the DN.

- Partial solution:  Reject named pipe descriptors if a system provides
  a way to tell them from pipe()s.  Except I don't know of a way.

- Find some file descriptor type which is not affected by a directory's
  gid (maybe not associated with the filesystem).  Likely unportable and
  more complicated, thus a poor fallback solution for the problem of
  transferring client credentials.  Also, HPUX socketpair() returns
  descriptors with uid=gid=0, so maybe disassociated from the file
  system also can mean disassociated from file properties like uids...


========================================================================

Server-side descriptor handling bugs.

These open for denial of service attacks and OS upgrade problems.  The
fixes should be invisible to clients.

Fourth issue, a HPUX client can inject a file descriptor leak into the
server by sending two descriptors instead of one:  The server-side code
with struct msghdr.msg_accrights in liblutil/getpeereid.c accepts up to
two descriptors, but only closes one and only if just one was received.

Fifth issue, the same code assumes a descriptor is sent.
If a client connects and sends nothing, one server thread will block.
And if it just sends a normal PDU, the server will throw away its first 8
octets when MSG_PEEK is not used, expecting these to be a dummy Abandon
Request the descriptor is attached to.  This can happen if a newer OS
version gains support for real peer credentials.  A new client will not
send a descriptor, this breaks when used with an old server.

However the HPUX box I'm using has an OS bug: recvmsg(,,MSG_PEEK) may
return two descriptor numbers, 0 and a garbage number.  So the potential
descriptor leak above protects the server from doing close(0).  Removing
MSG_PEEK helps, but I still see strange behavior.


Thus if removing descriptor passing is removed, clients should still
send a dummy Abandon (with msgId=abandonId=0, thus harmless), to avoid
breakage with older servers.

getpeerid.c also supports reading credentials with recvmsg() and
SCM_CREDS, but I can't see corresponding code in libldap/os-local.c?
I'm not sure how SCM_CREDS works - if the client must send them, I
assume they too can block a server thread.  A fix would be to read them
at the time when normal PDUs are read.  Set a flag which says to use
recvmsg() for the next data to read.  Also, if the client sends a
descriptor but the server checks for SCM_CREDS, will the server receive
the descriptor?  If so that must be close()d.

Comment 1 Howard Chu 2007-03-24 23:37:05 UTC
h.b.furuseth@usit.uio.no wrote:
> Users can give away file ownership on HPUX (at least the box I am using,
> I don't know HP in general).  fchown(pipe descriptor, 0, 0) lets me Bind
> as root.
> 
> There is a slight escape: fchown(regular file) resets the setuid bit, so
> the server could require a regular file with the setuid bit.
> 
> It does not reset a pipe's setuid bit.  And I think resetting the setuid
> bit is an OS feature which differs between OSes, so at the very best
> we'd need some research, and I think it'll take a tmpfile() call and 7-8
> system calls to create a regular file and descriptor just right.

POSIX requires that the setuid bit is cleared by chown if the file had 
its execute bit set. So we may be able to take advantage of this fact by 
  requiring both the execute and the setuid bit to be set.

> Note: The current server code requires (a) that the descriptor is a
> pipe, and (b) that group/other permissions are 0, so the user cannot use
> a descriptor from opening someone else's named pipe.

>   For the first issue, we can fix this by requiring that unusual,
>   non-default permission bits be set on the passed descriptor. That will
>   distinguish pipes explicitly created for this authentication purpose
>   from pipes arbitrarily inherited from other programs.
> 
>   For the second issue, we can fix this by requiring that the client
>   perform a stat of the Unix domain socket, and send the stat result
>   buffer over the pipe. The server will then read this buffer and compare
>   the results to its own stat of the socket. If the stat data is missing
>   or doesn't match, we know that the credentials were sent by a
>   man-in-the-middle.
> 
> This one gets a bit complicated.
> 
> We must use stat(socket filename) and not fstat(socket descriptor).  The
> latter returns different inodes for server socket, server connection and
> client connection - at least on HPUX and Linux.  That does leave a
> window where the naughty server's owner can swap a hard link to his
> server socket for a hard link to the server he attacks, maybe back and
> forth in a loop.  A client can detect it by doing fstat(connection) as
> well and compare the uid and gid of the stat results.  Unless there are
> systems where the connection will have uid 0, like HPUX's socketpair()s?

Comparing the st_ino would be more effective, if you're worried about 
swapping hardlinks.

>   At present we haven't come up with any resolution for the 3rd issue.
> 
> Some options:
> 
> - Do nothing.

I'm in favor of this; I don't see it as a meaningful threat. It requires 
some other security misconfiguration to already exist before it can be a 
problem.

> - Remove gidNumber from the DN.  Loses some functionality and causes
>   version compatibility problems for programs that use the DN.
> 
> - Partial solution:  Reject named pipe descriptors if a system provides
>   a way to tell them from pipe()s.  Except I don't know of a way.
> 
> - Find some file descriptor type which is not affected by a directory's
>   gid (maybe not associated with the filesystem).  Likely unportable and
>   more complicated, thus a poor fallback solution for the problem of
>   transferring client credentials.  Also, HPUX socketpair() returns
>   descriptors with uid=gid=0, so maybe disassociated from the file
>   system also can mean disassociated from file properties like uids...
> 
> 
> ========================================================================
> 
> Server-side descriptor handling bugs.
> 
> These open for denial of service attacks and OS upgrade problems.  The
> fixes should be invisible to clients.
> 
> Fourth issue, a HPUX client can inject a file descriptor leak into the
> server by sending two descriptors instead of one:  The server-side code
> with struct msghdr.msg_accrights in liblutil/getpeereid.c accepts up to
> two descriptors, but only closes one and only if just one was received.
> 
> Fifth issue, the same code assumes a descriptor is sent.
> If a client connects and sends nothing, one server thread will block.
> And if it just sends a normal PDU, the server will throw away its first 8
> octets when MSG_PEEK is not used, expecting these to be a dummy Abandon
> Request the descriptor is attached to.  This can happen if a newer OS
> version gains support for real peer credentials.  A new client will not
> send a descriptor, this breaks when used with an old server.
> 
> However the HPUX box I'm using has an OS bug: recvmsg(,,MSG_PEEK) may
> return two descriptor numbers, 0 and a garbage number.  So the potential
> descriptor leak above protects the server from doing close(0).  Removing
> MSG_PEEK helps, but I still see strange behavior.

The fix here will be to check for the credentials message on the first 
protocol message received on a sockbuf, and cache the message there. (We 
should have a sockbuf control command to enable this behavior.) Then the 
getpeereids() function will just parse the cached message if it's found.

> Thus if removing descriptor passing is removed, clients should still
> send a dummy Abandon (with msgId=abandonId=0, thus harmless), to avoid
> breakage with older servers.

Maintaining that is going to be difficult, unless we simply add the 
dummy message to all platforms across the board. I.e., if some new 
release of HPUX or AIX adds support for one of the existing peer cred 
mechanisms, autoconf isn't going to tell us that we still need to send 
the old dummy message.

> getpeerid.c also supports reading credentials with recvmsg() and
> SCM_CREDS, but I can't see corresponding code in libldap/os-local.c?
> I'm not sure how SCM_CREDS works - if the client must send them, I
> assume they too can block a server thread.  A fix would be to read them
> at the time when normal PDUs are read.  Set a flag which says to use
> recvmsg() for the next data to read.  Also, if the client sends a
> descriptor but the server checks for SCM_CREDS, will the server receive
> the descriptor?  If so that must be close()d.

-- 
   -- Howard Chu
   Chief Architect, Symas Corp.  http://www.symas.com
   Director, Highland Sun        http://highlandsun.com/hyc/
   Chief Architect, OpenLDAP     http://www.openldap.org/project/

Comment 2 Howard Chu 2007-03-24 23:46:16 UTC
moved from Incoming to Software Bugs
Comment 3 Howard Chu 2007-03-25 11:01:12 UTC
h.b.furuseth@usit.uio.no wrote:
> Server-side descriptor handling bugs.

These are now fixed in HEAD.

> These open for denial of service attacks and OS upgrade problems.  The
> fixes should be invisible to clients.
> 
> Fourth issue, a HPUX client can inject a file descriptor leak into the
> server by sending two descriptors instead of one:  The server-side code
> with struct msghdr.msg_accrights in liblutil/getpeereid.c accepts up to
> two descriptors, but only closes one and only if just one was received.

The code only accepts a single descriptor now. In fact I have no idea 
what happens if the rest of the message is ignored, but I'm assuming 
that the descriptor is discarded by the OS. Will have to play with lsof 
a bit and see what shows up.

> Fifth issue, the same code assumes a descriptor is sent.
> If a client connects and sends nothing, one server thread will block.
> And if it just sends a normal PDU, the server will throw away its first 8
> octets when MSG_PEEK is not used, expecting these to be a dummy Abandon
> Request the descriptor is attached to.  This can happen if a newer OS
> version gains support for real peer credentials.  A new client will not
> send a descriptor, this breaks when used with an old server.
> 
> However the HPUX box I'm using has an OS bug: recvmsg(,,MSG_PEEK) may
> return two descriptor numbers, 0 and a garbage number.  So the potential
> descriptor leak above protects the server from doing close(0).  Removing
> MSG_PEEK helps, but I still see strange behavior.

I've reworked the getpeereid function to save the data that it receives 
so that it can be stuffed back into the sockbuf structure and read out 
again. So whatever the first protocol message is will not be lost.

> Thus if removing descriptor passing is removed, clients should still
> send a dummy Abandon (with msgId=abandonId=0, thus harmless), to avoid
> breakage with older servers.

I don't think this is worth dealing with. Since there is a security 
problem in the old code, nobody should be installing a new client 
without also upgrading the server.

> getpeerid.c also supports reading credentials with recvmsg() and
> SCM_CREDS, but I can't see corresponding code in libldap/os-local.c?
> I'm not sure how SCM_CREDS works - if the client must send them, I
> assume they too can block a server thread.  A fix would be to read them
> at the time when normal PDUs are read.  Set a flag which says to use
> recvmsg() for the next data to read.  Also, if the client sends a
> descriptor but the server checks for SCM_CREDS, will the server receive
> the descriptor?  If so that must be close()d.

SCM_CREDS needs to be sent explicitly, the same as the other 
message-based code. It's definitely odd that there's no client-side code 
to send this message. LukeH committed that for NetBSD, we'll have to ask 
him what happened to that.
-- 
   -- Howard Chu
   Chief Architect, Symas Corp.  http://www.symas.com
   Director, Highland Sun        http://highlandsun.com/hyc/
   Chief Architect, OpenLDAP     http://www.openldap.org/project/

Comment 4 Howard Chu 2007-03-25 13:47:11 UTC
h.b.furuseth@usit.uio.no wrote:
> Full_Name: Hallvard B Furuseth
> Version: Many...
> OS: HPUX
> URL: 
> Submission from: (NULL) (129.240.202.105)
> Submitted by: hallvard


> Users can give away file ownership on HPUX (at least the box I am using,
> I don't know HP in general).  fchown(pipe descriptor, 0, 0) lets me Bind
> as root.
> 
> There is a slight escape: fchown(regular file) resets the setuid bit, so
> the server could require a regular file with the setuid bit.
> 
> It does not reset a pipe's setuid bit.  And I think resetting the setuid
> bit is an OS feature which differs between OSes, so at the very best
> we'd need some research, and I think it'll take a tmpfile() call and 7-8
> system calls to create a regular file and descriptor just right.
> 
> Note: The current server code requires (a) that the descriptor is a
> pipe, and (b) that group/other permissions are 0, so the user cannot use
> a descriptor from opening someone else's named pipe.

The solution is a lot simpler. The client now just sends its socket 
descriptor to the server. And for completeness' sake we require the 
descriptor to have its setuid bit set, along with rwx user and no access 
to anyone else.

Also, in the server, we compare the server socket's name (using 
getsockname) with the client socket's peer's name. The two of them must 
match exactly.

> Anyway, maybe this is the place to stop reading and skip to "Server-side
> descriptor handling bugs" below.  I'd already written up this ITS when I
> noticed the fchown issue, so I'm sending it all off anyway.
> 
>   The first issue is that it's possible for a user program to inherit
>   root-owned descriptors from a number of sources. cron on Linux is an
>   example of this case (although since Linux provides explicit identity
>   passing, it is not vulnerable for that example). Another more pressing
>   problem is on HPUX: the ssh daemon spawns non-interactive children with
>   root-owned pipes for their stdio descriptors. So it's possible to write
>   an ldapi client on HPUX that allows any user to authenticate as Unix root.

The sockname checks will prevent arbitrarily inherited sockets from 
being used.

>   The second issue is that the credentials can be reused indefinitely by
>   the server to talk to another ldapi server. If the directories leading
>   up to the ldapi socket are not adequately protected, this could allow a
>   man-in-the-middle to receive credentials from any number of users and
>   then connect to another ldapi service using any of those credentials.

> Or a user could provide some info/service at an ldapi socket of his own,
> announce it, and collect credentials.  Others are not supposed to need
> to know or trust him just for browsing his server.

The sockname checks will also prevent a socket from being reused with 
some other server. It still isn't foolproof - if the directory where the 
socket resides is world-writable, somebody can rename the existing 
socket and put their own in its place. But I think that's a doc issue; 
you need to protect the directories in the path up to the socket. (And 
we've already documented this fact, as I recall...)

>   Another issue is that it's possible for a client to use a gid for groups
>   that it doesn't actually belong to. This requires the existence of a
>   world-writable directory in the filesystem, with its setgid bit set.
> 
> Or that a root person gives the user a directory (presumably under a
> directory the user cannot write), but forgets to change the gid.
> 
>   I think the probability of this situation arising is pretty low, and
>   the risk exposure is probably pretty low too. Just mentioning it for
>   completeness.

Using a socket completely avoids this problem, because sockets can't be 
opened in the filesystem.

The new behavior is completely incompatible with the old, so 
SASL/EXTERNAL simply won't work across versions. Since this is a 
security issue, that seems to be unavoidable.

-- 
   -- Howard Chu
   Chief Architect, Symas Corp.  http://www.symas.com
   Director, Highland Sun        http://highlandsun.com/hyc/
   Chief Architect, OpenLDAP     http://www.openldap.org/project/

Comment 5 Howard Chu 2007-03-25 13:48:00 UTC
changed notes
changed state Open to Test
Comment 6 Hallvard Furuseth 2007-03-25 14:43:21 UTC
hyc@highlandsun.com writes:
> POSIX requires that the setuid bit is cleared by chown if the file had
> its execute bit set. So we may be able to take advantage of this fact by
>   requiring both the execute and the setuid bit to be set.

As long as we check that we are running on such a POSIX box...

But it only requires that for a _regular_ file, if "the process does not
have appropriate privileges". (Which no longer means something as simple
as "root", though I don't know what it means nowadays).
(I'm reading IEEE Std 1003.1, 2004 Edition, if that makes a difference.)

And fchown(connection,,) which you are using now does reset it on my
HPUX box.  But I assume this means the client or configure needs to
check that fchown(connection) does clear the setuid bit.

>> We must use stat(socket filename) and not fstat(socket descriptor).  The
>> latter returns different inodes for server socket, server connection and
>> client connection - at least on HPUX and Linux.  That does leave a
>> window where the naughty server's owner can swap a hard link to his
>> server socket for a hard link to the server he attacks, maybe back and
>> forth in a loop.  A client can detect it by doing fstat(connection) as
>> well and compare the uid and gid of the stat results.  Unless there are
>> systems where the connection will have uid 0, like HPUX's socketpair()s?
>
> Comparing the st_ino would be more effective, if you're worried about
> swapping hardlinks.

Except that the connection and the filename have different st_ino.

>>   At present we haven't come up with any resolution for the 3rd issue.
>>
>> Some options:
>>
>> - Do nothing.
>
> I'm in favor of this; I don't see it as a meaningful threat. It requires
> some other security misconfiguration to already exist before it can be a
> problem.

I don't know which option I favor.  But now that I think of it, it's not
necesarily misconfiguration.  Sharing access is what groups are for,
after all.  It's rare for the user not to be a member of the group, but
I've done that deliberately once or twice.

>> Thus if removing descriptor passing is removed, clients should still
>> send a dummy Abandon (with msgId=abandonId=0, thus harmless), to avoid
>> breakage with older servers.
>
> Maintaining that is going to be difficult, unless we simply add the
> dummy message to all platforms across the board.

Then I suggest we do that.  Seems simple enough.

-- 
Regards,
Hallvard

Comment 7 Hallvard Furuseth 2007-03-25 14:53:20 UTC
Howard Chu writes:
>> These open for denial of service attacks and OS upgrade problems.  The
>> fixes should be invisible to clients.
>>
>> Fourth issue, a HPUX client can inject a file descriptor leak into the
>> server by sending two descriptors instead of one:  The server-side code
>> with struct msghdr.msg_accrights in liblutil/getpeereid.c accepts up to
>> two descriptors, but only closes one and only if just one was received.
>
> The code only accepts a single descriptor now. In fact I have no idea
> what happens if the rest of the message is ignored, but I'm assuming
> that the descriptor is discarded by the OS.

I tested before posting the ITS.  It leaks.

If you read it with a recvmsg() which can accept descriptors, you get
the descriptor and must close it.  After all you just pick it up from
memory afterwards.  You don't use another OS call after recvmsg(), so
the OS doesn't know that you didn't use it.

>> Thus if removing descriptor passing is removed, clients should still
>> send a dummy Abandon (with msgId=abandonId=0, thus harmless), to avoid
>> breakage with older servers.
>
> I don't think this is worth dealing with. Since there is a security
> problem in the old code, nobody should be installing a new client
> without also upgrading the server.

If the client library comes from the same installation as the server,
yes.  But it's not unusual for users to grab the Newest and Bestest
code and use that, in particular when the admin is slower.

> SCM_CREDS needs to be sent explicitly, the same as the other
> message-based code. It's definitely odd that there's no client-side code
> to send this message. LukeH committed that for NetBSD, we'll have to ask
> him what happened to that.

Hopefully we can switch from descriptor passing to that where both is
supported, then.

-- 
Regards,
Hallvard

Comment 8 Howard Chu 2007-03-25 22:28:23 UTC
Hallvard B Furuseth wrote:
> Howard Chu writes:
>>> These open for denial of service attacks and OS upgrade problems.  The
>>> fixes should be invisible to clients.
>>>
>>> Fourth issue, a HPUX client can inject a file descriptor leak into the
>>> server by sending two descriptors instead of one:  The server-side code
>>> with struct msghdr.msg_accrights in liblutil/getpeereid.c accepts up to
>>> two descriptors, but only closes one and only if just one was received.
>> The code only accepts a single descriptor now. In fact I have no idea
>> what happens if the rest of the message is ignored, but I'm assuming
>> that the descriptor is discarded by the OS.
> 
> I tested before posting the ITS.  It leaks.

You misunderstand. I mean: the code only provides a buffer large enough 
to accept a single descriptor. If more descriptors are passed, the 
received message is truncated. In this case, the other descriptors never 
arrive in the process. The descriptors don't leak.

-- 
   -- Howard Chu
   Chief Architect, Symas Corp.  http://www.symas.com
   Director, Highland Sun        http://highlandsun.com/hyc/
   Chief Architect, OpenLDAP     http://www.openldap.org/project/

Comment 9 Howard Chu 2007-03-26 03:30:18 UTC
h.b.furuseth@usit.uio.no wrote:
> getpeerid.c also supports reading credentials with recvmsg() and
> SCM_CREDS, but I can't see corresponding code in libldap/os-local.c?
> I'm not sure how SCM_CREDS works - if the client must send them, I
> assume they too can block a server thread.  A fix would be to read them
> at the time when normal PDUs are read.  Set a flag which says to use
> recvmsg() for the next data to read.  Also, if the client sends a
> descriptor but the server checks for SCM_CREDS, will the server receive
> the descriptor?  If so that must be close()d.

Googling found some details here.

http://julipedia.blogspot.com/2006/08/localcreds-socket-credentials.html
http://julipedia.blogspot.com/2006/08/more-on-localcreds.html

In short, on NetBSD this doesn't require any action on the client side. 
But the server must enable it on the listening side, and the credentials 
will be sent with every message from the client until it's disabled 
again. So it looks like there's some missing setsockopt calls here to 
turn this on on the listening socket and turn it off again on a client 
socket after the creds have been received.
-- 
   -- Howard Chu
   Chief Architect, Symas Corp.  http://www.symas.com
   Director, Highland Sun        http://highlandsun.com/hyc/
   Chief Architect, OpenLDAP     http://www.openldap.org/project/

Comment 10 Howard Chu 2007-03-26 03:37:28 UTC
hyc@highlandsun.com wrote:
> h.b.furuseth@usit.uio.no wrote:
>> getpeerid.c also supports reading credentials with recvmsg() and
>> SCM_CREDS, but I can't see corresponding code in libldap/os-local.c?

> So it looks like there's some missing setsockopt calls here to 
> turn this on on the listening socket and turn it off again on a client 
> socket after the creds have been received.

Actually turning it on is already done in daemon.c, so it's just turning 
it off again that's missing.

-- 
   -- Howard Chu
   Chief Architect, Symas Corp.  http://www.symas.com
   Director, Highland Sun        http://highlandsun.com/hyc/
   Chief Architect, OpenLDAP     http://www.openldap.org/project/

Comment 11 Hallvard Furuseth 2007-03-26 10:47:55 UTC
We are reinventing the answer to a comp.security.unix FAQ.  Whatever we
do, we should ask them too.  (Maybe a not so well-known OpenLDAP person
should ask, in case it occurs to a c.s.u reader to check his projects...
Don't know how much paranoia makes sense:-)

Two other answers I've found:

- Solaris: One can use "doors".

- STREAMS pipes:

  SysV supports receiving file descriptors via a STREAMS pipe.  Source
  uid and gid are passed with it.  So the server creates a pipe.  The
  client opens it and sends some fd over it with ioctl I_SENDFD.  The
  server grabs it and the credentials with ioctl I_RECVFD, and closes
  the fd without using it for anything.

  For some reason the examples I've seen say the server creates a unique
  named pipe which it asks the client to open, rather than passing a
  pipe() descriptor to the client.  Also the I_SENDFD doc says the
  uid/gid which are sent are the pipe owner's uid/gid, while the
  I_RECVFD doc says the sender process' uid/gid are received.  Haven't
  tested or checked what's going on, maybe the two issues are related.

Could have a look at code for the same thing, I think e.g. at openssh
and postgresql use it.  Haven't have time to look, and might not for
some days.



I wrote:
> hyc@highlandsun.com writes:
>> POSIX requires that the setuid bit is cleared by chown if the file had
>> its execute bit set. So we may be able to take advantage of this fact by
>>   requiring both the execute and the setuid bit to be set.
>
> As long as we check that we are running on such a POSIX box...
>
> But it only requires that for a _regular_ file, if "the process does not
> have appropriate privileges". (Which no longer means something as simple
> as "root", though I don't know what it means nowadays).
> (I'm reading IEEE Std 1003.1, 2004 Edition, if that makes a difference.)
>
> And fchown(connection,,) which you are using now does reset it on my
> HPUX box.  But I assume this means the client or configure needs to
> check that fchown(connection) does clear the setuid bit.

Oops - s/client or configure/server or configure/.  And it must be
tested as non-root, since (f)chown need not remove the setuid bit if
root is doing it.

>>> We must use stat(socket filename) and not fstat(socket descriptor).  The
>>> latter returns different inodes for server socket, server connection and
>>> client connection - at least on HPUX and Linux.  That does leave a
>>> window where the naughty server's owner can swap a hard link to his
>>> server socket for a hard link to the server he attacks, maybe back and
>>> forth in a loop.  A client can detect it by doing fstat(connection) as
>>> well and compare the uid and gid of the stat results.  Unless there are
>>> systems where the connection will have uid 0, like HPUX's socketpair()s?
>>
>> Comparing the st_ino would be more effective, if you're worried about
>> swapping hardlinks.
>
> Except that the connection and the filename have different st_ino.

And it doesn't work anyway when running client and server as different
users.  Oops.

-- 
Regards,
Hallvard

Comment 12 Hallvard Furuseth 2007-03-26 13:48:32 UTC
The FreeBSD, OpenBSD and NetBSD mkfifo(2) manpages say

	The fifo's group ID is set to that of the parent directory in
	which it is created.

Similar for open().  Standard BSD feature.  Using the process gid is a
SysV feature.  I can't test it, but unless there is something special
about /tmp it looks like the BSD norm that anyone can create a named
pipe with the gid of /tmp.

-- 
Regards,
Hallvard

Comment 13 Howard Chu 2007-06-18 02:00:19 UTC
changed state Test to Closed
Comment 14 Howard Chu 2009-02-17 05:20:13 UTC
moved from Software Bugs to Archive.Software Bugs
Comment 15 OpenLDAP project 2014-08-01 21:06:47 UTC
fixed in HEAD