From 5680918c9e2cc8b2418a3809892532be0d10018a Mon Sep 17 00:00:00 2001 From: Eugene Syromyatnikov Date: Thu, 17 Oct 2019 15:29:50 +0200 Subject: [PATCH 70/76] evdev: decode struct input_absinfo regardless of in-kernel definitions * evdev.c (struct_input_absinfo): New typedef. (abs_ioctl): Add code argument. Add orig_sz, res_sz, sz, read_sz local variables. Decode resolution field regardless of HAVE_STRUCT_INPUT_ABSINFO_RESOLUTION. (evdev_read_ioctl, evdev_write_ioctl): Pass code to abs_ioctl. * tests/ioctl_evdev-success.c (print_input_absinfo): Update expected output. (main): Add absinfo_sz, absinfo_24, absinfo_32 local variables; add additional checks for struct input_absinfo. References: https://bugzilla.redhat.com/show_bug.cgi?id=1758201 --- evdev.c | 78 ++++++++++++++++++++++++++++++--------------- tests/ioctl_evdev-success.c | 51 ++++++++++++++++++++++++++--- 2 files changed, 99 insertions(+), 30 deletions(-) Index: strace-5.1/evdev.c =================================================================== --- strace-5.1.orig/evdev.c 2020-01-29 12:37:35.139765850 +0100 +++ strace-5.1/evdev.c 2020-01-29 12:39:10.344891943 +0100 @@ -37,6 +37,15 @@ # define SYN_MAX 0xf # endif +typedef struct { + int32_t value; + int32_t minimum; + int32_t maximum; + int32_t fuzz; + int32_t flat; + int32_t resolution; /**< Added by Linux commit v2.6.31-rc1~100^2~1 */ +} struct_input_absinfo; + /** Added by Linux commit v2.6.37-rc1~5^2~3^2~47 */ typedef struct { uint8_t flags; @@ -53,6 +62,9 @@ uint64_t codes_ptr; } struct_input_mask; +static_assert(sizeof(struct input_absinfo) <= sizeof(struct_input_absinfo), + "Unexpected struct input_absinfo size, please update " + "the decoder"); # ifdef HAVE_STRUCT_INPUT_KEYMAP_ENTRY static_assert(sizeof(struct input_keymap_entry) == sizeof(struct_input_keymap_entry), @@ -85,36 +97,50 @@ const size_t evdev_abs_size = ARRAY_SIZE(evdev_abs) - 1; static int -abs_ioctl(struct tcb *const tcp, const kernel_ulong_t arg) +abs_ioctl(struct tcb *const tcp, const unsigned int code, + const kernel_ulong_t arg) { + static const size_t orig_sz = offsetofend(struct_input_absinfo, flat); + static const size_t res_sz = offsetofend(struct_input_absinfo, + resolution); + + struct_input_absinfo absinfo; + size_t sz = _IOC_SIZE(code); + size_t read_sz = MIN(sz, sizeof(absinfo)); + + if (sz < orig_sz) + return RVAL_DECODED; + tprints(", "); - struct input_absinfo absinfo; + if (umoven_or_printaddr(tcp, arg, read_sz, &absinfo)) + return RVAL_IOCTL_DECODED; - if (!umove_or_printaddr(tcp, arg, &absinfo)) { - tprintf("{value=%u" - ", minimum=%u, ", - absinfo.value, - absinfo.minimum); - - if (!abbrev(tcp)) { - tprintf("maximum=%u" - ", fuzz=%u" - ", flat=%u", - absinfo.maximum, - absinfo.fuzz, - absinfo.flat); -# ifdef HAVE_STRUCT_INPUT_ABSINFO_RESOLUTION - tprintf(", resolution=%u", - absinfo.resolution); -# endif - } else { - tprints("..."); - } + tprintf("{value=%u" + ", minimum=%u, ", + absinfo.value, + absinfo.minimum); - tprints("}"); + if (!abbrev(tcp)) { + tprintf("maximum=%u" + ", fuzz=%u" + ", flat=%u", + absinfo.maximum, + absinfo.fuzz, + absinfo.flat); + if (sz >= res_sz) { + tprintf(", resolution=%u%s", + absinfo.resolution, + sz > res_sz ? ", ..." : ""); + } else if (sz > orig_sz) { + tprints(", ..."); + } + } else { + tprints("..."); } + tprints("}"); + return RVAL_IOCTL_DECODED; } @@ -394,7 +420,7 @@ /* multi-number fixed-length commands */ if ((_IOC_NR(code) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) - return abs_ioctl(tcp, arg); + return abs_ioctl(tcp, code, arg); /* multi-number variable-length commands */ if ((_IOC_NR(code) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) @@ -435,7 +461,7 @@ /* multi-number fixed-length commands */ if ((_IOC_NR(code) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) - return abs_ioctl(tcp, arg); + return abs_ioctl(tcp, code, arg); return 0; } Index: strace-5.1/tests/ioctl_evdev-success.c =================================================================== --- strace-5.1.orig/tests/ioctl_evdev-success.c 2020-01-27 19:35:30.929507199 +0100 +++ strace-5.1/tests/ioctl_evdev-success.c 2020-01-29 12:39:10.345891934 +0100 @@ -56,6 +56,9 @@ print_input_absinfo(long rc, const void *ptr, const void *arg) { const struct input_absinfo *absinfo = ptr; +# if VERBOSE + const uintptr_t sz = (uintptr_t) arg; +# endif if (rc < 0) { printf("%p", absinfo); @@ -67,9 +70,20 @@ PRINT_FIELD_U(", ", *absinfo, maximum); PRINT_FIELD_U(", ", *absinfo, fuzz); PRINT_FIELD_U(", ", *absinfo, flat); + if (sz > offsetofend(struct input_absinfo, flat)) { + if (sz >= 24) { # ifdef HAVE_STRUCT_INPUT_ABSINFO_RESOLUTION - PRINT_FIELD_U(", ", *absinfo, resolution); + PRINT_FIELD_U(", ", *absinfo, resolution); +# else + printf(", resolution=%u", *((int *) ptr + 5)); # endif + + if (sz > 24) + printf(", ..."); + } else { + printf(", ..."); + } + } # else printf(", ..."); # endif @@ -176,10 +190,22 @@ ", EVIOCGID, NULL) returning %lu", inject_retval); + static const void *absinfo_sz = + (const void *) (uintptr_t) sizeof(struct input_absinfo); + TAIL_ALLOC_OBJECT_CONST_PTR(struct input_id, id); TAIL_ALLOC_OBJECT_CONST_PTR(struct input_absinfo, absinfo); TAIL_ALLOC_OBJECT_CONST_PTR(int, bad_addr_slot); + struct input_absinfo *absinfo_24 = tail_alloc(MAX(sizeof(*absinfo_24), + 24)); + struct input_absinfo *absinfo_32 = tail_alloc(MAX(sizeof(*absinfo_32), + 32)); + + fill_memory(absinfo, sizeof(struct input_absinfo)); + fill_memory(absinfo_24, 24); + fill_memory(absinfo_32, 32); + # ifdef EVIOCGMTSLOTS int mtslots[] = { ABS_MT_SLOT, 1, 3 }; /* we use the second element to indicate the number of values */ @@ -236,9 +262,26 @@ const void *ptr; } a[] = { { { ARG_STR(EVIOCGID), id, print_input_id }, NULL }, - { { ARG_STR(EVIOCGABS(ABS_X)), absinfo, print_input_absinfo }, NULL }, - { { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo }, NULL }, - { { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo }, NULL }, + { { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 19), "EVIOCGABS(ABS_Y)", + absinfo, NULL }, NULL }, + { { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 20), + "EVIOCGABS(ABS_Y)", absinfo, print_input_absinfo }, + (const void *) (uintptr_t) 20 }, + { { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 21), + "EVIOCGABS(ABS_Y)", absinfo_24, print_input_absinfo }, + (const void *) (uintptr_t) 21 }, + { { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 24), + "EVIOCGABS(ABS_Y)", absinfo_24, print_input_absinfo }, + (const void *) (uintptr_t) 24 }, + { { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 32), + "EVIOCGABS(ABS_Y)", absinfo_32, print_input_absinfo }, + (const void *) (uintptr_t) 32 }, + { { ARG_STR(EVIOCGABS(ABS_X)), absinfo, print_input_absinfo }, + absinfo_sz}, + { { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo }, + absinfo_sz }, + { { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo }, + absinfo_sz }, { { ARG_STR(EVIOCGBIT(0, 0)), ev_more, print_getbit }, inject_retval * 8 <= EV_LED ? (const void *) &ev_more_str_2 Index: strace-5.1/tests-m32/ioctl_evdev-success.c =================================================================== --- strace-5.1.orig/tests-m32/ioctl_evdev-success.c 2020-01-27 19:35:30.932507172 +0100 +++ strace-5.1/tests-m32/ioctl_evdev-success.c 2020-01-29 12:39:23.992766667 +0100 @@ -56,6 +56,9 @@ print_input_absinfo(long rc, const void *ptr, const void *arg) { const struct input_absinfo *absinfo = ptr; +# if VERBOSE + const uintptr_t sz = (uintptr_t) arg; +# endif if (rc < 0) { printf("%p", absinfo); @@ -67,9 +70,20 @@ PRINT_FIELD_U(", ", *absinfo, maximum); PRINT_FIELD_U(", ", *absinfo, fuzz); PRINT_FIELD_U(", ", *absinfo, flat); + if (sz > offsetofend(struct input_absinfo, flat)) { + if (sz >= 24) { # ifdef HAVE_STRUCT_INPUT_ABSINFO_RESOLUTION - PRINT_FIELD_U(", ", *absinfo, resolution); + PRINT_FIELD_U(", ", *absinfo, resolution); +# else + printf(", resolution=%u", *((int *) ptr + 5)); # endif + + if (sz > 24) + printf(", ..."); + } else { + printf(", ..."); + } + } # else printf(", ..."); # endif @@ -176,10 +190,22 @@ ", EVIOCGID, NULL) returning %lu", inject_retval); + static const void *absinfo_sz = + (const void *) (uintptr_t) sizeof(struct input_absinfo); + TAIL_ALLOC_OBJECT_CONST_PTR(struct input_id, id); TAIL_ALLOC_OBJECT_CONST_PTR(struct input_absinfo, absinfo); TAIL_ALLOC_OBJECT_CONST_PTR(int, bad_addr_slot); + struct input_absinfo *absinfo_24 = tail_alloc(MAX(sizeof(*absinfo_24), + 24)); + struct input_absinfo *absinfo_32 = tail_alloc(MAX(sizeof(*absinfo_32), + 32)); + + fill_memory(absinfo, sizeof(struct input_absinfo)); + fill_memory(absinfo_24, 24); + fill_memory(absinfo_32, 32); + # ifdef EVIOCGMTSLOTS int mtslots[] = { ABS_MT_SLOT, 1, 3 }; /* we use the second element to indicate the number of values */ @@ -236,9 +262,26 @@ const void *ptr; } a[] = { { { ARG_STR(EVIOCGID), id, print_input_id }, NULL }, - { { ARG_STR(EVIOCGABS(ABS_X)), absinfo, print_input_absinfo }, NULL }, - { { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo }, NULL }, - { { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo }, NULL }, + { { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 19), "EVIOCGABS(ABS_Y)", + absinfo, NULL }, NULL }, + { { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 20), + "EVIOCGABS(ABS_Y)", absinfo, print_input_absinfo }, + (const void *) (uintptr_t) 20 }, + { { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 21), + "EVIOCGABS(ABS_Y)", absinfo_24, print_input_absinfo }, + (const void *) (uintptr_t) 21 }, + { { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 24), + "EVIOCGABS(ABS_Y)", absinfo_24, print_input_absinfo }, + (const void *) (uintptr_t) 24 }, + { { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 32), + "EVIOCGABS(ABS_Y)", absinfo_32, print_input_absinfo }, + (const void *) (uintptr_t) 32 }, + { { ARG_STR(EVIOCGABS(ABS_X)), absinfo, print_input_absinfo }, + absinfo_sz}, + { { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo }, + absinfo_sz }, + { { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo }, + absinfo_sz }, { { ARG_STR(EVIOCGBIT(0, 0)), ev_more, print_getbit }, inject_retval * 8 <= EV_LED ? (const void *) &ev_more_str_2 Index: strace-5.1/tests-mx32/ioctl_evdev-success.c =================================================================== --- strace-5.1.orig/tests-mx32/ioctl_evdev-success.c 2020-01-27 19:35:30.933507163 +0100 +++ strace-5.1/tests-mx32/ioctl_evdev-success.c 2020-01-29 12:39:23.994766648 +0100 @@ -56,6 +56,9 @@ print_input_absinfo(long rc, const void *ptr, const void *arg) { const struct input_absinfo *absinfo = ptr; +# if VERBOSE + const uintptr_t sz = (uintptr_t) arg; +# endif if (rc < 0) { printf("%p", absinfo); @@ -67,9 +70,20 @@ PRINT_FIELD_U(", ", *absinfo, maximum); PRINT_FIELD_U(", ", *absinfo, fuzz); PRINT_FIELD_U(", ", *absinfo, flat); + if (sz > offsetofend(struct input_absinfo, flat)) { + if (sz >= 24) { # ifdef HAVE_STRUCT_INPUT_ABSINFO_RESOLUTION - PRINT_FIELD_U(", ", *absinfo, resolution); + PRINT_FIELD_U(", ", *absinfo, resolution); +# else + printf(", resolution=%u", *((int *) ptr + 5)); # endif + + if (sz > 24) + printf(", ..."); + } else { + printf(", ..."); + } + } # else printf(", ..."); # endif @@ -176,10 +190,22 @@ ", EVIOCGID, NULL) returning %lu", inject_retval); + static const void *absinfo_sz = + (const void *) (uintptr_t) sizeof(struct input_absinfo); + TAIL_ALLOC_OBJECT_CONST_PTR(struct input_id, id); TAIL_ALLOC_OBJECT_CONST_PTR(struct input_absinfo, absinfo); TAIL_ALLOC_OBJECT_CONST_PTR(int, bad_addr_slot); + struct input_absinfo *absinfo_24 = tail_alloc(MAX(sizeof(*absinfo_24), + 24)); + struct input_absinfo *absinfo_32 = tail_alloc(MAX(sizeof(*absinfo_32), + 32)); + + fill_memory(absinfo, sizeof(struct input_absinfo)); + fill_memory(absinfo_24, 24); + fill_memory(absinfo_32, 32); + # ifdef EVIOCGMTSLOTS int mtslots[] = { ABS_MT_SLOT, 1, 3 }; /* we use the second element to indicate the number of values */ @@ -236,9 +262,26 @@ const void *ptr; } a[] = { { { ARG_STR(EVIOCGID), id, print_input_id }, NULL }, - { { ARG_STR(EVIOCGABS(ABS_X)), absinfo, print_input_absinfo }, NULL }, - { { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo }, NULL }, - { { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo }, NULL }, + { { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 19), "EVIOCGABS(ABS_Y)", + absinfo, NULL }, NULL }, + { { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 20), + "EVIOCGABS(ABS_Y)", absinfo, print_input_absinfo }, + (const void *) (uintptr_t) 20 }, + { { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 21), + "EVIOCGABS(ABS_Y)", absinfo_24, print_input_absinfo }, + (const void *) (uintptr_t) 21 }, + { { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 24), + "EVIOCGABS(ABS_Y)", absinfo_24, print_input_absinfo }, + (const void *) (uintptr_t) 24 }, + { { _IOC(_IOC_READ, 'E', 0x40 + ABS_Y, 32), + "EVIOCGABS(ABS_Y)", absinfo_32, print_input_absinfo }, + (const void *) (uintptr_t) 32 }, + { { ARG_STR(EVIOCGABS(ABS_X)), absinfo, print_input_absinfo }, + absinfo_sz}, + { { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo }, + absinfo_sz }, + { { ARG_STR(EVIOCGABS(ABS_Y)), absinfo, print_input_absinfo }, + absinfo_sz }, { { ARG_STR(EVIOCGBIT(0, 0)), ev_more, print_getbit }, inject_retval * 8 <= EV_LED ? (const void *) &ev_more_str_2