[compiler-rt] f639882 - [sanitizer] Allow getsockname with NULL addrlen

Haowei Wu via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 3 10:23:14 PDT 2021


Author: Tamir Duberstein
Date: 2021-11-03T10:23:01-07:00
New Revision: f639882be8883d9dee6ed291852b721e10103a0d

URL: https://github.com/llvm/llvm-project/commit/f639882be8883d9dee6ed291852b721e10103a0d
DIFF: https://github.com/llvm/llvm-project/commit/f639882be8883d9dee6ed291852b721e10103a0d.diff

LOG: [sanitizer] Allow getsockname with NULL addrlen

This is already permitted in getpeername, and returns EFAULT
on Linux (does not crash the program).

Fixes https://github.com/google/sanitizers/issues/1451.

Differential Revision: https://reviews.llvm.org/D113055

Added: 
    compiler-rt/test/sanitizer_common/TestCases/Linux/get_sock_peer_name.cpp

Modified: 
    compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
index a6a5230cdadc3..abb38ccfa15d2 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -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;
 }
@@ -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);

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
index 0000000000000..cd916d36b4b2e
--- /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 <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;
+}


        


More information about the llvm-commits mailing list