2

UNIX sockets often have a mechanism to authenticate their peer processes. However, there is a requirement for care in order to avoid confused deputy attacks.

Linux, for example, has two ways to pass credentials over a UNIX socket: SO_PASSCRED and SO_PEERCRED. SO_PEERCRED is only supported for stream sockets or socketpair(2), and the user identity is derived from the effective credentials and fixed when the socket is connected or the socket pair created. SO_PASSCRED, on the other hand, is generated again for each message, and by default, is derived from the real credentials. FreeBSD has similar APIs, though the details differ.

In general, sockets used by a process are either created by that process, inherited from the parent or passed through a UNIX socket. If the socket is created by the process, the process can clearly take responsibility for using the socket securely. For inherited and passed sockets, SO_PEERCRED doesn't cause special issues, because the credentials are derived from the creator.

SO_PASSCRED has the problem that processes calling write(2) can unintendedly pass their credentials through a socket they didn't create or connect, and often messages written can be controlled by the creator. In the case of an inherited socket, a setuid/setgid process would have different credentials to their parent, but as the passed credentials are based on the real credentials of the process, the parent should not be able to use the credentials of the elevated process.

On the other hand, if a UNIX socket is passed through a UNIX socket, the recipient could have elevated real credentials. In this case, a daemon receiving a socket could be tricked to write(2) to it, even though the daemon does not know the peer.

What precautions can be done to avoid the abuse of the credentials? Is it possible to make passing untrusted sockets to daemons secure?

  • Services should use SO_PEERCRED when possible.
  • If the daemon does not intend to receive a socket, it should fstat(2) the received file descriptor and check the type.
  • Privileged daemons could explicitly add an SCM_CREDENTIALS message when sending to an untrusted socket and use an unprivileged user identity.
  • Services authenticating with SO_PASSCRED could make sure that a simple write(2) is not a valid use of credentials. For example, an ancillary message could be required, or a multi-roundtrip protocol that is unlikely to be followed by a confused deputy.

How have commonly used daemons solved this?

  • tl;dr; the problem is that the uid and gid passed via SCM_CREDENTIALS are by default the real uid and gid of the process calling write(2), but someone may mistakenly assume they're always the effective uid and gid. That's a point worth re-hashing, but an example of that in actual software would be great ;-) – mosvy Dec 7 '19 at 15:51
  • @mosvy passing real credentials instead of effective solves the case of setuid/setgid processes, but not daemons writing to file descriptors passed through a socket. For daemons, the real and effective ids are usually the same. – Juho Östman Dec 7 '19 at 16:38
  • Sorry if I'm not following you, but your scenario seems to assume that either a) it's possible to combine in the same message privileged credentials with data controlled by a non-privileged process (or vice-versa), or b) some process is using the credentials to "validate" the other end of the socket in general, rather than the exact message they're attached to. – mosvy Dec 8 '19 at 9:32
  • For a) I'm absolutely not able to reproduce it in Linux: even if multiple send/writes on a stream socket may result in a single recvmsg/read, that will not happen when the receiving socket has SO_PASSCRED turned on and the writes are done by processes with different credentials. For b) is there an example of that mistake in the wild? – mosvy Dec 8 '19 at 9:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.