/* * Check decoding of successful PERF_EVENT_IOC_{ID,QUERY_BPF} ioctls. * * Copyright (c) 2018 The strace developers. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "tests.h" #ifdef HAVE_LINUX_PERF_EVENT_H # include # include # include # include # include # include # include # ifndef PERF_EVENT_IOC_ID # define PERF_EVENT_IOC_ID _IOR('$', 7, void *) # endif # ifndef PERF_EVENT_IOC_QUERY_BPF # define PERF_EVENT_IOC_QUERY_BPF _IOWR('$', 10, void *) struct perf_event_query_bpf { uint32_t ids_len; uint32_t prog_cnt; uint32_t ids[0]; }; # endif int main(int argc, char **argv) { static const uint64_t magic64 = 0xfacefeeddeadc0deULL; TAIL_ALLOC_OBJECT_CONST_PTR(uint64_t, u64_ptr); uint64_t *const u64_efault = u64_ptr + 1; uint32_t *const u32_arr = tail_alloc(sizeof(uint32_t) * 4); uint32_t *const u32_efault = u32_arr + 4; unsigned long num_skip; long inject_retval; bool locked = false; *u64_ptr = magic64; 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 long i = 0; i < num_skip; i++) { long ret = ioctl(-1, PERF_EVENT_IOC_ID, NULL); printf("ioctl(-1, PERF_EVENT_IOC_ID, NULL) = %s%s\n", sprintrc(ret), ret == inject_retval ? " (INJECTED)" : ""); if (ret != inject_retval) continue; locked = true; break; } if (!locked) error_msg_and_fail("Hasn't locked on ioctl(-1" ", PERF_EVENT_IOC_ID, NULL) returning %lu", inject_retval); /* PERF_EVENT_IOC_ID */ assert(ioctl(-1, PERF_EVENT_IOC_ID, NULL) == inject_retval); printf("ioctl(-1, PERF_EVENT_IOC_ID, NULL) = %ld (INJECTED)\n", inject_retval); assert(ioctl(-1, PERF_EVENT_IOC_ID, u64_efault) == inject_retval); printf("ioctl(-1, PERF_EVENT_IOC_ID, %p) = %ld (INJECTED)\n", u64_efault, inject_retval); assert(ioctl(-1, PERF_EVENT_IOC_ID, u64_ptr) == inject_retval); printf("ioctl(-1, PERF_EVENT_IOC_ID, [%" PRIu64 "]) = %ld (INJECTED)\n", magic64, inject_retval); /* PERF_EVENT_IOC_QUERY_BPF */ assert(ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, NULL) == inject_retval); printf("ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, NULL) = %ld (INJECTED)\n", inject_retval); assert(ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, u32_efault) == inject_retval); printf("ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, %p) = %ld (INJECTED)\n", u32_efault, inject_retval); u32_arr[3] = 0xdeadbeef; assert(ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, u32_arr + 3) == inject_retval); printf("ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, {ids_len=3735928559, ...}) " "= %ld (INJECTED)\n", inject_retval); u32_arr[2] = 0xdecaffed; assert(ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, u32_arr + 2) == inject_retval); printf("ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, {ids_len=3737845741" ", prog_cnt=3735928559, ids=%p})" " = %ld (INJECTED)\n", u32_efault, inject_retval); u32_arr[0] = 0xbadc0ded; u32_arr[1] = 5; assert(ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, u32_arr) == inject_retval); printf("ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, {ids_len=3134983661" ", prog_cnt=5, ids=[3737845741, 3735928559, ... /* %p */]})" " = %ld (INJECTED)\n", u32_efault, inject_retval); u32_arr[1] = 2; assert(ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, u32_arr) == inject_retval); printf("ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, {ids_len=3134983661" ", prog_cnt=2, ids=[3737845741, 3735928559]})" " = %ld (INJECTED)\n", inject_retval); puts("+++ exited with 0 +++"); return 0; } #else SKIP_MAIN_UNDEFINED("HAVE_LINUX_PERF_EVENT_H"); #endif