From 92cd86f01e90617982fd8ce11f803bfa06b5d113 Mon Sep 17 00:00:00 2001 From: aszlig Date: Wed, 8 Jul 2020 06:38:10 +0200 Subject: [PATCH] darwin: Use LOCAL_PEERCRED instead of SO_PEERCRED While LOCAL_PEERCRED is somewhat similar to SO_PEERCRED, we unfortunately don't have access to the PID of the remote peer. This is something we actually need to properly distinguish the remote peer by giving it an IP address with the PID encoded, otherwise we'd end up with duplicate IPs. On the other hand, using random IP addresses also is not a very good solution here, since we actually *want* to have the same IP for the same process. Right now the UID and GID fields are not used at all on Darwin, but we really need to figure out a way to properly assign fake IP addresses. Signed-off-by: aszlig --- src/sockaddr.cc | 25 ++++++++++++++++++++----- src/sockaddr.hh | 8 ++++++++ src/socket.cc | 22 ++++++++++++++++++++++ 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/src/sockaddr.cc b/src/sockaddr.cc index 95223f0..969807b 100644 --- a/src/sockaddr.cc +++ b/src/sockaddr.cc @@ -107,11 +107,23 @@ bool SockAddr::set_host(const SockAddr &other) } } -bool SockAddr::set_host(const ucred &peercred) +#if defined(SO_PEERCRED) +#define PEERCRED_TYPE ucred +#define PEERCRED_PID peercred.pid +#define PEERCRED_GID peercred.gid +#define PEERCRED_UID peercred.uid +#else +#define PEERCRED_TYPE xucred +#define PEERCRED_PID peercred.cr_pid +#define PEERCRED_GID peercred.cr_gid +#define PEERCRED_UID peercred.cr_uid +#endif + +bool SockAddr::set_host(const PEERCRED_TYPE &peercred) { if (this->ss_family == AF_INET) { this->cast4()->sin_addr.s_addr = - htonl(static_cast(peercred.pid)); + htonl(static_cast(PEERCRED_PID)); return true; } else if (this->ss_family == AF_INET6) { sockaddr_in6 *addr = this->cast6(); @@ -119,12 +131,15 @@ bool SockAddr::set_host(const ucred &peercred) addr->sin6_addr.s6_addr[1] = 0x80; addr->sin6_addr.s6_addr[2] = 0x00; addr->sin6_addr.s6_addr[3] = 0x00; - uint32_t part = htonl(static_cast(peercred.uid)); + uint32_t part = htonl(static_cast(PEERCRED_UID)); memcpy(addr->sin6_addr.s6_addr + 4, &part, 4); - part = htonl(static_cast(peercred.gid)); +// XXX! +#if defined(SO_PEERCRED) + part = htonl(static_cast(PEERCRED_GID)); memcpy(addr->sin6_addr.s6_addr + 8, &part, 4); - part = htonl(static_cast(peercred.pid)); + part = htonl(static_cast(PEERCRED_PID)); memcpy(addr->sin6_addr.s6_addr + 12, &part, 4); +#endif return true; } return false; diff --git a/src/sockaddr.hh b/src/sockaddr.hh index 64a65e0..0333b6a 100644 --- a/src/sockaddr.hh +++ b/src/sockaddr.hh @@ -6,6 +6,10 @@ #include #include +#if defined(__APPLE__) +#include +#endif + struct SockAddr : public sockaddr_storage { SockAddr(); @@ -20,7 +24,11 @@ struct SockAddr : public sockaddr_storage std::optional get_host(void) const; bool set_host(const std::string&); +#if defined(SO_PEERCRED) bool set_host(const ucred&); +#else + bool set_host(const xucred&); +#endif bool set_host(const SockAddr&); bool set_random_host(void); diff --git a/src/socket.cc b/src/socket.cc index 5dcaa67..be13edb 100644 --- a/src/socket.cc +++ b/src/socket.cc @@ -4,6 +4,10 @@ #include #include +#if defined(__APPLE__) +#include +#endif + #include "socket.hh" #include "realcalls.hh" #include "logging.hh" @@ -265,10 +269,19 @@ bool Socket::create_binding(const SockAddr &addr) if (!local.set_host(addr)) return false; } else { +#if defined(SO_PEERCRED) ucred local_cred; local_cred.uid = getuid(); local_cred.gid = getgid(); local_cred.pid = getpid(); +#else + xucred local_cred; + local_cred.cr_uid = getuid(); + /* XXX! + local_cred.cr_gid = getgid(); + local_cred.cr_pid = getpid(); + */ +#endif // Our local sockaddr, which we only need if we didn't have a // bind() before our connect. @@ -453,11 +466,20 @@ int Socket::accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) } else { // We use SO_PEERCRED to get uid, gid and pid in order to generate // unique IP addresses. +#if defined(SO_PEERCRED) ucred peercred; socklen_t len = sizeof peercred; if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &peercred, &len) == -1) return -1; +#else + xucred peercred; + socklen_t len = sizeof peercred; + + if (getsockopt(sockfd, SOL_LOCAL, LOCAL_PEERCRED, &peercred, + &len) == -1) + return -1; +#endif if (!peer.set_host(peercred)) { errno = EINVAL;