Skip to content

Commit

Permalink
Merge tag 'perf-for-bpf-2020-05-06' of git://git.kernel.org/pub/scm/l…
Browse files Browse the repository at this point in the history
…inux/kernel/git/tip/tip into bpf-next

CAP_PERFMON for BPF
  • Loading branch information
Alexei Starovoitov committed May 7, 2020
2 parents a085a1e + 9807372 commit f87b87a
Show file tree
Hide file tree
Showing 10 changed files with 145 additions and 4 deletions.
4 changes: 4 additions & 0 deletions include/linux/capability.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,10 @@ extern bool privileged_wrt_inode_uidgid(struct user_namespace *ns, const struct
extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap);
extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap);
extern bool ptracer_capable(struct task_struct *tsk, struct user_namespace *ns);
static inline bool perfmon_capable(void)
{
return capable(CAP_PERFMON) || capable(CAP_SYS_ADMIN);
}

/* audit system wants to get cap info from files as well */
extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps);
Expand Down
8 changes: 7 additions & 1 deletion include/uapi/linux/capability.h
Original file line number Diff line number Diff line change
Expand Up @@ -367,8 +367,14 @@ struct vfs_ns_cap_data {

#define CAP_AUDIT_READ 37

/*
* Allow system performance and observability privileged operations
* using perf_events, i915_perf and other kernel subsystems
*/

#define CAP_PERFMON 38

#define CAP_LAST_CAP CAP_AUDIT_READ
#define CAP_LAST_CAP CAP_PERFMON

#define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)

Expand Down
4 changes: 2 additions & 2 deletions security/selinux/include/classmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
"audit_control", "setfcap"

#define COMMON_CAP2_PERMS "mac_override", "mac_admin", "syslog", \
"wake_alarm", "block_suspend", "audit_read"
"wake_alarm", "block_suspend", "audit_read", "perfmon"

#if CAP_LAST_CAP > CAP_AUDIT_READ
#if CAP_LAST_CAP > CAP_PERFMON
#error New capability defined, please update COMMON_CAP2_PERMS.
#endif

Expand Down
5 changes: 4 additions & 1 deletion tools/perf/builtin-stat.c
Original file line number Diff line number Diff line change
Expand Up @@ -686,8 +686,11 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx)
break;
}
}
if (child_pid != -1)
if (child_pid != -1) {
if (timeout)
kill(child_pid, SIGTERM);
wait4(child_pid, &status, 0, &stat_config.ru_data);
}

if (workload_exec_errno) {
const char *emsg = str_error_r(workload_exec_errno, msg, sizeof(msg));
Expand Down
20 changes: 20 additions & 0 deletions tools/perf/util/annotate.c
Original file line number Diff line number Diff line change
Expand Up @@ -1821,6 +1821,24 @@ static int symbol__disassemble_bpf(struct symbol *sym __maybe_unused,
}
#endif // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)

static int
symbol__disassemble_bpf_image(struct symbol *sym,
struct annotate_args *args)
{
struct annotation *notes = symbol__annotation(sym);
struct disasm_line *dl;

args->offset = -1;
args->line = strdup("to be implemented");
args->line_nr = 0;
dl = disasm_line__new(args);
if (dl)
annotation_line__add(&dl->al, &notes->src->source);

free(args->line);
return 0;
}

/*
* Possibly create a new version of line with tabs expanded. Returns the
* existing or new line, storage is updated if a new line is allocated. If
Expand Down Expand Up @@ -1920,6 +1938,8 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)

if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) {
return symbol__disassemble_bpf(sym, args);
} else if (dso->binary_type == DSO_BINARY_TYPE__BPF_IMAGE) {
return symbol__disassemble_bpf_image(sym, args);
} else if (dso__is_kcore(dso)) {
kce.kcore_filename = symfs_filename;
kce.addr = map__rip_2objdump(map, sym->start);
Expand Down
93 changes: 93 additions & 0 deletions tools/perf/util/bpf-event.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
#include <bpf/libbpf.h>
#include <linux/btf.h>
#include <linux/err.h>
#include <linux/string.h>
#include <internal/lib.h>
#include <symbol/kallsyms.h>
#include "bpf-event.h"
#include "debug.h"
#include "dso.h"
Expand Down Expand Up @@ -290,11 +293,82 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session,
return err ? -1 : 0;
}

struct kallsyms_parse {
union perf_event *event;
perf_event__handler_t process;
struct machine *machine;
struct perf_tool *tool;
};

static int
process_bpf_image(char *name, u64 addr, struct kallsyms_parse *data)
{
struct machine *machine = data->machine;
union perf_event *event = data->event;
struct perf_record_ksymbol *ksymbol;
int len;

ksymbol = &event->ksymbol;

*ksymbol = (struct perf_record_ksymbol) {
.header = {
.type = PERF_RECORD_KSYMBOL,
.size = offsetof(struct perf_record_ksymbol, name),
},
.addr = addr,
.len = page_size,
.ksym_type = PERF_RECORD_KSYMBOL_TYPE_BPF,
.flags = 0,
};

len = scnprintf(ksymbol->name, KSYM_NAME_LEN, "%s", name);
ksymbol->header.size += PERF_ALIGN(len + 1, sizeof(u64));
memset((void *) event + event->header.size, 0, machine->id_hdr_size);
event->header.size += machine->id_hdr_size;

return perf_tool__process_synth_event(data->tool, event, machine,
data->process);
}

static int
kallsyms_process_symbol(void *data, const char *_name,
char type __maybe_unused, u64 start)
{
char disp[KSYM_NAME_LEN];
char *module, *name;
unsigned long id;
int err = 0;

module = strchr(_name, '\t');
if (!module)
return 0;

/* We are going after [bpf] module ... */
if (strcmp(module + 1, "[bpf]"))
return 0;

name = memdup(_name, (module - _name) + 1);
if (!name)
return -ENOMEM;

name[module - _name] = 0;

/* .. and only for trampolines and dispatchers */
if ((sscanf(name, "bpf_trampoline_%lu", &id) == 1) ||
(sscanf(name, "bpf_dispatcher_%s", disp) == 1))
err = process_bpf_image(name, start, data);

free(name);
return err;
}

int perf_event__synthesize_bpf_events(struct perf_session *session,
perf_event__handler_t process,
struct machine *machine,
struct record_opts *opts)
{
const char *kallsyms_filename = "/proc/kallsyms";
struct kallsyms_parse arg;
union perf_event *event;
__u32 id = 0;
int err;
Expand All @@ -303,6 +377,8 @@ int perf_event__synthesize_bpf_events(struct perf_session *session,
event = malloc(sizeof(event->bpf) + KSYM_NAME_LEN + machine->id_hdr_size);
if (!event)
return -1;

/* Synthesize all the bpf programs in system. */
while (true) {
err = bpf_prog_get_next_id(id, &id);
if (err) {
Expand Down Expand Up @@ -335,6 +411,23 @@ int perf_event__synthesize_bpf_events(struct perf_session *session,
break;
}
}

/* Synthesize all the bpf images - trampolines/dispatchers. */
if (symbol_conf.kallsyms_name != NULL)
kallsyms_filename = symbol_conf.kallsyms_name;

arg = (struct kallsyms_parse) {
.event = event,
.process = process,
.machine = machine,
.tool = session->tool,
};

if (kallsyms__parse(kallsyms_filename, &arg, kallsyms_process_symbol)) {
pr_err("%s: failed to synthesize bpf images: %s\n",
__func__, strerror(errno));
}

free(event);
return err;
}
Expand Down
1 change: 1 addition & 0 deletions tools/perf/util/dso.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ int dso__read_binary_type_filename(const struct dso *dso,
case DSO_BINARY_TYPE__GUEST_KALLSYMS:
case DSO_BINARY_TYPE__JAVA_JIT:
case DSO_BINARY_TYPE__BPF_PROG_INFO:
case DSO_BINARY_TYPE__BPF_IMAGE:
case DSO_BINARY_TYPE__NOT_FOUND:
ret = -1;
break;
Expand Down
1 change: 1 addition & 0 deletions tools/perf/util/dso.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ enum dso_binary_type {
DSO_BINARY_TYPE__GUEST_KCORE,
DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
DSO_BINARY_TYPE__BPF_PROG_INFO,
DSO_BINARY_TYPE__BPF_IMAGE,
DSO_BINARY_TYPE__NOT_FOUND,
};

Expand Down
12 changes: 12 additions & 0 deletions tools/perf/util/machine.c
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,12 @@ int machine__process_switch_event(struct machine *machine __maybe_unused,
return 0;
}

static int is_bpf_image(const char *name)
{
return strncmp(name, "bpf_trampoline_", sizeof("bpf_trampoline_") - 1) ||
strncmp(name, "bpf_dispatcher_", sizeof("bpf_dispatcher_") - 1);
}

static int machine__process_ksymbol_register(struct machine *machine,
union perf_event *event,
struct perf_sample *sample __maybe_unused)
Expand All @@ -759,6 +765,12 @@ static int machine__process_ksymbol_register(struct machine *machine,
map->start = event->ksymbol.addr;
map->end = map->start + event->ksymbol.len;
maps__insert(&machine->kmaps, map);
dso__set_loaded(dso);

if (is_bpf_image(event->ksymbol.name)) {
dso->binary_type = DSO_BINARY_TYPE__BPF_IMAGE;
dso__set_long_name(dso, "", false);
}
}

sym = symbol__new(map->map_ip(map, map->start),
Expand Down
1 change: 1 addition & 0 deletions tools/perf/util/symbol.c
Original file line number Diff line number Diff line change
Expand Up @@ -1544,6 +1544,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
return true;

case DSO_BINARY_TYPE__BPF_PROG_INFO:
case DSO_BINARY_TYPE__BPF_IMAGE:
case DSO_BINARY_TYPE__NOT_FOUND:
default:
return false;
Expand Down

0 comments on commit f87b87a

Please sign in to comment.