[compiler-rt] [rtsan] Add ioctl interceptor (PR #117569)

Chris Apple via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 25 08:11:03 PST 2024


https://github.com/cjappl updated https://github.com/llvm/llvm-project/pull/117569

>From 5565fe2f18c9aa0b12c85752bbfe5b54781baa37 Mon Sep 17 00:00:00 2001
From: Chris Apple <cja-private at pm.me>
Date: Mon, 25 Nov 2024 07:23:05 -0800
Subject: [PATCH] [rtsan] Add ioctl interceptor

---
 .../lib/rtsan/rtsan_interceptors_posix.cpp    | 18 ++++++
 .../tests/rtsan_test_interceptors_posix.cpp   | 57 ++++++++++++++++++-
 2 files changed, 73 insertions(+), 2 deletions(-)

diff --git a/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp b/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp
index 91d023e858ba3b..5debf13ab9815c 100644
--- a/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp
+++ b/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp
@@ -190,6 +190,23 @@ INTERCEPTOR(int, fcntl, int filedes, int cmd, ...) {
   return REAL(fcntl)(filedes, cmd, arg);
 }
 
+INTERCEPTOR(int, ioctl, int filedes, unsigned long request, ...) {
+  __rtsan_notify_intercepted_call("ioctl");
+
+  // See fcntl for discussion on why we use intptr_t
+  // And why we read from va_args on all request types
+  using arg_type = intptr_t;
+  static_assert(sizeof(arg_type) >= sizeof(struct ifreq *));
+  static_assert(sizeof(arg_type) >= sizeof(int));
+
+  va_list args;
+  va_start(args, request);
+  arg_type arg = va_arg(args, arg_type);
+  va_end(args);
+
+  return REAL(ioctl)(filedes, request, arg);
+}
+
 #if SANITIZER_INTERCEPT_FCNTL64
 INTERCEPTOR(int, fcntl64, int filedes, int cmd, ...) {
   __rtsan_notify_intercepted_call("fcntl64");
@@ -801,6 +818,7 @@ void __rtsan::InitializeInterceptors() {
   RTSAN_MAYBE_INTERCEPT_LSEEK64;
   INTERCEPT_FUNCTION(dup);
   INTERCEPT_FUNCTION(dup2);
+  INTERCEPT_FUNCTION(ioctl);
 
 #if SANITIZER_APPLE
   INTERCEPT_FUNCTION(OSSpinLockLock);
diff --git a/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp b/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp
index bf6a3a895bd3d4..c47a3a12c65b5c 100644
--- a/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp
+++ b/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp
@@ -20,7 +20,6 @@
 #if SANITIZER_APPLE
 #include <libkern/OSAtomic.h>
 #include <os/lock.h>
-#include <sys/types.h>
 #include <unistd.h>
 #endif
 
@@ -38,12 +37,16 @@
 #endif
 
 #include <fcntl.h>
+#include <ifaddrs.h>
+#include <net/if.h>
 #include <netdb.h>
 #include <poll.h>
 #include <pthread.h>
 #include <stdio.h>
+#include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <sys/socket.h>
+#include <sys/types.h>
 #include <sys/uio.h>
 
 #if _FILE_OFFSET_BITS == 64 && SANITIZER_GLIBC
@@ -245,7 +248,6 @@ TEST(TestRtsanInterceptors, SchedYieldDiesWhenRealtime) {
 /*
     Filesystem
 */
-
 TEST_F(RtsanFileTest, OpenDiesWhenRealtime) {
   auto Func = [this]() { open(GetTemporaryFilePath(), O_RDONLY); };
   ExpectRealtimeDeath(Func, MAYBE_APPEND_64("open"));
@@ -373,6 +375,57 @@ class RtsanOpenedFileTest : public RtsanFileTest {
   int fd = -1;
 };
 
+TEST(TestRtsanInterceptors, IoctlDiesWhenRealtime) {
+  auto Func = []() { ioctl(0, FIONREAD); };
+  ExpectRealtimeDeath(Func, "ioctl");
+  ExpectNonRealtimeSurvival(Func);
+}
+
+TEST_F(RtsanOpenedFileTest, IoctlBehavesWithOutputArg) {
+  int arg{};
+  ioctl(GetOpenFd(), FIONREAD, &arg);
+
+  EXPECT_THAT(arg, Ge(0));
+}
+
+TEST(TestRtsanInterceptors, IoctlBehavesWithOutputPointer) {
+  // These initial checks just see if we CAN run these tests.
+  // If we can't (can't open a socket, or can't find an interface, just
+  // gracefully skip.
+  int sock = socket(AF_INET, SOCK_STREAM, 0);
+  if (sock == -1) {
+    perror("socket");
+    GTEST_SKIP();
+    return;
+  }
+
+  struct ifaddrs *ifaddr = nullptr;
+  if (getifaddrs(&ifaddr) == -1 || ifaddr == nullptr) {
+    perror("getifaddrs");
+    close(sock);
+    GTEST_SKIP();
+    return;
+  }
+
+  struct ifreq ifr {};
+  strncpy(ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ - 1);
+
+  int retval = ioctl(sock, SIOCGIFADDR, &ifr);
+  if (retval == -1) {
+    perror("ioctl");
+    close(sock);
+    freeifaddrs(ifaddr);
+    ASSERT_TRUE(false) << "ioctl failed";
+    return;
+  }
+
+  freeifaddrs(ifaddr);
+  close(sock);
+
+  ASSERT_THAT(ifr.ifr_addr.sa_data, NotNull());
+  ASSERT_THAT(ifr.ifr_addr.sa_family, Eq(AF_INET));
+}
+
 TEST_F(RtsanOpenedFileTest, LseekDiesWhenRealtime) {
   auto Func = [this]() { lseek(GetOpenFd(), 0, SEEK_SET); };
   ExpectRealtimeDeath(Func, MAYBE_APPEND_64("lseek"));



More information about the llvm-commits mailing list