Skip to content

Commit

Permalink
[sanitizer] Allow getsockname with NULL addrlen
Browse files Browse the repository at this point in the history
This is already permitted in getpeername, and returns EFAULT
on Linux (does not crash the program).

Fixes google/sanitizers#1451.

Differential Revision: https://reviews.llvm.org/D113055
  • Loading branch information
tamird authored and zeroomega committed Nov 3, 2021
1 parent ab270e4 commit f639882
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 7 deletions.
21 changes: 14 additions & 7 deletions compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
Expand Up @@ -2712,17 +2712,20 @@ INTERCEPTOR(int, getnameinfo, void *sockaddr, unsigned salen, char *host,
#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;
}
Expand Down Expand Up @@ -3227,13 +3230,17 @@ INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) {
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);
Expand Down
@@ -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 <assert.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>

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<const sockaddr *>(&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;
}

0 comments on commit f639882

Please sign in to comment.