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_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
- 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_CREDENTIALSmessage when sending to an untrusted socket and use an unprivileged user identity.
- Services authenticating with
SO_PASSCREDcould 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?