summaryrefslogtreecommitdiff
path: root/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
diff options
context:
space:
mode:
authorSergey Matveev <earthdok@google.com>2014-02-05 19:35:24 +0000
committerSergey Matveev <earthdok@google.com>2014-02-05 19:35:24 +0000
commit9d830ae84c3e2d53b87c950a3bd9c73da2baad97 (patch)
treedc3b0b774e300319239786b6061830656b95d6e1 /lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
parentdde475a8db2c68076f7d4dd059dc8ed1b17fbc0d (diff)
[sanitizer] Implement ioctl decoding.
When an unknown ioctl is encountered, try to guess the parameter size from the request id. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@200872 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc')
-rwxr-xr-xlib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc43
1 files changed, 39 insertions, 4 deletions
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
index 22f86dca6..31b65ca06 100755
--- a/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
+++ b/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
@@ -493,11 +493,15 @@ static void ioctl_init() {
// Handle the most evil ioctls that encode argument value as part of request id.
static unsigned ioctl_request_fixup(unsigned req) {
#if SANITIZER_LINUX
- if ((req & ~0x3fff001fU) == IOCTL_EVIOCGBIT)
+ // Strip size and event number.
+ const unsigned kEviocgbitMask =
+ (IOC_SIZEMASK << IOC_SIZESHIFT) | EVIOC_EV_MAX;
+ if ((req & ~kEviocgbitMask) == IOCTL_EVIOCGBIT)
return IOCTL_EVIOCGBIT;
- if ((req & ~0x3fU) == IOCTL_EVIOCGABS)
+ // Strip absolute axis number.
+ if ((req & ~EVIOC_ABS_MAX) == IOCTL_EVIOCGABS)
return IOCTL_EVIOCGABS;
- if ((req & ~0x3fU) == IOCTL_EVIOCSABS)
+ if ((req & ~EVIOC_ABS_MAX) == IOCTL_EVIOCSABS)
return IOCTL_EVIOCSABS;
#endif
return req;
@@ -519,13 +523,44 @@ static const ioctl_desc *ioctl_table_lookup(unsigned req) {
return 0;
}
+static bool ioctl_decode(unsigned req, ioctl_desc *desc) {
+ CHECK(desc);
+ desc->req = req;
+ desc->name = "<DECODED_IOCTL>";
+ desc->size = IOC_SIZE(req);
+ // Sanity check.
+ if (desc->size > 1024) return false;
+ unsigned dir = IOC_DIR(req);
+ switch (dir) {
+ case IOC_NONE:
+ desc->type = ioctl_desc::NONE;
+ break;
+ case IOC_READ | IOC_WRITE:
+ desc->type = ioctl_desc::READWRITE;
+ break;
+ case IOC_READ:
+ desc->type = ioctl_desc::WRITE;
+ break;
+ case IOC_WRITE:
+ desc->type = ioctl_desc::READ;
+ break;
+ default:
+ return false;
+ }
+ if (desc->type != IOC_NONE && desc->size == 0) return false;
+ char id = IOC_TYPE(req);
+ // Sanity check.
+ if (!(id >= 'a' && id <= 'z') && !(id >= 'A' && id <= 'Z')) return false;
+ return true;
+}
+
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);
+ desc = ioctl_table_lookup(req & ~(IOC_SIZEMASK << IOC_SIZESHIFT));
// 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 &&