diff --git a/compiler-rt/lib/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt index d41f871ccef7..55c3ad1452d6 100644 --- a/compiler-rt/lib/sanitizer_common/CMakeLists.txt +++ b/compiler-rt/lib/sanitizer_common/CMakeLists.txt @@ -40,6 +40,7 @@ set(SANITIZER_HEADERS sanitizer_atomic.h sanitizer_common.h sanitizer_common_interceptors.inc + sanitizer_common_interceptors_ioctl.inc sanitizer_common_interceptors_scanf.inc sanitizer_common_syscalls.inc sanitizer_flags.h diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc index a5dbf0c2dad9..880644b6f861 100755 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc @@ -130,6 +130,26 @@ static void ioctl_table_fill() { _(CDROMVOLCTRL, READ, struct_cdrom_volctrl_sz); _(CDROMVOLREAD, WRITE, struct_cdrom_volctrl_sz); _(CDROM_GET_UPC, WRITE, 8); + _(EVIOCGABS, WRITE, struct_input_absinfo_sz); // fixup + _(EVIOCGBIT, WRITE, struct_input_id_sz); // fixup + _(EVIOCGEFFECTS, WRITE, sizeof(int)); + _(EVIOCGID, WRITE, struct_input_id_sz); + _(EVIOCGKEY, WRITE, 0); + _(EVIOCGKEYCODE, WRITE, sizeof(int) * 2); + _(EVIOCGLED, WRITE, 0); + _(EVIOCGNAME, WRITE, 0); + _(EVIOCGPHYS, WRITE, 0); + _(EVIOCGRAB, READ, sizeof(int)); + _(EVIOCGREP, WRITE, sizeof(int) * 2); + _(EVIOCGSND, WRITE, 0); + _(EVIOCGSW, WRITE, 0); + _(EVIOCGUNIQ, WRITE, 0); + _(EVIOCGVERSION, WRITE, sizeof(int)); + _(EVIOCRMFF, READ, sizeof(int)); + _(EVIOCSABS, READ, struct_input_absinfo_sz); // fixup + _(EVIOCSFF, READ, struct_ff_effect_sz); + _(EVIOCSKEYCODE, READ, sizeof(int) * 2); + _(EVIOCSREP, READ, sizeof(int) * 2); _(FDCLRPRM, NONE, 0); _(FDDEFPRM, READ, struct_floppy_struct_sz); _(FDFLUSH, NONE, 0); @@ -350,6 +370,9 @@ static void ioctl_table_fill() { _(EQL_GETSLAVECFG, WRITE, struct_ifreq_sz); _(EQL_SETMASTRCFG, WRITE, struct_ifreq_sz); _(EQL_SETSLAVECFG, WRITE, struct_ifreq_sz); + _(EVIOCGKEYCODE_V2, WRITE, struct_input_keymap_entry_sz); + _(EVIOCGPROP, WRITE, 0); + _(EVIOCSKEYCODE_V2, READ, struct_input_keymap_entry_sz); _(FS_IOC_GETFLAGS, WRITE, sizeof(int)); _(FS_IOC_GETVERSION, WRITE, sizeof(int)); _(FS_IOC_SETFLAGS, READ, sizeof(int)); @@ -463,7 +486,18 @@ static void ioctl_init() { ioctl_initialized = true; } -static const ioctl_desc *ioctl_lookup(unsigned req) { +// Handle the most evil ioctls that encode argument value as part of request id. +static unsigned ioctl_request_fixup(unsigned req) { + if ((req & ~0x3fff001fU) == IOCTL_EVIOCGBIT) + return IOCTL_EVIOCGBIT; + if ((req & ~0x3fU) == IOCTL_EVIOCGABS) + return IOCTL_EVIOCGABS; + if ((req & ~0x3fU) == IOCTL_EVIOCSABS) + return IOCTL_EVIOCSABS; + return req; +} + +static const ioctl_desc *ioctl_table_lookup(unsigned req) { int left = 0; int right = ioctl_table_size; while (left < right) { @@ -479,10 +513,27 @@ static const ioctl_desc *ioctl_lookup(unsigned req) { return 0; } +static const ioctl_desc *ioctl_lookup(unsigned req) { + req = ioctl_request_fixup(req); + const ioctl_desc *desc = ioctl_table_lookup(req); + if (desc) return desc; + + // Try stripping access size from the request id. + desc = ioctl_table_lookup(req & ~0x3fff0000U); + // Sanity check: requests that encode access size are either read or write and + // have size of 0 in the table. + if (desc && desc->size == 0 && + (desc->type == ioctl_desc::WRITE || desc->type == ioctl_desc::READ)) + return desc; + return 0; +} + static void ioctl_common_pre(void *ctx, const ioctl_desc *desc, int d, unsigned request, void *arg) { - if (desc->type == ioctl_desc::READ) - COMMON_INTERCEPTOR_READ_RANGE(ctx, arg, desc->size); + if (desc->type == ioctl_desc::READ) { + unsigned size = desc->size ? desc->size : IOC_SIZE(request); + COMMON_INTERCEPTOR_READ_RANGE(ctx, arg, size); + } if (desc->type != ioctl_desc::CUSTOM) return; switch (request) { @@ -499,7 +550,8 @@ static void ioctl_common_post(void *ctx, const ioctl_desc *desc, int res, int d, unsigned request, void *arg) { if (desc->type == ioctl_desc::WRITE) { // FIXME: add verbose output - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, arg, desc->size); + unsigned size = desc->size ? desc->size : IOC_SIZE(request); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, arg, size); } if (desc->type != ioctl_desc::CUSTOM) return; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc index 9264e61ba000..7ae0c65b1957 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cc @@ -46,6 +46,8 @@ #include #include #include +#include +#include #include #endif @@ -173,6 +175,7 @@ namespace __sanitizer { unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer); unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf); unsigned struct_copr_msg_sz = sizeof(struct copr_msg); + unsigned struct_ff_effect_sz = sizeof(struct ff_effect); unsigned struct_floppy_drive_params_sz = sizeof(struct floppy_drive_params); unsigned struct_floppy_drive_struct_sz = sizeof(struct floppy_drive_struct); unsigned struct_floppy_fdc_state_sz = sizeof(struct floppy_fdc_state); @@ -183,6 +186,8 @@ namespace __sanitizer { unsigned struct_format_descr_sz = sizeof(struct format_descr); unsigned struct_hd_driveid_sz = sizeof(struct hd_driveid); unsigned struct_hd_geometry_sz = sizeof(struct hd_geometry); + unsigned struct_input_absinfo_sz = sizeof(struct input_absinfo); + unsigned struct_input_id_sz = sizeof(struct input_id); unsigned struct_midi_info_sz = sizeof(struct midi_info); unsigned struct_mtget_sz = sizeof(struct mtget); unsigned struct_mtop_sz = sizeof(struct mtop); @@ -199,15 +204,16 @@ namespace __sanitizer { #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID + unsigned mpu_command_rec_sz = sizeof(mpu_command_rec); unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info); unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct); unsigned struct_cyclades_monitor_sz = sizeof(struct cyclades_monitor); + unsigned struct_input_keymap_entry_sz = sizeof(struct input_keymap_entry); unsigned struct_ipx_config_data_sz = sizeof(struct ipx_config_data); unsigned struct_kbdiacrs_sz = sizeof(struct kbdiacrs); unsigned struct_kbentry_sz = sizeof(struct kbentry); unsigned struct_kbkeycode_sz = sizeof(struct kbkeycode); unsigned struct_kbsentry_sz = sizeof(struct kbsentry); - unsigned mpu_command_rec_sz = sizeof(mpu_command_rec); unsigned struct_mtconfiginfo_sz = sizeof(struct mtconfiginfo); unsigned struct_nr_parms_struct_sz = sizeof(struct nr_parms_struct); unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats); @@ -275,6 +281,26 @@ namespace __sanitizer { unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; #endif #if SANITIZER_LINUX + unsigned IOCTL_EVIOCGABS = EVIOCGABS(0); + unsigned IOCTL_EVIOCGBIT = EVIOCGBIT(0, 0); + unsigned IOCTL_EVIOCGEFFECTS = EVIOCGEFFECTS; + unsigned IOCTL_EVIOCGID = EVIOCGID; + unsigned IOCTL_EVIOCGKEY = EVIOCGKEY(0); + unsigned IOCTL_EVIOCGKEYCODE = EVIOCGKEYCODE; + unsigned IOCTL_EVIOCGLED = EVIOCGLED(0); + unsigned IOCTL_EVIOCGNAME = EVIOCGNAME(0); + unsigned IOCTL_EVIOCGPHYS = EVIOCGPHYS(0); + unsigned IOCTL_EVIOCGRAB = EVIOCGRAB; + unsigned IOCTL_EVIOCGREP = EVIOCGREP; + unsigned IOCTL_EVIOCGSND = EVIOCGSND(0); + unsigned IOCTL_EVIOCGSW = EVIOCGSW(0); + unsigned IOCTL_EVIOCGUNIQ = EVIOCGUNIQ(0); + unsigned IOCTL_EVIOCGVERSION = EVIOCGVERSION; + unsigned IOCTL_EVIOCRMFF = EVIOCRMFF; + unsigned IOCTL_EVIOCSABS = EVIOCSABS(0); + unsigned IOCTL_EVIOCSFF = EVIOCSFF; + unsigned IOCTL_EVIOCSKEYCODE = EVIOCSKEYCODE; + unsigned IOCTL_EVIOCSREP = EVIOCSREP; unsigned IOCTL_BLKFLSBUF = BLKFLSBUF; unsigned IOCTL_BLKGETSIZE = BLKGETSIZE; unsigned IOCTL_BLKRAGET = BLKRAGET; @@ -530,6 +556,9 @@ namespace __sanitizer { unsigned IOCTL_EQL_GETSLAVECFG = EQL_GETSLAVECFG; unsigned IOCTL_EQL_SETMASTRCFG = EQL_SETMASTRCFG; unsigned IOCTL_EQL_SETSLAVECFG = EQL_SETSLAVECFG; + unsigned IOCTL_EVIOCGKEYCODE_V2 = EVIOCGKEYCODE_V2; + unsigned IOCTL_EVIOCGPROP = EVIOCGPROP(0); + unsigned IOCTL_EVIOCSKEYCODE_V2 = EVIOCSKEYCODE_V2; unsigned IOCTL_FS_IOC_GETFLAGS = FS_IOC_GETFLAGS; unsigned IOCTL_FS_IOC_GETVERSION = FS_IOC_GETVERSION; unsigned IOCTL_FS_IOC_SETFLAGS = FS_IOC_SETFLAGS; @@ -635,6 +664,8 @@ CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); + +COMPILER_CHECK(IOC_SIZE(0x12345678) == _IOC_SIZE(0x12345678)); #endif CHECK_TYPE_SIZE(addrinfo); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h index 077badf7b982..cf55d36f9745 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -160,6 +160,8 @@ namespace __sanitizer { }; #endif +#define IOC_SIZE(nr) (((nr) >> 16) & 0x3fff) + extern unsigned struct_arpreq_sz; extern unsigned struct_ifreq_sz; extern unsigned struct_termios_sz; @@ -177,6 +179,7 @@ namespace __sanitizer { extern unsigned struct_copr_buffer_sz; extern unsigned struct_copr_debug_buf_sz; extern unsigned struct_copr_msg_sz; + extern unsigned struct_ff_effect_sz; extern unsigned struct_floppy_drive_params_sz; extern unsigned struct_floppy_drive_struct_sz; extern unsigned struct_floppy_fdc_state_sz; @@ -187,6 +190,8 @@ namespace __sanitizer { extern unsigned struct_format_descr_sz; extern unsigned struct_hd_driveid_sz; extern unsigned struct_hd_geometry_sz; + extern unsigned struct_input_absinfo_sz; + extern unsigned struct_input_id_sz; extern unsigned struct_midi_info_sz; extern unsigned struct_mtget_sz; extern unsigned struct_mtop_sz; @@ -203,15 +208,16 @@ namespace __sanitizer { #endif #if SANITIZER_LINUX && !SANITIZER_ANDROID + extern unsigned mpu_command_rec_sz; extern unsigned struct_audio_buf_info_sz; extern unsigned struct_ax25_parms_struct_sz; extern unsigned struct_cyclades_monitor_sz; + extern unsigned struct_input_keymap_entry_sz; extern unsigned struct_ipx_config_data_sz; extern unsigned struct_kbdiacrs_sz; extern unsigned struct_kbentry_sz; extern unsigned struct_kbkeycode_sz; extern unsigned struct_kbsentry_sz; - extern unsigned mpu_command_rec_sz; extern unsigned struct_mtconfiginfo_sz; extern unsigned struct_nr_parms_struct_sz; extern unsigned struct_ppp_stats_sz; @@ -279,6 +285,26 @@ namespace __sanitizer { extern unsigned IOCTL_SIOCGETVIFCNT; #endif #if SANITIZER_LINUX + extern unsigned IOCTL_EVIOCGABS; + extern unsigned IOCTL_EVIOCGBIT; + extern unsigned IOCTL_EVIOCGEFFECTS; + extern unsigned IOCTL_EVIOCGID; + extern unsigned IOCTL_EVIOCGKEY; + extern unsigned IOCTL_EVIOCGKEYCODE; + extern unsigned IOCTL_EVIOCGLED; + extern unsigned IOCTL_EVIOCGNAME; + extern unsigned IOCTL_EVIOCGPHYS; + extern unsigned IOCTL_EVIOCGRAB; + extern unsigned IOCTL_EVIOCGREP; + extern unsigned IOCTL_EVIOCGSND; + extern unsigned IOCTL_EVIOCGSW; + extern unsigned IOCTL_EVIOCGUNIQ; + extern unsigned IOCTL_EVIOCGVERSION; + extern unsigned IOCTL_EVIOCRMFF; + extern unsigned IOCTL_EVIOCSABS; + extern unsigned IOCTL_EVIOCSFF; + extern unsigned IOCTL_EVIOCSKEYCODE; + extern unsigned IOCTL_EVIOCSREP; extern unsigned IOCTL_BLKFLSBUF; extern unsigned IOCTL_BLKGETSIZE; extern unsigned IOCTL_BLKRAGET; @@ -534,6 +560,9 @@ namespace __sanitizer { extern unsigned IOCTL_EQL_GETSLAVECFG; extern unsigned IOCTL_EQL_SETMASTRCFG; extern unsigned IOCTL_EQL_SETSLAVECFG; + extern unsigned IOCTL_EVIOCGKEYCODE_V2; + extern unsigned IOCTL_EVIOCGPROP; + extern unsigned IOCTL_EVIOCSKEYCODE_V2; extern unsigned IOCTL_FS_IOC_GETFLAGS; extern unsigned IOCTL_FS_IOC_GETVERSION; extern unsigned IOCTL_FS_IOC_SETFLAGS; diff --git a/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt index 9e820e5ddde8..8f871a508dc8 100644 --- a/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt +++ b/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt @@ -5,6 +5,7 @@ set(SANITIZER_UNITTESTS sanitizer_atomic_test.cc sanitizer_common_test.cc sanitizer_flags_test.cc + sanitizer_ioctl_test.cc sanitizer_libc_test.cc sanitizer_linux_test.cc sanitizer_list_test.cc @@ -31,7 +32,8 @@ set(SANITIZER_TEST_CFLAGS_COMMON -I${COMPILER_RT_SOURCE_DIR}/lib/sanitizer_common -DGTEST_HAS_RTTI=0 -O2 -g -fno-rtti - -Wall -Werror -Werror=sign-compare) + -Wall -Werror -Werror=sign-compare + -Wno-unused-function) set(SANITIZER_TEST_LINK_FLAGS_COMMON -lstdc++ -ldl) diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc b/compiler-rt/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc new file mode 100644 index 000000000000..1ecd6cb96b75 --- /dev/null +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_ioctl_test.cc @@ -0,0 +1,72 @@ +//===-- sanitizer_ioctl_test.cc -------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Tests for ioctl interceptor implementation in sanitizer_common. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" +#if SANITIZER_LINUX + +#include +#include + +#include "interception/interception.h" +#include "sanitizer_test_utils.h" +#include "sanitizer_common/sanitizer_platform_limits_posix.h" +#include "sanitizer_common/sanitizer_common.h" +#include "gtest/gtest.h" + + +using namespace __sanitizer; + +#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, sz) \ + do { \ + (void) ctx; \ + (void) ptr; \ + (void) sz; \ + } while (0) +#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sz) \ + do { \ + (void) ctx; \ + (void) ptr; \ + (void) sz; \ + } while (0) + +#include "sanitizer_common/sanitizer_common_interceptors_ioctl.inc" + +static struct IoctlInit { + IoctlInit() { ioctl_init(); } +} ioctl_static_initializer; + +TEST(SanitizerIoctl, Fixup) { + EXPECT_EQ((unsigned)FIONBIO, ioctl_request_fixup(FIONBIO)); + + EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(0, 16))); + EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(1, 16))); + EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(1, 17))); + EXPECT_EQ(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(31, 16))); + EXPECT_NE(EVIOCGBIT(0, 0), ioctl_request_fixup(EVIOCGBIT(32, 16))); + + EXPECT_EQ(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(0))); + EXPECT_EQ(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(5))); + EXPECT_EQ(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(63))); + EXPECT_NE(EVIOCGABS(0), ioctl_request_fixup(EVIOCGABS(64))); + + EXPECT_EQ(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(0))); + EXPECT_EQ(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(5))); + EXPECT_EQ(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(63))); + EXPECT_NE(EVIOCSABS(0), ioctl_request_fixup(EVIOCSABS(64))); + + const ioctl_desc *desc = ioctl_lookup(EVIOCGKEY(16)); + EXPECT_NE((void *)0, desc); + EXPECT_EQ(EVIOCGKEY(0), desc->req); +} + +#endif // SANITIZER_LINUX