[RFC/PATCH v1 3/3] tests: check decondig of successful evdev ioctl
Zhibin Li
08826794brmt at gmail.com
Fri Aug 10 11:12:44 UTC 2018
* tests/ioctl_evdev-success.c: New file.
(struct evdev_check): New structure.
(invoke_test_syscall, test_evdev, print_input_absinfo, print_input_id,
print_mtslots, print_getbit): New functions.
(main): Use them.
* tests/ioctl_evdev-success-v.c: New file.
* tests/ioctl_evdev-success.test: New test.
* tests/ioctl_evdev-success-v.test: Likewise.
* tests/.gitignore: Add ioctl_evdev-success and ioctl_evdev-success-v.
* tests/Makefile.am (check_PROGRAMS): Likewise.
(DECODER_TESTS): Add the two tests mentioned above.
---
tests/.gitignore | 2 +
tests/Makefile.am | 4 +
tests/ioctl_evdev-success-v.c | 2 +
tests/ioctl_evdev-success-v.test | 13 ++
tests/ioctl_evdev-success.c | 232 +++++++++++++++++++++++++++++++
tests/ioctl_evdev-success.test | 13 ++
6 files changed, 266 insertions(+)
create mode 100644 tests/ioctl_evdev-success-v.c
create mode 100755 tests/ioctl_evdev-success-v.test
create mode 100644 tests/ioctl_evdev-success.c
create mode 100755 tests/ioctl_evdev-success.test
diff --git a/tests/.gitignore b/tests/.gitignore
index 6ef4d820..3b662b60 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -143,6 +143,8 @@ ioctl_dm
ioctl_dm-v
ioctl_evdev
ioctl_evdev-v
+ioctl_evdev-success
+ioctl_evdev-success-v
ioctl_inotify
ioctl_kvm_run
ioctl_kvm_run-v
diff --git a/tests/Makefile.am b/tests/Makefile.am
index a2f39506..5bb580a6 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -118,6 +118,8 @@ check_PROGRAMS = $(PURE_EXECUTABLES) \
int_0x80 \
ioctl_dm-v \
ioctl_evdev-v \
+ ioctl_evdev-success \
+ ioctl_evdev-success-v \
ioctl_loop-nv \
ioctl_loop-v \
ioctl_nsfs \
@@ -247,6 +249,8 @@ DECODER_TESTS = \
futex.test \
getuid.test \
ioctl.test \
+ ioctl_evdev-success.test \
+ ioctl_evdev-success-v.test \
ioctl_perf-success.test \
ipc_msgbuf.test \
kern_features-fault.test \
diff --git a/tests/ioctl_evdev-success-v.c b/tests/ioctl_evdev-success-v.c
new file mode 100644
index 00000000..6fc35477
--- /dev/null
+++ b/tests/ioctl_evdev-success-v.c
@@ -0,0 +1,2 @@
+#define VERBOSE 1
+#include "ioctl_evdev-success.c"
diff --git a/tests/ioctl_evdev-success-v.test b/tests/ioctl_evdev-success-v.test
new file mode 100755
index 00000000..358d9a38
--- /dev/null
+++ b/tests/ioctl_evdev-success-v.test
@@ -0,0 +1,13 @@
+#!/bin/sh -efu
+
+. "${srcdir=.}/scno_tampering.sh"
+
+: ${IOCTL_INJECT_START=256}
+: ${IOCTL_INJECT_RETVAL=8}
+
+run_prog
+run_strace -a16 -v -e trace=ioctl \
+ -e inject=ioctl:retval="${IOCTL_INJECT_RETVAL}":when="${IOCTL_INJECT_START}+" \
+ ../ioctl_evdev-success-v "${IOCTL_INJECT_START}" "${IOCTL_INJECT_RETVAL}"> "$EXP"
+grep -v '^ioctl([012][,<]' < "$LOG" > "$OUT"
+match_diff "$OUT" "$EXP"
diff --git a/tests/ioctl_evdev-success.c b/tests/ioctl_evdev-success.c
new file mode 100644
index 00000000..8c3f8f02
--- /dev/null
+++ b/tests/ioctl_evdev-success.c
@@ -0,0 +1,232 @@
+#include "tests.h"
+
+#ifdef HAVE_LINUX_INPUT_H
+
+# include <inttypes.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <sys/ioctl.h>
+# include <linux/input.h>
+# include "print_fields.h"
+
+static const char *errstr;
+
+struct evdev_check {
+ unsigned long cmd;
+ const char *cmd_str;
+ void *arg_ptr;
+ void (*print_arg)(long rc, void *ptr, void *arg);
+};
+
+static long
+invoke_test_syscall(unsigned long cmd, void *p)
+{
+ long rc = ioctl(-1, cmd, p);
+ errstr = sprintrc(rc);
+ static char inj_errstr[4096];
+
+ snprintf(inj_errstr, sizeof(inj_errstr), "%s (INJECTED)", errstr);
+ errstr = inj_errstr;
+ return rc;
+}
+
+static void
+test_evdev(struct evdev_check *check, void *arg)
+{
+ long rc = invoke_test_syscall(check->cmd, check->arg_ptr);
+ printf("ioctl(-1, %s, ", check->cmd_str);
+ if (check->print_arg)
+ check->print_arg(rc, check->arg_ptr, arg);
+ else
+ printf("%p", check->arg_ptr);
+ printf(") = %s\n", errstr);
+}
+
+static void
+print_input_absinfo(long rc, void *ptr, void *arg)
+{
+ struct input_absinfo *absinfo = ptr;
+
+ if (rc < 0) {
+ printf("%p", absinfo);
+ return;
+ }
+ PRINT_FIELD_U("{", *absinfo, value);
+ PRINT_FIELD_U(", ", *absinfo, minimum);
+# if VERBOSE
+ PRINT_FIELD_U(", ", *absinfo, maximum);
+ PRINT_FIELD_U(", ", *absinfo, fuzz);
+ PRINT_FIELD_U(", ", *absinfo, flat);
+# ifdef HAVE_STRUCT_INPUT_ABSINFO_RESOLUTION
+ PRINT_FIELD_U(", ", *absinfo, resolution);
+# endif
+# else
+ printf(", ...");
+# endif
+ printf("}");
+}
+
+static void
+print_input_id(long rc, void *ptr, void *arg)
+{
+ struct input_id *id = ptr;
+
+ if (rc < 0) {
+ printf("%p", id);
+ return;
+ }
+ printf("{ID_BUS=%" PRIu16
+ ", ID_VENDOR=%" PRIu16
+ ", ID_PRODUCT=%" PRIu16
+ ", ID_VERSION=%" PRIu16 "}",
+ id->bustype, id->vendor, id->product, id->version);
+}
+
+# ifdef EVIOCGMTSLOTS
+static void
+print_mtslots(long rc, void *ptr, void *arg)
+{
+ int *buffer = ptr;
+ const char **str = arg;
+ int num = atoi(*(str + 1));
+
+ if (rc < 0) {
+ printf("%p", buffer);
+ return;
+ }
+
+ printf("{code=%s", *str);
+ printf(", values=[");
+ for (unsigned int i = 1; i <= (unsigned) num; i++)
+ printf("%s%s", i > 1 ? ", " : "", *(str + i + 1));
+ printf("]}");
+}
+# endif
+
+static void
+print_getbit(long rc, void *ptr, void *arg)
+{
+ const char **str = arg;
+ int num = atoi(*str);
+
+ if (rc < 0) {
+ printf("%p", ptr);
+ return;
+ }
+
+ printf("[");
+ printf("%s", *(str + 1));
+ for (unsigned int i = 2; i <= (unsigned) num; i++) {
+# if ! VERBOSE
+ if (i > 4) {
+ printf(", ...");
+ break;
+ }
+# endif
+ printf(", ");
+ printf("%s", *(str + i));
+ }
+ printf("]");
+}
+
+int
+main(int argc, char **argv)
+{
+ unsigned long num_skip;
+ long inject_retval;
+ bool locked = false;
+
+ if (argc == 1)
+ return 0;
+
+ if (argc < 3)
+ error_msg_and_fail("Usage: %s NUM_SKIP INJECT_RETVAL", argv[0]);
+
+ num_skip = strtoul(argv[1], NULL, 0);
+ inject_retval = strtol(argv[2], NULL, 0);
+
+ if (inject_retval < 0)
+ error_msg_and_fail("Expected non-negative INJECT_RETVAL, "
+ "but got %ld", inject_retval);
+
+ for (unsigned int i = 0; i < num_skip; i++) {
+ long rc = ioctl(-1, EVIOCGID, NULL);
+ printf("ioctl(-1, EVIOCGID, NULL) = %s%s\n",
+ sprintrc(rc),
+ rc == inject_retval ? " (INJECTED)" : "");
+
+ if (rc != inject_retval)
+ continue;
+
+ locked = true;
+ break;
+ }
+
+ if (!locked)
+ error_msg_and_fail("Hasn't locked on ioctl(-1"
+ ", EVIOCGID, NULL) returning %lu",
+ inject_retval);
+
+ 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);
+# ifdef EVIOCGMTSLOTS
+ int mtslots[] = { ABS_MT_SLOT, 1, 3 };
+ /* we use the second element to indicate the number of values */
+ /* mtslots_str[1] is "2" so the number of values is 2 */
+ const char *mtslots_str[] = { "ABS_MT_SLOT", "2", "1", "3" };
+
+ /* invalid flag */
+ int invalid_mtslot[] = { -1, 1 };
+ char invalid_str[4096];
+ snprintf(invalid_str, sizeof(invalid_str), "%#x /* ABS_MT_??? */", invalid_mtslot[0]);
+ const char *invalid_mtslot_str[] = { invalid_str, "1", "1" };
+# endif
+
+ /* set more than 4 bits */
+ unsigned long ev_more[] = { 1 << EV_ABS | 1 << EV_MSC | 1 << EV_LED | 1 << EV_SND | 1 << EV_PWR };
+ /* we use the first element to indicate the number of set bits */
+ /* ev_more_str[0] is "5" so the number of set bits is 5 */
+ const char *ev_more_str[] = { "5", "EV_ABS", "EV_MSC", "EV_LED", "EV_SND", "EV_PWR" };
+
+ /* set less than 4 bits */
+ unsigned long ev_less[] = { 1 << EV_ABS | 1 << EV_MSC | 1 << EV_LED };
+ const char *ev_less_str[] = { "3", "EV_ABS", "EV_MSC", "EV_LED" };
+
+ /* set zero bit */
+ unsigned long ev_zero[] = { 0x0 };
+ const char *ev_zero_str[] = { "0", " 0 " };
+
+ /* KEY_MAX is 0x2ff which is greater than retval * 8 */
+ unsigned long key[] = { 1 << KEY_1 | 1 << KEY_2, 0 };
+ const char *key_str[] = { "2", "KEY_1", "KEY_2" };
+
+ struct {
+ struct evdev_check check;
+ 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 },
+ { { ARG_STR(EVIOCGBIT(0, 0)), ev_more, print_getbit }, &ev_more_str },
+ { { ARG_STR(EVIOCGBIT(0, 0)), ev_less, print_getbit }, &ev_less_str },
+ { { ARG_STR(EVIOCGBIT(0, 0)), ev_zero, print_getbit }, &ev_zero_str },
+ { { ARG_STR(EVIOCGBIT(EV_KEY, 0)), key, print_getbit }, &key_str},
+# ifdef EVIOCGMTSLOTS
+ { { ARG_STR(EVIOCGMTSLOTS(12)), mtslots, print_mtslots }, &mtslots_str },
+ { { ARG_STR(EVIOCGMTSLOTS(8)), invalid_mtslot, print_mtslots }, &invalid_mtslot_str }
+# endif
+ };
+ for (unsigned int i = 0; i < ARRAY_SIZE(a); i++) {
+ test_evdev(&a[i].check, a[i].ptr);
+ }
+
+ puts("+++ exited with 0 +++");
+ return 0;
+}
+#else
+
+SKIP_MAIN_UNDEFINED("HAVE_LINUX_INPUT_H")
+
+#endif
diff --git a/tests/ioctl_evdev-success.test b/tests/ioctl_evdev-success.test
new file mode 100755
index 00000000..e735af91
--- /dev/null
+++ b/tests/ioctl_evdev-success.test
@@ -0,0 +1,13 @@
+#!/bin/sh -efu
+
+. "${srcdir=.}/scno_tampering.sh"
+
+: ${IOCTL_INJECT_START=256}
+: ${IOCTL_INJECT_RETVAL=8}
+
+run_prog
+run_strace -a16 -e trace=ioctl \
+ -e inject=ioctl:retval="${IOCTL_INJECT_RETVAL}":when="${IOCTL_INJECT_START}+" \
+ ../ioctl_evdev-success "${IOCTL_INJECT_START}" "${IOCTL_INJECT_RETVAL}"> "$EXP"
+grep -v '^ioctl([012][,<]' < "$LOG" > "$OUT"
+match_diff "$OUT" "$EXP"
--
2.17.1
More information about the Strace-devel
mailing list