mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

Modify several functions in tools/bpf/bpftool/common.c to allow specification of requested access for file descriptors, such as read-only access. Update bpftool to request only read access for maps when write access is not required. This fixes errors when reading from maps that are protected from modification via security_bpf_map. Signed-off-by: Slava Imameev <slava.imameev@crowdstrike.com> Reviewed-by: Quentin Monnet <qmo@kernel.org> Link: https://lore.kernel.org/r/20250620151812.13952-1-slava.imameev@crowdstrike.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
227 lines
5 KiB
C
227 lines
5 KiB
C
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
|
/* Copyright (C) 2018 Netronome Systems, Inc. */
|
|
/* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of version 2 of the GNU General Public
|
|
* License as published by the Free Software Foundation.
|
|
*/
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <bpf/libbpf.h>
|
|
#include <poll.h>
|
|
#include <signal.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include <linux/bpf.h>
|
|
#include <linux/perf_event.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/syscall.h>
|
|
|
|
#include <bpf/bpf.h>
|
|
|
|
#include "main.h"
|
|
|
|
#define MMAP_PAGE_CNT 16
|
|
|
|
static volatile bool stop;
|
|
|
|
struct perf_event_sample {
|
|
struct perf_event_header header;
|
|
__u64 time;
|
|
__u32 size;
|
|
unsigned char data[];
|
|
};
|
|
|
|
struct perf_event_lost {
|
|
struct perf_event_header header;
|
|
__u64 id;
|
|
__u64 lost;
|
|
};
|
|
|
|
static void int_exit(int signo)
|
|
{
|
|
fprintf(stderr, "Stopping...\n");
|
|
stop = true;
|
|
}
|
|
|
|
struct event_pipe_ctx {
|
|
bool all_cpus;
|
|
int cpu;
|
|
int idx;
|
|
};
|
|
|
|
static enum bpf_perf_event_ret
|
|
print_bpf_output(void *private_data, int cpu, struct perf_event_header *event)
|
|
{
|
|
struct perf_event_sample *e = container_of(event,
|
|
struct perf_event_sample,
|
|
header);
|
|
struct perf_event_lost *lost = container_of(event,
|
|
struct perf_event_lost,
|
|
header);
|
|
struct event_pipe_ctx *ctx = private_data;
|
|
int idx = ctx->all_cpus ? cpu : ctx->idx;
|
|
|
|
if (json_output) {
|
|
jsonw_start_object(json_wtr);
|
|
jsonw_name(json_wtr, "type");
|
|
jsonw_uint(json_wtr, e->header.type);
|
|
jsonw_name(json_wtr, "cpu");
|
|
jsonw_uint(json_wtr, cpu);
|
|
jsonw_name(json_wtr, "index");
|
|
jsonw_uint(json_wtr, idx);
|
|
if (e->header.type == PERF_RECORD_SAMPLE) {
|
|
jsonw_name(json_wtr, "timestamp");
|
|
jsonw_uint(json_wtr, e->time);
|
|
jsonw_name(json_wtr, "data");
|
|
print_data_json(e->data, e->size);
|
|
} else if (e->header.type == PERF_RECORD_LOST) {
|
|
jsonw_name(json_wtr, "lost");
|
|
jsonw_start_object(json_wtr);
|
|
jsonw_name(json_wtr, "id");
|
|
jsonw_uint(json_wtr, lost->id);
|
|
jsonw_name(json_wtr, "count");
|
|
jsonw_uint(json_wtr, lost->lost);
|
|
jsonw_end_object(json_wtr);
|
|
}
|
|
jsonw_end_object(json_wtr);
|
|
} else {
|
|
if (e->header.type == PERF_RECORD_SAMPLE) {
|
|
printf("== @%llu.%09llu CPU: %d index: %d =====\n",
|
|
e->time / 1000000000ULL, e->time % 1000000000ULL,
|
|
cpu, idx);
|
|
fprint_hex(stdout, e->data, e->size, " ");
|
|
printf("\n");
|
|
} else if (e->header.type == PERF_RECORD_LOST) {
|
|
printf("lost %llu events\n", lost->lost);
|
|
} else {
|
|
printf("unknown event type=%u size=%u\n",
|
|
e->header.type, e->header.size);
|
|
}
|
|
}
|
|
|
|
return LIBBPF_PERF_EVENT_CONT;
|
|
}
|
|
|
|
int do_event_pipe(int argc, char **argv)
|
|
{
|
|
struct perf_event_attr perf_attr = {
|
|
.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_TIME,
|
|
.type = PERF_TYPE_SOFTWARE,
|
|
.config = PERF_COUNT_SW_BPF_OUTPUT,
|
|
.sample_period = 1,
|
|
.wakeup_events = 1,
|
|
};
|
|
struct bpf_map_info map_info = {};
|
|
LIBBPF_OPTS(perf_buffer_raw_opts, opts);
|
|
struct event_pipe_ctx ctx = {
|
|
.all_cpus = true,
|
|
.cpu = -1,
|
|
.idx = -1,
|
|
};
|
|
struct perf_buffer *pb;
|
|
__u32 map_info_len;
|
|
int err, map_fd;
|
|
|
|
map_info_len = sizeof(map_info);
|
|
map_fd = map_parse_fd_and_info(&argc, &argv, &map_info, &map_info_len,
|
|
0);
|
|
if (map_fd < 0)
|
|
return -1;
|
|
|
|
if (map_info.type != BPF_MAP_TYPE_PERF_EVENT_ARRAY) {
|
|
p_err("map is not a perf event array");
|
|
goto err_close_map;
|
|
}
|
|
|
|
while (argc) {
|
|
if (argc < 2) {
|
|
BAD_ARG();
|
|
goto err_close_map;
|
|
}
|
|
|
|
if (is_prefix(*argv, "cpu")) {
|
|
char *endptr;
|
|
|
|
NEXT_ARG();
|
|
ctx.cpu = strtoul(*argv, &endptr, 0);
|
|
if (*endptr) {
|
|
p_err("can't parse %s as CPU ID", *argv);
|
|
goto err_close_map;
|
|
}
|
|
|
|
NEXT_ARG();
|
|
} else if (is_prefix(*argv, "index")) {
|
|
char *endptr;
|
|
|
|
NEXT_ARG();
|
|
ctx.idx = strtoul(*argv, &endptr, 0);
|
|
if (*endptr) {
|
|
p_err("can't parse %s as index", *argv);
|
|
goto err_close_map;
|
|
}
|
|
|
|
NEXT_ARG();
|
|
} else {
|
|
BAD_ARG();
|
|
goto err_close_map;
|
|
}
|
|
|
|
ctx.all_cpus = false;
|
|
}
|
|
|
|
if (!ctx.all_cpus) {
|
|
if (ctx.idx == -1 || ctx.cpu == -1) {
|
|
p_err("cpu and index must be specified together");
|
|
goto err_close_map;
|
|
}
|
|
} else {
|
|
ctx.cpu = 0;
|
|
ctx.idx = 0;
|
|
}
|
|
|
|
opts.cpu_cnt = ctx.all_cpus ? 0 : 1;
|
|
opts.cpus = &ctx.cpu;
|
|
opts.map_keys = &ctx.idx;
|
|
pb = perf_buffer__new_raw(map_fd, MMAP_PAGE_CNT, &perf_attr,
|
|
print_bpf_output, &ctx, &opts);
|
|
if (!pb) {
|
|
p_err("failed to create perf buffer: %s (%d)",
|
|
strerror(errno), errno);
|
|
goto err_close_map;
|
|
}
|
|
|
|
signal(SIGINT, int_exit);
|
|
signal(SIGHUP, int_exit);
|
|
signal(SIGTERM, int_exit);
|
|
|
|
if (json_output)
|
|
jsonw_start_array(json_wtr);
|
|
|
|
while (!stop) {
|
|
err = perf_buffer__poll(pb, 200);
|
|
if (err < 0 && err != -EINTR) {
|
|
p_err("perf buffer polling failed: %s (%d)",
|
|
strerror(errno), errno);
|
|
goto err_close_pb;
|
|
}
|
|
}
|
|
|
|
if (json_output)
|
|
jsonw_end_array(json_wtr);
|
|
|
|
perf_buffer__free(pb);
|
|
close(map_fd);
|
|
|
|
return 0;
|
|
|
|
err_close_pb:
|
|
perf_buffer__free(pb);
|
|
err_close_map:
|
|
close(map_fd);
|
|
return -1;
|
|
}
|