Commit 037776e4 authored by Daniel Borkmann's avatar Daniel Borkmann

Merge branch 'bpf-fix-broken-uapi-for-pt-regs'

Hendrik Brueckner says:

====================
Perf tool bpf selftests revealed a broken uapi for s390 and arm64.
With the BPF_PROG_TYPE_PERF_EVENT program type the bpf_perf_event
structure exports the pt_regs structure for all architectures.

This fails for s390 and arm64 because pt_regs are not part of the
user api and kept in-kernel only.  To mitigate the broken uapi,
introduce a wrapper that exports pt_regs in an asm-generic way.
For arm64, export the exising user_pt_regs structure.  For s390,
introduce a user_pt_regs structure that exports the beginning of
pt_regs.

Note that user_pt_regs must export from the beginning of pt_regs
as BPF_PROG_TYPE_PERF_EVENT program type is not the only type for
running BPF programs.

Some more background:

  For the bpf_perf_event, there is a uapi definition that is
  passed to the BPF program.  For other "probe" points like
  trace points, kprobes, and uprobes, there is no uapi and the
  BPF program is always passed pt_regs (which is OK as the BPF
  program runs in the kernel context).  The perf tool can attach
  BPF programs to all of these "probe" points and, optionally,
  can create a BPF prologue to access particular arguments
  (passed as registers).  For this, it uses DWARF/CFI
  information to obtain the register and calls a perf-arch
  backend function, regs_query_register_offset().  This function
  returns the index into (user_)pt_regs for a particular
  register.  Then, perf creates a BPF prologue that accesses
  this register based on the passed stucture from the "probe"
  point.

Part of this series, are also updates to the testing and bpf selftest
to deal with asm-specifics.  To complete the bpf support in perf, the
the regs_query_register_offset function is added for s390 to support
BPF prologue creation.

Changelog v1 -> v2:
- Correct kbuild test bot issues by including
  asm-generic/bpf_perf_event.h for archictectures that do not have
  their own asm version.
- Added patch to clean-up whitespace and coding style issues in s390
  asm/ptrace.h (#4/6) as suggested by Alexei.
====================
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
parents 2391f0b4 a81c4213
# UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm
generic-y += bpf_perf_event.h
......@@ -3,6 +3,7 @@ include include/uapi/asm-generic/Kbuild.asm
generic-y += auxvec.h
generic-y += bitsperlong.h
generic-y += bpf_perf_event.h
generic-y += errno.h
generic-y += fcntl.h
generic-y += ioctl.h
......
......@@ -7,6 +7,7 @@ generated-y += unistd-oabi.h
generated-y += unistd-eabi.h
generic-y += bitsperlong.h
generic-y += bpf_perf_event.h
generic-y += errno.h
generic-y += ioctl.h
generic-y += ipcbuf.h
......
......@@ -18,6 +18,7 @@
#define __ASM_PERF_EVENT_H
#include <asm/stack_pointer.h>
#include <asm/ptrace.h>
#define ARMV8_PMU_MAX_COUNTERS 32
#define ARMV8_PMU_COUNTER_MASK (ARMV8_PMU_MAX_COUNTERS - 1)
......@@ -79,6 +80,7 @@ struct pt_regs;
extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
extern unsigned long perf_misc_flags(struct pt_regs *regs);
#define perf_misc_flags(regs) perf_misc_flags(regs)
#define perf_arch_bpf_user_pt_regs(regs) &regs->user_regs
#endif
#define perf_arch_fetch_caller_regs(regs, __ip) { \
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _UAPI__ASM_BPF_PERF_EVENT_H__
#define _UAPI__ASM_BPF_PERF_EVENT_H__
#include <asm/ptrace.h>
typedef struct user_pt_regs bpf_user_pt_regs_t;
#endif /* _UAPI__ASM_BPF_PERF_EVENT_H__ */
......@@ -3,6 +3,7 @@ include include/uapi/asm-generic/Kbuild.asm
generic-y += auxvec.h
generic-y += bitsperlong.h
generic-y += bpf_perf_event.h
generic-y += errno.h
generic-y += ioctl.h
generic-y += ipcbuf.h
......
......@@ -3,6 +3,7 @@ include include/uapi/asm-generic/Kbuild.asm
generic-y += auxvec.h
generic-y += bitsperlong.h
generic-y += bpf_perf_event.h
generic-y += errno.h
generic-y += fcntl.h
generic-y += ioctl.h
......
......@@ -3,6 +3,7 @@ include include/uapi/asm-generic/Kbuild.asm
generic-y += auxvec.h
generic-y += bitsperlong.h
generic-y += bpf_perf_event.h
generic-y += errno.h
generic-y += fcntl.h
generic-y += ioctl.h
......
# UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm
generic-y += bpf_perf_event.h
......@@ -2,6 +2,7 @@
include include/uapi/asm-generic/Kbuild.asm
generic-y += auxvec.h
generic-y += bpf_perf_event.h
generic-y += errno.h
generic-y += fcntl.h
generic-y += ioctl.h
......
......@@ -2,6 +2,7 @@
include include/uapi/asm-generic/Kbuild.asm
generic-y += auxvec.h
generic-y += bpf_perf_event.h
generic-y += errno.h
generic-y += fcntl.h
generic-y += ioctl.h
......
# UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm
generic-y += bpf_perf_event.h
generic-y += kvm_para.h
# UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm
generic-y += bpf_perf_event.h
generic-y += kvm_para.h
generic-y += siginfo.h
......@@ -3,6 +3,7 @@ include include/uapi/asm-generic/Kbuild.asm
generic-y += auxvec.h
generic-y += bitsperlong.h
generic-y += bpf_perf_event.h
generic-y += errno.h
generic-y += ioctl.h
generic-y += ipcbuf.h
......
......@@ -3,6 +3,7 @@ include include/uapi/asm-generic/Kbuild.asm
generic-y += auxvec.h
generic-y += bitsperlong.h
generic-y += bpf_perf_event.h
generic-y += errno.h
generic-y += fcntl.h
generic-y += ioctl.h
......
......@@ -2,6 +2,7 @@
include include/uapi/asm-generic/Kbuild.asm
generic-y += bitsperlong.h
generic-y += bpf_perf_event.h
generic-y += errno.h
generic-y += fcntl.h
generic-y += ioctl.h
......
# UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm
generic-y += bpf_perf_event.h
generic-y += ipcbuf.h
# UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm
generic-y += bpf_perf_event.h
generic-y += siginfo.h
......@@ -3,6 +3,7 @@ include include/uapi/asm-generic/Kbuild.asm
generic-y += auxvec.h
generic-y += bitsperlong.h
generic-y += bpf_perf_event.h
generic-y += errno.h
generic-y += fcntl.h
generic-y += ioctl.h
......
......@@ -3,6 +3,7 @@ include include/uapi/asm-generic/Kbuild.asm
generic-y += auxvec.h
generic-y += bitsperlong.h
generic-y += bpf_perf_event.h
generic-y += errno.h
generic-y += fcntl.h
generic-y += ioctl.h
......
......@@ -2,6 +2,7 @@
include include/uapi/asm-generic/Kbuild.asm
generic-y += auxvec.h
generic-y += bpf_perf_event.h
generic-y += kvm_para.h
generic-y += param.h
generic-y += poll.h
......
# UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm
generic-y += bpf_perf_event.h
generic-y += param.h
generic-y += poll.h
generic-y += resource.h
......
......@@ -3,6 +3,7 @@ include include/uapi/asm-generic/Kbuild.asm
generic-y += setup.h
generic-y += unistd.h
generic-y += bpf_perf_event.h
generic-y += errno.h
generic-y += fcntl.h
generic-y += ioctl.h
......
......@@ -40,6 +40,7 @@ struct pt_regs;
extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
extern unsigned long perf_misc_flags(struct pt_regs *regs);
#define perf_misc_flags(regs) perf_misc_flags(regs)
#define perf_arch_bpf_user_pt_regs(regs) &regs->user_regs
/* Perf pt_regs extension for sample-data-entry indicators */
struct perf_sf_sde_regs {
......
......@@ -74,9 +74,14 @@ enum {
*/
struct pt_regs
{
union {
user_pt_regs user_regs;
struct {
unsigned long args[1];
psw_t psw;
unsigned long gprs[NUM_GPRS];
};
};
unsigned long orig_gpr2;
unsigned int int_code;
unsigned int int_parm;
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _UAPI__ASM_BPF_PERF_EVENT_H__
#define _UAPI__ASM_BPF_PERF_EVENT_H__
#include <asm/ptrace.h>
typedef user_pt_regs bpf_user_pt_regs_t;
#endif /* _UAPI__ASM_BPF_PERF_EVENT_H__ */
......@@ -185,8 +185,7 @@
#include <linux/stddef.h>
#include <linux/types.h>
typedef union
{
typedef union {
float f;
double d;
__u64 ui;
......@@ -197,8 +196,7 @@ typedef union
} fp;
} freg_t;
typedef struct
{
typedef struct {
__u32 fpc;
__u32 pad;
freg_t fprs[NUM_FPRS];
......@@ -210,8 +208,7 @@ typedef struct
#define FPC_RM_MASK 0x00000003
/* this typedef defines how a Program Status Word looks like */
typedef struct
{
typedef struct {
unsigned long mask;
unsigned long addr;
} __attribute__ ((aligned(8))) psw_t;
......@@ -282,29 +279,36 @@ typedef struct
/*
* The s390_regs structure is used to define the elf_gregset_t.
*/
typedef struct
{
typedef struct {
psw_t psw;
unsigned long gprs[NUM_GPRS];
unsigned int acrs[NUM_ACRS];
unsigned long orig_gpr2;
} s390_regs;
/*
* The user_pt_regs structure exports the beginning of
* the in-kernel pt_regs structure to user space.
*/
typedef struct {
unsigned long args[1];
psw_t psw;
unsigned long gprs[NUM_GPRS];
} user_pt_regs;
/*
* Now for the user space program event recording (trace) definitions.
* The following structures are used only for the ptrace interface, don't
* touch or even look at it if you don't want to modify the user-space
* ptrace interface. In particular stay away from it for in-kernel PER.
*/
typedef struct
{
typedef struct {
unsigned long cr[NUM_CR_WORDS];
} per_cr_words;
#define PER_EM_MASK 0xE8000000UL
typedef struct
{
typedef struct {
#ifdef __s390x__
unsigned : 32;
#endif /* __s390x__ */
......@@ -326,15 +330,13 @@ typedef struct
unsigned long ending_addr;
} per_cr_bits;
typedef struct
{
typedef struct {
unsigned short perc_atmid;
unsigned long address;
unsigned char access_id;
} per_lowcore_words;
typedef struct
{
typedef struct {
unsigned perc_branching : 1;
unsigned perc_instruction_fetch : 1;
unsigned perc_storage_alteration : 1;
......@@ -353,8 +355,7 @@ typedef struct
unsigned access_id : 4;
} per_lowcore_bits;
typedef struct
{
typedef struct {
union {
per_cr_words words;
per_cr_bits bits;
......@@ -379,8 +380,7 @@ typedef struct
} lowcore;
} per_struct;
typedef struct
{
typedef struct {
unsigned int len;
unsigned long kernel_addr;
unsigned long process_addr;
......@@ -415,15 +415,13 @@ typedef struct
*/
#define PTRACE_PROT 21
typedef enum
{
typedef enum {
ptprot_set_access_watchpoint,
ptprot_set_write_watchpoint,
ptprot_disable_watchpoint
} ptprot_flags;
typedef struct
{
typedef struct {
unsigned long lowaddr;
unsigned long hiaddr;
ptprot_flags prot;
......@@ -439,8 +437,7 @@ typedef struct
* The user_regs_struct defines the way the user registers are
* store on the stack for signal handling.
*/
struct user_regs_struct
{
struct user_regs_struct {
psw_t psw;
unsigned long gprs[NUM_GPRS];
unsigned int acrs[NUM_ACRS];
......
# UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm
generic-y += bpf_perf_event.h
generic-y += siginfo.h
......@@ -2,6 +2,7 @@
include include/uapi/asm-generic/Kbuild.asm
generic-y += bitsperlong.h
generic-y += bpf_perf_event.h
generic-y += errno.h
generic-y += fcntl.h
generic-y += ioctl.h
......
# UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm
generic-y += bpf_perf_event.h
generic-y += types.h
# UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm
generic-y += bpf_perf_event.h
generic-y += errno.h
generic-y += fcntl.h
generic-y += ioctl.h
......
......@@ -3,6 +3,7 @@ include include/uapi/asm-generic/Kbuild.asm
generic-y += auxvec.h
generic-y += bitsperlong.h
generic-y += bpf_perf_event.h
generic-y += errno.h
generic-y += fcntl.h
generic-y += ioctl.h
......
# UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm
generic-y += bpf_perf_event.h
generated-y += unistd_32.h
generated-y += unistd_64.h
generated-y += unistd_x32.h
......@@ -2,6 +2,7 @@
include include/uapi/asm-generic/Kbuild.asm
generic-y += bitsperlong.h
generic-y += bpf_perf_event.h
generic-y += errno.h
generic-y += fcntl.h
generic-y += ioctl.h
......
......@@ -15,6 +15,7 @@
#define _LINUX_PERF_EVENT_H
#include <uapi/linux/perf_event.h>
#include <uapi/linux/bpf_perf_event.h>
/*
* Kernel-internal data types and definitions:
......@@ -787,7 +788,7 @@ struct perf_output_handle {
};
struct bpf_perf_event_data_kern {
struct pt_regs *regs;
bpf_user_pt_regs_t *regs;
struct perf_sample_data *data;
struct perf_event *event;
};
......@@ -1177,6 +1178,9 @@ extern void perf_bp_event(struct perf_event *event, void *data);
(user_mode(regs) ? PERF_RECORD_MISC_USER : PERF_RECORD_MISC_KERNEL)
# define perf_instruction_pointer(regs) instruction_pointer(regs)
#endif
#ifndef perf_arch_bpf_user_pt_regs
# define perf_arch_bpf_user_pt_regs(regs) regs
#endif
static inline bool has_branch_stack(struct perf_event *event)
{
......
#ifndef _UAPI__ASM_GENERIC_BPF_PERF_EVENT_H__
#define _UAPI__ASM_GENERIC_BPF_PERF_EVENT_H__
#include <linux/ptrace.h>
/* Export kernel pt_regs structure */
typedef struct pt_regs bpf_user_pt_regs_t;
#endif /* _UAPI__ASM_GENERIC_BPF_PERF_EVENT_H__ */
......@@ -8,11 +8,10 @@
#ifndef _UAPI__LINUX_BPF_PERF_EVENT_H__
#define _UAPI__LINUX_BPF_PERF_EVENT_H__
#include <linux/types.h>
#include <linux/ptrace.h>
#include <asm/bpf_perf_event.h>
struct bpf_perf_event_data {
struct pt_regs regs;
bpf_user_pt_regs_t regs;
__u64 sample_period;
};
......
......@@ -7987,11 +7987,11 @@ static void bpf_overflow_handler(struct perf_event *event,
{
struct bpf_perf_event_data_kern ctx = {
.data = data,
.regs = regs,
.event = event,
};
int ret = 0;
ctx.regs = perf_arch_bpf_user_pt_regs(regs);
preempt_disable();
if (unlikely(__this_cpu_inc_return(bpf_prog_active) != 1))
goto out;
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _UAPI__ASM_BPF_PERF_EVENT_H__
#define _UAPI__ASM_BPF_PERF_EVENT_H__
#include <asm/ptrace.h>
typedef struct user_pt_regs bpf_user_pt_regs_t;
#endif /* _UAPI__ASM_BPF_PERF_EVENT_H__ */
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _UAPI__ASM_BPF_PERF_EVENT_H__
#define _UAPI__ASM_BPF_PERF_EVENT_H__
#include <asm/ptrace.h>
typedef user_pt_regs bpf_user_pt_regs_t;
#endif /* _UAPI__ASM_BPF_PERF_EVENT_H__ */
This diff is collapsed.
#ifndef _UAPI__ASM_GENERIC_BPF_PERF_EVENT_H__
#define _UAPI__ASM_GENERIC_BPF_PERF_EVENT_H__
#include <linux/ptrace.h>
/* Export kernel pt_regs structure */
typedef struct pt_regs bpf_user_pt_regs_t;
#endif /* _UAPI__ASM_GENERIC_BPF_PERF_EVENT_H__ */
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/* Copyright (c) 2016 Facebook
*
* This program is free software; you can redistribute it and/or
......@@ -7,11 +8,10 @@
#ifndef _UAPI__LINUX_BPF_PERF_EVENT_H__
#define _UAPI__LINUX_BPF_PERF_EVENT_H__
#include <linux/types.h>
#include <linux/ptrace.h>
#include <asm/bpf_perf_event.h>
struct bpf_perf_event_data {
struct pt_regs regs;
bpf_user_pt_regs_t regs;
__u64 sample_period;
};
......
......@@ -2,3 +2,4 @@ ifndef NO_DWARF
PERF_HAVE_DWARF_REGS := 1
endif
HAVE_KVM_STAT_SUPPORT := 1
PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
......@@ -2,17 +2,43 @@
/*
* Mapping of DWARF debug register numbers into register names.
*
* Copyright IBM Corp. 2010
* Copyright IBM Corp. 2010, 2017
* Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
* Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
*
*/
#include <errno.h>
#include <stddef.h>
#include <dwarf-regs.h>
#include <stdlib.h>
#include <linux/kernel.h>
#include <asm/ptrace.h>
#include <string.h>
#include <dwarf-regs.h>
#include "dwarf-regs-table.h"
const char *get_arch_regstr(unsigned int n)
{
return (n >= ARRAY_SIZE(s390_dwarf_regs)) ? NULL : s390_dwarf_regs[n];
}
/*
* Convert the register name into an offset to struct pt_regs (kernel).
* This is required by the BPF prologue generator. The BPF
* program is called in the BPF overflow handler in the perf
* core.
*/
int regs_query_register_offset(const char *name)
{
unsigned long gpr;
if (!name || strncmp(name, "%r", 2))
return -EINVAL;
errno = 0;
gpr = strtoul(name + 2, NULL, 10);
if (errno || gpr >= 16)
return -EINVAL;
return offsetof(user_pt_regs, gprs) + 8 * gpr;
}
......@@ -30,6 +30,7 @@ arch/x86/include/uapi/asm/vmx.h
arch/powerpc/include/uapi/asm/kvm.h
arch/s390/include/uapi/asm/kvm.h
arch/s390/include/uapi/asm/kvm_perf.h
arch/s390/include/uapi/asm/ptrace.h
arch/s390/include/uapi/asm/sie.h
arch/arm/include/uapi/asm/kvm.h
arch/arm64/include/uapi/asm/kvm.h
......
# SPDX-License-Identifier: GPL-2.0
ifeq ($(srctree),)
srctree := $(patsubst %/,%,$(dir $(CURDIR)))
srctree := $(patsubst %/,%,$(dir $(srctree)))
srctree := $(patsubst %/,%,$(dir $(srctree)))
srctree := $(patsubst %/,%,$(dir $(srctree)))
endif
include $(srctree)/tools/scripts/Makefile.arch
$(call detected_var,SRCARCH)
LIBDIR := ../../../lib
BPFDIR := $(LIBDIR)/bpf
APIDIR := ../../../include/uapi
ASMDIR:= ../../../arch/$(ARCH)/include/uapi
GENDIR := ../../../../include/generated
GENHDR := $(GENDIR)/autoconf.h
......@@ -9,7 +21,7 @@ ifneq ($(wildcard $(GENHDR)),)
GENFLAGS := -DHAVE_GENHDR
endif
CFLAGS += -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(GENDIR) $(GENFLAGS) -I../../../include
CFLAGS += -Wall -O2 -I$(APIDIR) -I$(ASMDIR) -I$(LIBDIR) -I$(GENDIR) $(GENFLAGS) -I../../../include
LDLIBS += -lcap -lelf
TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment