| /* |
| * Check decoding of PERF_EVENT_IOC_* commands of ioctl syscall. |
| * |
| * 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 <inttypes.h> |
| # include <stdio.h> |
| # include <string.h> |
| # include <unistd.h> |
| # include <sys/ioctl.h> |
| # include <asm/unistd.h> |
| # include <linux/perf_event.h> |
| |
| /* |
| * Workaround the bug in kernel UAPI that was fixed |
| * in Linux commit v2.6.33-rc1~48^2~288^2~19. |
| */ |
| # ifndef u64 |
| # define u64 uint64_t |
| # endif |
| |
| # define XLAT_MACROS_ONLY |
| # include "xlat/perf_ioctl_cmds.h" |
| # undef XLAT_MACROS_ONLY |
| |
| # define STR16 "0123456789abcdef" |
| |
| static long |
| sys_ioctl(kernel_long_t fd, kernel_ulong_t cmd, kernel_ulong_t arg) |
| { |
| return syscall(__NR_ioctl, fd, cmd, arg); |
| } |
| |
| int |
| main(void) |
| { |
| static const kernel_ulong_t unknown_perf_cmd = |
| (kernel_ulong_t) 0xbadc0dedfeed24edULL; |
| static const kernel_ulong_t magic = |
| (kernel_ulong_t) 0xdeadbeefbadc0dedULL; |
| static const uint64_t magic64 = 0xfacefeeddeadc0deULL; |
| static const char str[] = STR16 STR16 STR16 STR16; |
| |
| static struct { |
| unsigned int cmd; |
| const char *str; |
| } flag_iocs[] = { |
| { ARG_STR(PERF_EVENT_IOC_ENABLE) }, |
| { ARG_STR(PERF_EVENT_IOC_DISABLE) }, |
| { ARG_STR(PERF_EVENT_IOC_RESET) }, |
| }; |
| |
| 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; |
| char *const str_ptr = tail_memdup(str, sizeof(str)); |
| char *const str_efault = str_ptr + sizeof(str); |
| TAIL_ALLOC_OBJECT_CONST_PTR(struct perf_event_attr, pea_ptr); |
| |
| *u64_ptr = magic64; |
| fill_memory_ex(pea_ptr, sizeof(*pea_ptr), 0xaa, 0x55); |
| |
| /* Unknown perf commands */ |
| sys_ioctl(-1, unknown_perf_cmd, magic); |
| printf("ioctl(-1, _IOC(%s_IOC_READ|_IOC_WRITE, 0x24, %#x, %#x), " |
| "%#lx) = -1 EBADF (%m)\n", |
| _IOC_DIR((unsigned int) unknown_perf_cmd) & _IOC_NONE ? |
| "_IOC_NONE|" : "", |
| _IOC_NR((unsigned int) unknown_perf_cmd), |
| _IOC_SIZE((unsigned int) unknown_perf_cmd), |
| (unsigned long) magic); |
| |
| sys_ioctl(-1, PERF_EVENT_IOC_MODIFY_ATTRIBUTES + 1, magic); |
| printf("ioctl(-1, _IOC(_IOC_WRITE, 0x24, %#x, %#x), %#lx)" |
| " = -1 EBADF (%m)\n", |
| (unsigned int) _IOC_NR(PERF_EVENT_IOC_MODIFY_ATTRIBUTES + 1), |
| (unsigned int) _IOC_SIZE(PERF_EVENT_IOC_MODIFY_ATTRIBUTES + 1), |
| (unsigned long) magic); |
| |
| /* PERF_EVENT_IOC_{ENABLE,DISABLE,RESET} */ |
| for (unsigned i = 0; i < ARRAY_SIZE(flag_iocs); i++) { |
| ioctl(-1, flag_iocs[i].cmd, 0); |
| printf("ioctl(-1, %s, 0) = -1 EBADF (%m)\n", flag_iocs[i].str); |
| |
| ioctl(-1, flag_iocs[i].cmd, 1); |
| printf("ioctl(-1, %s, PERF_IOC_FLAG_GROUP) = -1 EBADF (%m)\n", |
| flag_iocs[i].str); |
| |
| ioctl(-1, flag_iocs[i].cmd, 2); |
| printf("ioctl(-1, %s, 0x2 /* PERF_IOC_FLAG_??? */) " |
| "= -1 EBADF (%m)\n", |
| flag_iocs[i].str); |
| |
| sys_ioctl(-1, flag_iocs[i].cmd, magic); |
| printf("ioctl(-1, %s, PERF_IOC_FLAG_GROUP|%#x) " |
| "= -1 EBADF (%m)\n", |
| flag_iocs[i].str, (unsigned int) magic & ~1U); |
| } |
| |
| /* PERF_EVENT_IOC_REFRESH */ |
| sys_ioctl(-1, PERF_EVENT_IOC_REFRESH, magic); |
| printf("ioctl(-1, PERF_EVENT_IOC_REFRESH, %d) = -1 EBADF (%m)\n", |
| (int) magic); |
| |
| /* PERF_EVENT_IOC_PERIOD */ |
| ioctl(-1, PERF_EVENT_IOC_PERIOD, NULL); |
| printf("ioctl(-1, PERF_EVENT_IOC_PERIOD, NULL) = -1 EBADF (%m)\n"); |
| |
| ioctl(-1, PERF_EVENT_IOC_PERIOD, u64_efault); |
| printf("ioctl(-1, PERF_EVENT_IOC_PERIOD, %p) = -1 EBADF (%m)\n", |
| u64_efault); |
| |
| ioctl(-1, PERF_EVENT_IOC_PERIOD, u64_ptr); |
| printf("ioctl(-1, PERF_EVENT_IOC_PERIOD, [%" PRIu64 "])" |
| " = -1 EBADF (%m)\n", |
| magic64); |
| |
| /* PERF_EVENT_IOC_SET_OUTPUT */ |
| sys_ioctl(-1, PERF_EVENT_IOC_SET_OUTPUT, magic); |
| printf("ioctl(-1, PERF_EVENT_IOC_SET_OUTPUT, %d) = -1 EBADF (%m)\n", |
| (int) magic); |
| |
| /* PERF_EVENT_IOC_SET_FILTER */ |
| ioctl(-1, PERF_EVENT_IOC_SET_FILTER, NULL); |
| printf("ioctl(-1, PERF_EVENT_IOC_SET_FILTER, NULL) = -1 EBADF (%m)\n"); |
| |
| ioctl(-1, PERF_EVENT_IOC_SET_FILTER, str_efault); |
| printf("ioctl(-1, PERF_EVENT_IOC_SET_FILTER, %p) = -1 EBADF (%m)\n", |
| str_efault); |
| |
| ioctl(-1, PERF_EVENT_IOC_SET_FILTER, str_ptr); |
| printf("ioctl(-1, PERF_EVENT_IOC_SET_FILTER, \"%.32s\"...)" |
| " = -1 EBADF (%m)\n", |
| str_ptr); |
| |
| ioctl(-1, PERF_EVENT_IOC_SET_FILTER, str_ptr + 40); |
| printf("ioctl(-1, PERF_EVENT_IOC_SET_FILTER, \"%.32s\")" |
| " = -1 EBADF (%m)\n", |
| str_ptr + 40); |
| |
| str_ptr[sizeof(str) - 1] = '0'; |
| ioctl(-1, PERF_EVENT_IOC_SET_FILTER, str_ptr + 40); |
| printf("ioctl(-1, PERF_EVENT_IOC_SET_FILTER, %p)" |
| " = -1 EBADF (%m)\n", |
| str_ptr + 40); |
| |
| /* PERF_EVENT_IOC_ID */ |
| ioctl(-1, PERF_EVENT_IOC_ID, NULL); |
| printf("ioctl(-1, PERF_EVENT_IOC_ID, NULL) = -1 EBADF (%m)\n"); |
| |
| ioctl(-1, PERF_EVENT_IOC_ID, u64_efault); |
| printf("ioctl(-1, PERF_EVENT_IOC_ID, %p) = -1 EBADF (%m)\n", |
| u64_efault); |
| |
| ioctl(-1, PERF_EVENT_IOC_ID, u64_ptr); |
| printf("ioctl(-1, PERF_EVENT_IOC_ID, %p) = -1 EBADF (%m)\n", |
| u64_ptr); |
| |
| /* PERF_EVENT_IOC_SET_BPF */ |
| sys_ioctl(-1, PERF_EVENT_IOC_SET_BPF, magic); |
| printf("ioctl(-1, PERF_EVENT_IOC_SET_BPF, %d) = -1 EBADF (%m)\n", |
| (int) magic); |
| |
| /* PERF_EVENT_IOC_PAUSE_OUTPUT */ |
| sys_ioctl(-1, PERF_EVENT_IOC_PAUSE_OUTPUT, magic); |
| printf("ioctl(-1, PERF_EVENT_IOC_PAUSE_OUTPUT, %lu) = -1 EBADF (%m)\n", |
| (unsigned long) magic); |
| |
| /* PERF_EVENT_IOC_QUERY_BPF */ |
| ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, NULL); |
| printf("ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, NULL) = -1 EBADF (%m)\n"); |
| |
| ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, u32_efault); |
| printf("ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, %p) = -1 EBADF (%m)\n", |
| u32_efault); |
| |
| u32_arr[0] = 0xbadc0ded; |
| ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, u32_arr); |
| printf("ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, {ids_len=3134983661, ...})" |
| " = -1 EBADF (%m)\n"); |
| |
| /* PERF_EVENT_IOC_MODIFY_ATTRIBUTES */ |
| ioctl(-1, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, NULL); |
| printf("ioctl(-1, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, NULL)" |
| " = -1 EBADF (%m)\n"); |
| |
| ioctl(-1, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, pea_ptr + 1); |
| printf("ioctl(-1, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, %p)" |
| " = -1 EBADF (%m)\n", |
| pea_ptr + 1); |
| |
| printf("ioctl(-1, PERF_EVENT_IOC_MODIFY_ATTRIBUTES" |
| ", {type=%#x /* PERF_TYPE_??? */" |
| ", size=%#x /* PERF_ATTR_SIZE_??? */" |
| ", config=%#llx, ...}) = -1 EBADF (%m)\n", |
| (unsigned int) pea_ptr->type, |
| (unsigned int) pea_ptr->size, |
| (unsigned long long) pea_ptr->config); |
| ioctl(-1, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, pea_ptr); |
| |
| puts("+++ exited with 0 +++"); |
| return 0; |
| } |
| |
| #else |
| |
| SKIP_MAIN_UNDEFINED("HAVE_LINUX_PERF_EVENT_H"); |
| |
| #endif |