Skip to content

Commit 3a8b28f

Browse files
authored
[rtsan] Add ioctl interceptor (#117569)
1 parent 3372303 commit 3a8b28f

File tree

2 files changed

+70
-1
lines changed

2 files changed

+70
-1
lines changed

compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,23 @@ INTERCEPTOR(int, fcntl, int filedes, int cmd, ...) {
190190
return REAL(fcntl)(filedes, cmd, arg);
191191
}
192192

193+
INTERCEPTOR(int, ioctl, int filedes, unsigned long request, ...) {
194+
__rtsan_notify_intercepted_call("ioctl");
195+
196+
// See fcntl for discussion on why we use intptr_t
197+
// And why we read from va_args on all request types
198+
using arg_type = intptr_t;
199+
static_assert(sizeof(arg_type) >= sizeof(struct ifreq *));
200+
static_assert(sizeof(arg_type) >= sizeof(int));
201+
202+
va_list args;
203+
va_start(args, request);
204+
arg_type arg = va_arg(args, arg_type);
205+
va_end(args);
206+
207+
return REAL(ioctl)(filedes, request, arg);
208+
}
209+
193210
#if SANITIZER_INTERCEPT_FCNTL64
194211
INTERCEPTOR(int, fcntl64, int filedes, int cmd, ...) {
195212
__rtsan_notify_intercepted_call("fcntl64");
@@ -801,6 +818,7 @@ void __rtsan::InitializeInterceptors() {
801818
RTSAN_MAYBE_INTERCEPT_LSEEK64;
802819
INTERCEPT_FUNCTION(dup);
803820
INTERCEPT_FUNCTION(dup2);
821+
INTERCEPT_FUNCTION(ioctl);
804822

805823
#if SANITIZER_APPLE
806824
INTERCEPT_FUNCTION(OSSpinLockLock);

compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
#if SANITIZER_APPLE
2121
#include <libkern/OSAtomic.h>
2222
#include <os/lock.h>
23-
#include <sys/types.h>
2423
#include <unistd.h>
2524
#endif
2625

@@ -38,12 +37,16 @@
3837
#endif
3938

4039
#include <fcntl.h>
40+
#include <ifaddrs.h>
41+
#include <net/if.h>
4142
#include <netdb.h>
4243
#include <poll.h>
4344
#include <pthread.h>
4445
#include <stdio.h>
46+
#include <sys/ioctl.h>
4547
#include <sys/mman.h>
4648
#include <sys/socket.h>
49+
#include <sys/types.h>
4750
#include <sys/uio.h>
4851

4952
#if _FILE_OFFSET_BITS == 64 && SANITIZER_GLIBC
@@ -373,6 +376,54 @@ class RtsanOpenedFileTest : public RtsanFileTest {
373376
int fd = -1;
374377
};
375378

379+
TEST(TestRtsanInterceptors, IoctlDiesWhenRealtime) {
380+
auto Func = []() { ioctl(0, FIONREAD); };
381+
ExpectRealtimeDeath(Func, "ioctl");
382+
ExpectNonRealtimeSurvival(Func);
383+
}
384+
385+
TEST_F(RtsanOpenedFileTest, IoctlBehavesWithOutputArg) {
386+
int arg{};
387+
ioctl(GetOpenFd(), FIONREAD, &arg);
388+
389+
EXPECT_THAT(arg, Ge(0));
390+
}
391+
392+
TEST(TestRtsanInterceptors, IoctlBehavesWithOutputPointer) {
393+
// These initial checks just see if we CAN run these tests.
394+
// If we can't (can't open a socket, or can't find an interface, just
395+
// gracefully skip.
396+
int sock = socket(AF_INET, SOCK_STREAM, 0);
397+
if (sock == -1) {
398+
perror("socket");
399+
GTEST_SKIP();
400+
}
401+
402+
struct ifaddrs *ifaddr = nullptr;
403+
if (getifaddrs(&ifaddr) == -1 || ifaddr == nullptr) {
404+
perror("getifaddrs");
405+
close(sock);
406+
GTEST_SKIP();
407+
}
408+
409+
struct ifreq ifr {};
410+
strncpy(ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ - 1);
411+
412+
int retval = ioctl(sock, SIOCGIFADDR, &ifr);
413+
if (retval == -1) {
414+
perror("ioctl");
415+
close(sock);
416+
freeifaddrs(ifaddr);
417+
FAIL();
418+
}
419+
420+
freeifaddrs(ifaddr);
421+
close(sock);
422+
423+
ASSERT_THAT(ifr.ifr_addr.sa_data, NotNull());
424+
ASSERT_THAT(ifr.ifr_addr.sa_family, Eq(AF_INET));
425+
}
426+
376427
TEST_F(RtsanOpenedFileTest, LseekDiesWhenRealtime) {
377428
auto Func = [this]() { lseek(GetOpenFd(), 0, SEEK_SET); };
378429
ExpectRealtimeDeath(Func, MAYBE_APPEND_64("lseek"));

0 commit comments

Comments
 (0)