[sanitizer] Handle EVIOxxxx ioctls.

llvm-svn: 184405
This commit is contained in:
Evgeniy Stepanov 2013-06-20 09:19:28 +00:00
parent 686c229b03
commit fbea5b95c6
6 changed files with 194 additions and 7 deletions

View File

@ -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

View File

@ -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;

View File

@ -46,6 +46,8 @@
#include <linux/fd.h>
#include <linux/fs.h>
#include <linux/hdreg.h>
#include <linux/input.h>
#include <linux/ioctl.h>
#include <linux/soundcard.h>
#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);

View File

@ -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;

View File

@ -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)

View File

@ -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 <linux/input.h>
#include <vector>
#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