Commit 57103eb7 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf fixes from Ingo Molnar:
 "Various fixes, most of them related to bugs perf fuzzing found in the
  x86 code"

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  perf/x86/regs: Use PERF_REG_EXTENDED_MASK
  perf/x86: Remove pmu->pebs_no_xmm_regs
  perf/x86: Clean up PEBS_XMM_REGS
  perf/x86/regs: Check reserved bits
  perf/x86: Disable extended registers for non-supported PMUs
  perf/ioctl: Add check for the sample_period value
  perf/core: Fix perf_sample_regs_user() mm check
parents eed7d30e 8b12b812
...@@ -561,14 +561,14 @@ int x86_pmu_hw_config(struct perf_event *event) ...@@ -561,14 +561,14 @@ int x86_pmu_hw_config(struct perf_event *event)
} }
/* sample_regs_user never support XMM registers */ /* sample_regs_user never support XMM registers */
if (unlikely(event->attr.sample_regs_user & PEBS_XMM_REGS)) if (unlikely(event->attr.sample_regs_user & PERF_REG_EXTENDED_MASK))
return -EINVAL; return -EINVAL;
/* /*
* Besides the general purpose registers, XMM registers may * Besides the general purpose registers, XMM registers may
* be collected in PEBS on some platforms, e.g. Icelake * be collected in PEBS on some platforms, e.g. Icelake
*/ */
if (unlikely(event->attr.sample_regs_intr & PEBS_XMM_REGS)) { if (unlikely(event->attr.sample_regs_intr & PERF_REG_EXTENDED_MASK)) {
if (x86_pmu.pebs_no_xmm_regs) if (!(event->pmu->capabilities & PERF_PMU_CAP_EXTENDED_REGS))
return -EINVAL; return -EINVAL;
if (!event->attr.precise_ip) if (!event->attr.precise_ip)
......
...@@ -987,7 +987,7 @@ static u64 pebs_update_adaptive_cfg(struct perf_event *event) ...@@ -987,7 +987,7 @@ static u64 pebs_update_adaptive_cfg(struct perf_event *event)
pebs_data_cfg |= PEBS_DATACFG_GP; pebs_data_cfg |= PEBS_DATACFG_GP;
if ((sample_type & PERF_SAMPLE_REGS_INTR) && if ((sample_type & PERF_SAMPLE_REGS_INTR) &&
(attr->sample_regs_intr & PEBS_XMM_REGS)) (attr->sample_regs_intr & PERF_REG_EXTENDED_MASK))
pebs_data_cfg |= PEBS_DATACFG_XMMS; pebs_data_cfg |= PEBS_DATACFG_XMMS;
if (sample_type & PERF_SAMPLE_BRANCH_STACK) { if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
...@@ -1964,10 +1964,9 @@ void __init intel_ds_init(void) ...@@ -1964,10 +1964,9 @@ void __init intel_ds_init(void)
x86_pmu.bts = boot_cpu_has(X86_FEATURE_BTS); x86_pmu.bts = boot_cpu_has(X86_FEATURE_BTS);
x86_pmu.pebs = boot_cpu_has(X86_FEATURE_PEBS); x86_pmu.pebs = boot_cpu_has(X86_FEATURE_PEBS);
x86_pmu.pebs_buffer_size = PEBS_BUFFER_SIZE; x86_pmu.pebs_buffer_size = PEBS_BUFFER_SIZE;
if (x86_pmu.version <= 4) { if (x86_pmu.version <= 4)
x86_pmu.pebs_no_isolation = 1; x86_pmu.pebs_no_isolation = 1;
x86_pmu.pebs_no_xmm_regs = 1;
}
if (x86_pmu.pebs) { if (x86_pmu.pebs) {
char pebs_type = x86_pmu.intel_cap.pebs_trap ? '+' : '-'; char pebs_type = x86_pmu.intel_cap.pebs_trap ? '+' : '-';
char *pebs_qual = ""; char *pebs_qual = "";
...@@ -2020,9 +2019,9 @@ void __init intel_ds_init(void) ...@@ -2020,9 +2019,9 @@ void __init intel_ds_init(void)
PERF_SAMPLE_TIME; PERF_SAMPLE_TIME;
x86_pmu.flags |= PMU_FL_PEBS_ALL; x86_pmu.flags |= PMU_FL_PEBS_ALL;
pebs_qual = "-baseline"; pebs_qual = "-baseline";
x86_get_pmu()->capabilities |= PERF_PMU_CAP_EXTENDED_REGS;
} else { } else {
/* Only basic record supported */ /* Only basic record supported */
x86_pmu.pebs_no_xmm_regs = 1;
x86_pmu.large_pebs_flags &= x86_pmu.large_pebs_flags &=
~(PERF_SAMPLE_ADDR | ~(PERF_SAMPLE_ADDR |
PERF_SAMPLE_TIME | PERF_SAMPLE_TIME |
......
...@@ -121,24 +121,6 @@ struct amd_nb { ...@@ -121,24 +121,6 @@ struct amd_nb {
(1ULL << PERF_REG_X86_R14) | \ (1ULL << PERF_REG_X86_R14) | \
(1ULL << PERF_REG_X86_R15)) (1ULL << PERF_REG_X86_R15))
#define PEBS_XMM_REGS \
((1ULL << PERF_REG_X86_XMM0) | \
(1ULL << PERF_REG_X86_XMM1) | \
(1ULL << PERF_REG_X86_XMM2) | \
(1ULL << PERF_REG_X86_XMM3) | \
(1ULL << PERF_REG_X86_XMM4) | \
(1ULL << PERF_REG_X86_XMM5) | \
(1ULL << PERF_REG_X86_XMM6) | \
(1ULL << PERF_REG_X86_XMM7) | \
(1ULL << PERF_REG_X86_XMM8) | \
(1ULL << PERF_REG_X86_XMM9) | \
(1ULL << PERF_REG_X86_XMM10) | \
(1ULL << PERF_REG_X86_XMM11) | \
(1ULL << PERF_REG_X86_XMM12) | \
(1ULL << PERF_REG_X86_XMM13) | \
(1ULL << PERF_REG_X86_XMM14) | \
(1ULL << PERF_REG_X86_XMM15))
/* /*
* Per register state. * Per register state.
*/ */
...@@ -668,8 +650,7 @@ struct x86_pmu { ...@@ -668,8 +650,7 @@ struct x86_pmu {
pebs_broken :1, pebs_broken :1,
pebs_prec_dist :1, pebs_prec_dist :1,
pebs_no_tlb :1, pebs_no_tlb :1,
pebs_no_isolation :1, pebs_no_isolation :1;
pebs_no_xmm_regs :1;
int pebs_record_size; int pebs_record_size;
int pebs_buffer_size; int pebs_buffer_size;
int max_pebs_events; int max_pebs_events;
......
...@@ -52,4 +52,7 @@ enum perf_event_x86_regs { ...@@ -52,4 +52,7 @@ enum perf_event_x86_regs {
/* These include both GPRs and XMMX registers */ /* These include both GPRs and XMMX registers */
PERF_REG_X86_XMM_MAX = PERF_REG_X86_XMM15 + 2, PERF_REG_X86_XMM_MAX = PERF_REG_X86_XMM15 + 2,
}; };
#define PERF_REG_EXTENDED_MASK (~((1ULL << PERF_REG_X86_XMM0) - 1))
#endif /* _ASM_X86_PERF_REGS_H */ #endif /* _ASM_X86_PERF_REGS_H */
...@@ -74,6 +74,9 @@ u64 perf_reg_value(struct pt_regs *regs, int idx) ...@@ -74,6 +74,9 @@ u64 perf_reg_value(struct pt_regs *regs, int idx)
return regs_get_register(regs, pt_regs_offset[idx]); return regs_get_register(regs, pt_regs_offset[idx]);
} }
#define PERF_REG_X86_RESERVED (((1ULL << PERF_REG_X86_XMM0) - 1) & \
~((1ULL << PERF_REG_X86_MAX) - 1))
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
#define REG_NOSUPPORT ((1ULL << PERF_REG_X86_R8) | \ #define REG_NOSUPPORT ((1ULL << PERF_REG_X86_R8) | \
(1ULL << PERF_REG_X86_R9) | \ (1ULL << PERF_REG_X86_R9) | \
...@@ -86,7 +89,7 @@ u64 perf_reg_value(struct pt_regs *regs, int idx) ...@@ -86,7 +89,7 @@ u64 perf_reg_value(struct pt_regs *regs, int idx)
int perf_reg_validate(u64 mask) int perf_reg_validate(u64 mask)
{ {
if (!mask || (mask & REG_NOSUPPORT)) if (!mask || (mask & (REG_NOSUPPORT | PERF_REG_X86_RESERVED)))
return -EINVAL; return -EINVAL;
return 0; return 0;
...@@ -112,7 +115,7 @@ void perf_get_regs_user(struct perf_regs *regs_user, ...@@ -112,7 +115,7 @@ void perf_get_regs_user(struct perf_regs *regs_user,
int perf_reg_validate(u64 mask) int perf_reg_validate(u64 mask)
{ {
if (!mask || (mask & REG_NOSUPPORT)) if (!mask || (mask & (REG_NOSUPPORT | PERF_REG_X86_RESERVED)))
return -EINVAL; return -EINVAL;
return 0; return 0;
......
...@@ -241,6 +241,7 @@ struct perf_event; ...@@ -241,6 +241,7 @@ struct perf_event;
#define PERF_PMU_CAP_NO_INTERRUPT 0x01 #define PERF_PMU_CAP_NO_INTERRUPT 0x01
#define PERF_PMU_CAP_NO_NMI 0x02 #define PERF_PMU_CAP_NO_NMI 0x02
#define PERF_PMU_CAP_AUX_NO_SG 0x04 #define PERF_PMU_CAP_AUX_NO_SG 0x04
#define PERF_PMU_CAP_EXTENDED_REGS 0x08
#define PERF_PMU_CAP_EXCLUSIVE 0x10 #define PERF_PMU_CAP_EXCLUSIVE 0x10
#define PERF_PMU_CAP_ITRACE 0x20 #define PERF_PMU_CAP_ITRACE 0x20
#define PERF_PMU_CAP_HETEROGENEOUS_CPUS 0x40 #define PERF_PMU_CAP_HETEROGENEOUS_CPUS 0x40
......
...@@ -11,6 +11,11 @@ struct perf_regs { ...@@ -11,6 +11,11 @@ struct perf_regs {
#ifdef CONFIG_HAVE_PERF_REGS #ifdef CONFIG_HAVE_PERF_REGS
#include <asm/perf_regs.h> #include <asm/perf_regs.h>
#ifndef PERF_REG_EXTENDED_MASK
#define PERF_REG_EXTENDED_MASK 0
#endif
u64 perf_reg_value(struct pt_regs *regs, int idx); u64 perf_reg_value(struct pt_regs *regs, int idx);
int perf_reg_validate(u64 mask); int perf_reg_validate(u64 mask);
u64 perf_reg_abi(struct task_struct *task); u64 perf_reg_abi(struct task_struct *task);
...@@ -18,6 +23,9 @@ void perf_get_regs_user(struct perf_regs *regs_user, ...@@ -18,6 +23,9 @@ void perf_get_regs_user(struct perf_regs *regs_user,
struct pt_regs *regs, struct pt_regs *regs,
struct pt_regs *regs_user_copy); struct pt_regs *regs_user_copy);
#else #else
#define PERF_REG_EXTENDED_MASK 0
static inline u64 perf_reg_value(struct pt_regs *regs, int idx) static inline u64 perf_reg_value(struct pt_regs *regs, int idx)
{ {
return 0; return 0;
......
...@@ -5005,6 +5005,9 @@ static int perf_event_period(struct perf_event *event, u64 __user *arg) ...@@ -5005,6 +5005,9 @@ static int perf_event_period(struct perf_event *event, u64 __user *arg)
if (perf_event_check_period(event, value)) if (perf_event_check_period(event, value))
return -EINVAL; return -EINVAL;
if (!event->attr.freq && (value & (1ULL << 63)))
return -EINVAL;
event_function_call(event, __perf_event_period, &value); event_function_call(event, __perf_event_period, &value);
return 0; return 0;
...@@ -5923,7 +5926,7 @@ static void perf_sample_regs_user(struct perf_regs *regs_user, ...@@ -5923,7 +5926,7 @@ static void perf_sample_regs_user(struct perf_regs *regs_user,
if (user_mode(regs)) { if (user_mode(regs)) {
regs_user->abi = perf_reg_abi(current); regs_user->abi = perf_reg_abi(current);
regs_user->regs = regs; regs_user->regs = regs;
} else if (current->mm) { } else if (!(current->flags & PF_KTHREAD)) {
perf_get_regs_user(regs_user, regs, regs_user_copy); perf_get_regs_user(regs_user, regs, regs_user_copy);
} else { } else {
regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE; regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
...@@ -10033,6 +10036,12 @@ void perf_pmu_unregister(struct pmu *pmu) ...@@ -10033,6 +10036,12 @@ void perf_pmu_unregister(struct pmu *pmu)
} }
EXPORT_SYMBOL_GPL(perf_pmu_unregister); EXPORT_SYMBOL_GPL(perf_pmu_unregister);
static inline bool has_extended_regs(struct perf_event *event)
{
return (event->attr.sample_regs_user & PERF_REG_EXTENDED_MASK) ||
(event->attr.sample_regs_intr & PERF_REG_EXTENDED_MASK);
}
static int perf_try_init_event(struct pmu *pmu, struct perf_event *event) static int perf_try_init_event(struct pmu *pmu, struct perf_event *event)
{ {
struct perf_event_context *ctx = NULL; struct perf_event_context *ctx = NULL;
...@@ -10064,12 +10073,16 @@ static int perf_try_init_event(struct pmu *pmu, struct perf_event *event) ...@@ -10064,12 +10073,16 @@ static int perf_try_init_event(struct pmu *pmu, struct perf_event *event)
perf_event_ctx_unlock(event->group_leader, ctx); perf_event_ctx_unlock(event->group_leader, ctx);
if (!ret) { if (!ret) {
if (!(pmu->capabilities & PERF_PMU_CAP_EXTENDED_REGS) &&
has_extended_regs(event))
ret = -EOPNOTSUPP;
if (pmu->capabilities & PERF_PMU_CAP_NO_EXCLUDE && if (pmu->capabilities & PERF_PMU_CAP_NO_EXCLUDE &&
event_has_any_exclude_flag(event)) { event_has_any_exclude_flag(event))
if (event->destroy)
event->destroy(event);
ret = -EINVAL; ret = -EINVAL;
}
if (ret && event->destroy)
event->destroy(event);
} }
if (ret) if (ret)
......
...@@ -52,4 +52,7 @@ enum perf_event_x86_regs { ...@@ -52,4 +52,7 @@ enum perf_event_x86_regs {
/* These include both GPRs and XMMX registers */ /* These include both GPRs and XMMX registers */
PERF_REG_X86_XMM_MAX = PERF_REG_X86_XMM15 + 2, PERF_REG_X86_XMM_MAX = PERF_REG_X86_XMM15 + 2,
}; };
#define PERF_REG_EXTENDED_MASK (~((1ULL << PERF_REG_X86_XMM0) - 1))
#endif /* _ASM_X86_PERF_REGS_H */ #endif /* _ASM_X86_PERF_REGS_H */
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
void perf_regs_load(u64 *regs); void perf_regs_load(u64 *regs);
#define PERF_REGS_MAX PERF_REG_X86_XMM_MAX #define PERF_REGS_MAX PERF_REG_X86_XMM_MAX
#define PERF_XMM_REGS_MASK (~((1ULL << PERF_REG_X86_XMM0) - 1))
#ifndef HAVE_ARCH_X86_64_SUPPORT #ifndef HAVE_ARCH_X86_64_SUPPORT
#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1) #define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)
#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_32 #define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_32
......
...@@ -277,7 +277,7 @@ uint64_t arch__intr_reg_mask(void) ...@@ -277,7 +277,7 @@ uint64_t arch__intr_reg_mask(void)
.type = PERF_TYPE_HARDWARE, .type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_CPU_CYCLES, .config = PERF_COUNT_HW_CPU_CYCLES,
.sample_type = PERF_SAMPLE_REGS_INTR, .sample_type = PERF_SAMPLE_REGS_INTR,
.sample_regs_intr = PERF_XMM_REGS_MASK, .sample_regs_intr = PERF_REG_EXTENDED_MASK,
.precise_ip = 1, .precise_ip = 1,
.disabled = 1, .disabled = 1,
.exclude_kernel = 1, .exclude_kernel = 1,
...@@ -293,7 +293,7 @@ uint64_t arch__intr_reg_mask(void) ...@@ -293,7 +293,7 @@ uint64_t arch__intr_reg_mask(void)
fd = sys_perf_event_open(&attr, 0, -1, -1, 0); fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
if (fd != -1) { if (fd != -1) {
close(fd); close(fd);
return (PERF_XMM_REGS_MASK | PERF_REGS_MASK); return (PERF_REG_EXTENDED_MASK | PERF_REGS_MASK);
} }
return PERF_REGS_MASK; return PERF_REGS_MASK;
......
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