cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

task_fd_query_user.c (11605B)


      1// SPDX-License-Identifier: GPL-2.0
      2
      3#include <stdio.h>
      4#include <stdlib.h>
      5#include <signal.h>
      6#include <unistd.h>
      7#include <stdbool.h>
      8#include <string.h>
      9#include <stdint.h>
     10#include <fcntl.h>
     11#include <linux/bpf.h>
     12#include <sys/ioctl.h>
     13#include <sys/types.h>
     14#include <sys/stat.h>
     15#include <linux/perf_event.h>
     16
     17#include <bpf/bpf.h>
     18#include <bpf/libbpf.h>
     19#include "bpf_util.h"
     20#include "perf-sys.h"
     21#include "trace_helpers.h"
     22
     23static struct bpf_program *progs[2];
     24static struct bpf_link *links[2];
     25
     26#define CHECK_PERROR_RET(condition) ({			\
     27	int __ret = !!(condition);			\
     28	if (__ret) {					\
     29		printf("FAIL: %s:\n", __func__);	\
     30		perror("    ");			\
     31		return -1;				\
     32	}						\
     33})
     34
     35#define CHECK_AND_RET(condition) ({			\
     36	int __ret = !!(condition);			\
     37	if (__ret)					\
     38		return -1;				\
     39})
     40
     41static __u64 ptr_to_u64(void *ptr)
     42{
     43	return (__u64) (unsigned long) ptr;
     44}
     45
     46#define PMU_TYPE_FILE "/sys/bus/event_source/devices/%s/type"
     47static int bpf_find_probe_type(const char *event_type)
     48{
     49	char buf[256];
     50	int fd, ret;
     51
     52	ret = snprintf(buf, sizeof(buf), PMU_TYPE_FILE, event_type);
     53	CHECK_PERROR_RET(ret < 0 || ret >= sizeof(buf));
     54
     55	fd = open(buf, O_RDONLY);
     56	CHECK_PERROR_RET(fd < 0);
     57
     58	ret = read(fd, buf, sizeof(buf));
     59	close(fd);
     60	CHECK_PERROR_RET(ret < 0 || ret >= sizeof(buf));
     61
     62	errno = 0;
     63	ret = (int)strtol(buf, NULL, 10);
     64	CHECK_PERROR_RET(errno);
     65	return ret;
     66}
     67
     68#define PMU_RETPROBE_FILE "/sys/bus/event_source/devices/%s/format/retprobe"
     69static int bpf_get_retprobe_bit(const char *event_type)
     70{
     71	char buf[256];
     72	int fd, ret;
     73
     74	ret = snprintf(buf, sizeof(buf), PMU_RETPROBE_FILE, event_type);
     75	CHECK_PERROR_RET(ret < 0 || ret >= sizeof(buf));
     76
     77	fd = open(buf, O_RDONLY);
     78	CHECK_PERROR_RET(fd < 0);
     79
     80	ret = read(fd, buf, sizeof(buf));
     81	close(fd);
     82	CHECK_PERROR_RET(ret < 0 || ret >= sizeof(buf));
     83	CHECK_PERROR_RET(strlen(buf) < strlen("config:"));
     84
     85	errno = 0;
     86	ret = (int)strtol(buf + strlen("config:"), NULL, 10);
     87	CHECK_PERROR_RET(errno);
     88	return ret;
     89}
     90
     91static int test_debug_fs_kprobe(int link_idx, const char *fn_name,
     92				__u32 expected_fd_type)
     93{
     94	__u64 probe_offset, probe_addr;
     95	__u32 len, prog_id, fd_type;
     96	int err, event_fd;
     97	char buf[256];
     98
     99	len = sizeof(buf);
    100	event_fd = bpf_link__fd(links[link_idx]);
    101	err = bpf_task_fd_query(getpid(), event_fd, 0, buf, &len,
    102				&prog_id, &fd_type, &probe_offset,
    103				&probe_addr);
    104	if (err < 0) {
    105		printf("FAIL: %s, for event_fd idx %d, fn_name %s\n",
    106		       __func__, link_idx, fn_name);
    107		perror("    :");
    108		return -1;
    109	}
    110	if (strcmp(buf, fn_name) != 0 ||
    111	    fd_type != expected_fd_type ||
    112	    probe_offset != 0x0 || probe_addr != 0x0) {
    113		printf("FAIL: bpf_trace_event_query(event_fd[%d]):\n",
    114		       link_idx);
    115		printf("buf: %s, fd_type: %u, probe_offset: 0x%llx,"
    116		       " probe_addr: 0x%llx\n",
    117		       buf, fd_type, probe_offset, probe_addr);
    118		return -1;
    119	}
    120	return 0;
    121}
    122
    123static int test_nondebug_fs_kuprobe_common(const char *event_type,
    124	const char *name, __u64 offset, __u64 addr, bool is_return,
    125	char *buf, __u32 *buf_len, __u32 *prog_id, __u32 *fd_type,
    126	__u64 *probe_offset, __u64 *probe_addr)
    127{
    128	int is_return_bit = bpf_get_retprobe_bit(event_type);
    129	int type = bpf_find_probe_type(event_type);
    130	struct perf_event_attr attr = {};
    131	struct bpf_link *link;
    132	int fd, err = -1;
    133
    134	if (type < 0 || is_return_bit < 0) {
    135		printf("FAIL: %s incorrect type (%d) or is_return_bit (%d)\n",
    136			__func__, type, is_return_bit);
    137		return err;
    138	}
    139
    140	attr.sample_period = 1;
    141	attr.wakeup_events = 1;
    142	if (is_return)
    143		attr.config |= 1 << is_return_bit;
    144
    145	if (name) {
    146		attr.config1 = ptr_to_u64((void *)name);
    147		attr.config2 = offset;
    148	} else {
    149		attr.config1 = 0;
    150		attr.config2 = addr;
    151	}
    152	attr.size = sizeof(attr);
    153	attr.type = type;
    154
    155	fd = sys_perf_event_open(&attr, -1, 0, -1, 0);
    156	link = bpf_program__attach_perf_event(progs[0], fd);
    157	if (libbpf_get_error(link)) {
    158		printf("ERROR: bpf_program__attach_perf_event failed\n");
    159		link = NULL;
    160		close(fd);
    161		goto cleanup;
    162	}
    163
    164	CHECK_PERROR_RET(bpf_task_fd_query(getpid(), fd, 0, buf, buf_len,
    165			 prog_id, fd_type, probe_offset, probe_addr) < 0);
    166	err = 0;
    167
    168cleanup:
    169	bpf_link__destroy(link);
    170	return err;
    171}
    172
    173static int test_nondebug_fs_probe(const char *event_type, const char *name,
    174				  __u64 offset, __u64 addr, bool is_return,
    175				  __u32 expected_fd_type,
    176				  __u32 expected_ret_fd_type,
    177				  char *buf, __u32 buf_len)
    178{
    179	__u64 probe_offset, probe_addr;
    180	__u32 prog_id, fd_type;
    181	int err;
    182
    183	err = test_nondebug_fs_kuprobe_common(event_type, name,
    184					      offset, addr, is_return,
    185					      buf, &buf_len, &prog_id,
    186					      &fd_type, &probe_offset,
    187					      &probe_addr);
    188	if (err < 0) {
    189		printf("FAIL: %s, "
    190		       "for name %s, offset 0x%llx, addr 0x%llx, is_return %d\n",
    191		       __func__, name ? name : "", offset, addr, is_return);
    192		perror("    :");
    193		return -1;
    194	}
    195	if ((is_return && fd_type != expected_ret_fd_type) ||
    196	    (!is_return && fd_type != expected_fd_type)) {
    197		printf("FAIL: %s, incorrect fd_type %u\n",
    198		       __func__, fd_type);
    199		return -1;
    200	}
    201	if (name) {
    202		if (strcmp(name, buf) != 0) {
    203			printf("FAIL: %s, incorrect buf %s\n", __func__, buf);
    204			return -1;
    205		}
    206		if (probe_offset != offset) {
    207			printf("FAIL: %s, incorrect probe_offset 0x%llx\n",
    208			       __func__, probe_offset);
    209			return -1;
    210		}
    211	} else {
    212		if (buf_len != 0) {
    213			printf("FAIL: %s, incorrect buf %p\n",
    214			       __func__, buf);
    215			return -1;
    216		}
    217
    218		if (probe_addr != addr) {
    219			printf("FAIL: %s, incorrect probe_addr 0x%llx\n",
    220			       __func__, probe_addr);
    221			return -1;
    222		}
    223	}
    224	return 0;
    225}
    226
    227static int test_debug_fs_uprobe(char *binary_path, long offset, bool is_return)
    228{
    229	char buf[256], event_alias[sizeof("test_1234567890")];
    230	const char *event_type = "uprobe";
    231	struct perf_event_attr attr = {};
    232	__u64 probe_offset, probe_addr;
    233	__u32 len, prog_id, fd_type;
    234	int err = -1, res, kfd, efd;
    235	struct bpf_link *link;
    236	ssize_t bytes;
    237
    238	snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/%s_events",
    239		 event_type);
    240	kfd = open(buf, O_WRONLY | O_TRUNC, 0);
    241	CHECK_PERROR_RET(kfd < 0);
    242
    243	res = snprintf(event_alias, sizeof(event_alias), "test_%d", getpid());
    244	CHECK_PERROR_RET(res < 0 || res >= sizeof(event_alias));
    245
    246	res = snprintf(buf, sizeof(buf), "%c:%ss/%s %s:0x%lx",
    247		       is_return ? 'r' : 'p', event_type, event_alias,
    248		       binary_path, offset);
    249	CHECK_PERROR_RET(res < 0 || res >= sizeof(buf));
    250	CHECK_PERROR_RET(write(kfd, buf, strlen(buf)) < 0);
    251
    252	close(kfd);
    253	kfd = -1;
    254
    255	snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%ss/%s/id",
    256		 event_type, event_alias);
    257	efd = open(buf, O_RDONLY, 0);
    258	CHECK_PERROR_RET(efd < 0);
    259
    260	bytes = read(efd, buf, sizeof(buf));
    261	CHECK_PERROR_RET(bytes <= 0 || bytes >= sizeof(buf));
    262	close(efd);
    263	buf[bytes] = '\0';
    264
    265	attr.config = strtol(buf, NULL, 0);
    266	attr.type = PERF_TYPE_TRACEPOINT;
    267	attr.sample_period = 1;
    268	attr.wakeup_events = 1;
    269
    270	kfd = sys_perf_event_open(&attr, -1, 0, -1, PERF_FLAG_FD_CLOEXEC);
    271	link = bpf_program__attach_perf_event(progs[0], kfd);
    272	if (libbpf_get_error(link)) {
    273		printf("ERROR: bpf_program__attach_perf_event failed\n");
    274		link = NULL;
    275		close(kfd);
    276		goto cleanup;
    277	}
    278
    279	len = sizeof(buf);
    280	err = bpf_task_fd_query(getpid(), kfd, 0, buf, &len,
    281				&prog_id, &fd_type, &probe_offset,
    282				&probe_addr);
    283	if (err < 0) {
    284		printf("FAIL: %s, binary_path %s\n", __func__, binary_path);
    285		perror("    :");
    286		return -1;
    287	}
    288	if ((is_return && fd_type != BPF_FD_TYPE_URETPROBE) ||
    289	    (!is_return && fd_type != BPF_FD_TYPE_UPROBE)) {
    290		printf("FAIL: %s, incorrect fd_type %u\n", __func__,
    291		       fd_type);
    292		return -1;
    293	}
    294	if (strcmp(binary_path, buf) != 0) {
    295		printf("FAIL: %s, incorrect buf %s\n", __func__, buf);
    296		return -1;
    297	}
    298	if (probe_offset != offset) {
    299		printf("FAIL: %s, incorrect probe_offset 0x%llx\n", __func__,
    300		       probe_offset);
    301		return -1;
    302	}
    303	err = 0;
    304
    305cleanup:
    306	bpf_link__destroy(link);
    307	return err;
    308}
    309
    310int main(int argc, char **argv)
    311{
    312	extern char __executable_start;
    313	char filename[256], buf[256];
    314	__u64 uprobe_file_offset;
    315	struct bpf_program *prog;
    316	struct bpf_object *obj;
    317	int i = 0, err = -1;
    318
    319	if (load_kallsyms()) {
    320		printf("failed to process /proc/kallsyms\n");
    321		return err;
    322	}
    323
    324	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
    325	obj = bpf_object__open_file(filename, NULL);
    326	if (libbpf_get_error(obj)) {
    327		fprintf(stderr, "ERROR: opening BPF object file failed\n");
    328		return err;
    329	}
    330
    331	/* load BPF program */
    332	if (bpf_object__load(obj)) {
    333		fprintf(stderr, "ERROR: loading BPF object file failed\n");
    334		goto cleanup;
    335	}
    336
    337	bpf_object__for_each_program(prog, obj) {
    338		progs[i] = prog;
    339		links[i] = bpf_program__attach(progs[i]);
    340		if (libbpf_get_error(links[i])) {
    341			fprintf(stderr, "ERROR: bpf_program__attach failed\n");
    342			links[i] = NULL;
    343			goto cleanup;
    344		}
    345		i++;
    346	}
    347
    348	/* test two functions in the corresponding *_kern.c file */
    349	CHECK_AND_RET(test_debug_fs_kprobe(0, "blk_mq_start_request",
    350					   BPF_FD_TYPE_KPROBE));
    351	CHECK_AND_RET(test_debug_fs_kprobe(1, "blk_account_io_done",
    352					   BPF_FD_TYPE_KRETPROBE));
    353
    354	/* test nondebug fs kprobe */
    355	CHECK_AND_RET(test_nondebug_fs_probe("kprobe", "bpf_check", 0x0, 0x0,
    356					     false, BPF_FD_TYPE_KPROBE,
    357					     BPF_FD_TYPE_KRETPROBE,
    358					     buf, sizeof(buf)));
    359#ifdef __x86_64__
    360	/* set a kprobe on "bpf_check + 0x5", which is x64 specific */
    361	CHECK_AND_RET(test_nondebug_fs_probe("kprobe", "bpf_check", 0x5, 0x0,
    362					     false, BPF_FD_TYPE_KPROBE,
    363					     BPF_FD_TYPE_KRETPROBE,
    364					     buf, sizeof(buf)));
    365#endif
    366	CHECK_AND_RET(test_nondebug_fs_probe("kprobe", "bpf_check", 0x0, 0x0,
    367					     true, BPF_FD_TYPE_KPROBE,
    368					     BPF_FD_TYPE_KRETPROBE,
    369					     buf, sizeof(buf)));
    370	CHECK_AND_RET(test_nondebug_fs_probe("kprobe", NULL, 0x0,
    371					     ksym_get_addr("bpf_check"), false,
    372					     BPF_FD_TYPE_KPROBE,
    373					     BPF_FD_TYPE_KRETPROBE,
    374					     buf, sizeof(buf)));
    375	CHECK_AND_RET(test_nondebug_fs_probe("kprobe", NULL, 0x0,
    376					     ksym_get_addr("bpf_check"), false,
    377					     BPF_FD_TYPE_KPROBE,
    378					     BPF_FD_TYPE_KRETPROBE,
    379					     NULL, 0));
    380	CHECK_AND_RET(test_nondebug_fs_probe("kprobe", NULL, 0x0,
    381					     ksym_get_addr("bpf_check"), true,
    382					     BPF_FD_TYPE_KPROBE,
    383					     BPF_FD_TYPE_KRETPROBE,
    384					     buf, sizeof(buf)));
    385	CHECK_AND_RET(test_nondebug_fs_probe("kprobe", NULL, 0x0,
    386					     ksym_get_addr("bpf_check"), true,
    387					     BPF_FD_TYPE_KPROBE,
    388					     BPF_FD_TYPE_KRETPROBE,
    389					     0, 0));
    390
    391	/* test nondebug fs uprobe */
    392	/* the calculation of uprobe file offset is based on gcc 7.3.1 on x64
    393	 * and the default linker script, which defines __executable_start as
    394	 * the start of the .text section. The calculation could be different
    395	 * on different systems with different compilers. The right way is
    396	 * to parse the ELF file. We took a shortcut here.
    397	 */
    398	uprobe_file_offset = (unsigned long)main - (unsigned long)&__executable_start;
    399	CHECK_AND_RET(test_nondebug_fs_probe("uprobe", (char *)argv[0],
    400					     uprobe_file_offset, 0x0, false,
    401					     BPF_FD_TYPE_UPROBE,
    402					     BPF_FD_TYPE_URETPROBE,
    403					     buf, sizeof(buf)));
    404	CHECK_AND_RET(test_nondebug_fs_probe("uprobe", (char *)argv[0],
    405					     uprobe_file_offset, 0x0, true,
    406					     BPF_FD_TYPE_UPROBE,
    407					     BPF_FD_TYPE_URETPROBE,
    408					     buf, sizeof(buf)));
    409
    410	/* test debug fs uprobe */
    411	CHECK_AND_RET(test_debug_fs_uprobe((char *)argv[0], uprobe_file_offset,
    412					   false));
    413	CHECK_AND_RET(test_debug_fs_uprobe((char *)argv[0], uprobe_file_offset,
    414					   true));
    415	err = 0;
    416
    417cleanup:
    418	for (i--; i >= 0; i--)
    419		bpf_link__destroy(links[i]);
    420
    421	bpf_object__close(obj);
    422	return err;
    423}