diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -2712,17 +2712,20 @@ #endif #if SANITIZER_INTERCEPT_GETSOCKNAME -INTERCEPTOR(int, getsockname, int sock_fd, void *addr, int *addrlen) { +INTERCEPTOR(int, getsockname, int sock_fd, void *addr, unsigned *addrlen) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, getsockname, sock_fd, addr, addrlen); - COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen)); - int addrlen_in = *addrlen; + unsigned addr_sz; + if (addrlen) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen)); + addr_sz = *addrlen; + } // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See // https://github.com/google/sanitizers/issues/321. int res = REAL(getsockname)(sock_fd, addr, addrlen); - if (res == 0) { - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addrlen_in, *addrlen)); + if (!res && addr && addrlen) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addr_sz, *addrlen)); } return res; } @@ -3227,13 +3230,17 @@ void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, getpeername, sockfd, addr, addrlen); unsigned addr_sz; - if (addrlen) addr_sz = *addrlen; + if (addrlen) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen)); + addr_sz = *addrlen; + } // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See // https://github.com/google/sanitizers/issues/321. int res = REAL(getpeername)(sockfd, addr, addrlen); - if (!res && addr && addrlen) + if (!res && addr && addrlen) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addr_sz, *addrlen)); + } return res; } #define INIT_GETPEERNAME COMMON_INTERCEPT_FUNCTION(getpeername); diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/get_sock_peer_name.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/get_sock_peer_name.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/get_sock_peer_name.cpp @@ -0,0 +1,35 @@ +// Test that ASan doesn't raise false alarm when getsockname and getpeername +// are called with addrlen=nullptr; +// +// RUN: %clangxx %s -o %t && %run %t 2>&1 + +#include +#include +#include +#include + +int main() { + const int fd = socket(AF_INET, SOCK_DGRAM, 0); + assert(fd >= 0); + + const sockaddr_in sin = { + .sin_family = AF_INET, + .sin_port = 1234, + .sin_addr = + { + .s_addr = INADDR_LOOPBACK, + }, + }; + assert(connect(fd, reinterpret_cast(&sin), sizeof(sin)) == + 0); + + errno = 0; + assert(getsockname(fd, nullptr, nullptr) == -1); + assert(errno == EFAULT); + + errno = 0; + assert(getpeername(fd, nullptr, nullptr) == -1); + assert(errno == EFAULT); + + return 0; +}