Linus,

Please pull the latest perf-urgent-for-linus git tree from:

   git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git 
perf-urgent-for-linus

   # HEAD: 8b12b812f5367c2469fb937da7e28dd321ad8d7b perf/x86/regs: Use 
PERF_REG_EXTENDED_MASK

Various fixes, most of them related to bugs perf fuzzing found in the x86 
code.

 Thanks,

        Ingo

------------------>
Kan Liang (5):
      perf/x86: Disable extended registers for non-supported PMUs
      perf/x86/regs: Check reserved bits
      perf/x86: Clean up PEBS_XMM_REGS
      perf/x86: Remove pmu->pebs_no_xmm_regs
      perf/x86/regs: Use PERF_REG_EXTENDED_MASK

Peter Zijlstra (1):
      perf/core: Fix perf_sample_regs_user() mm check

Ravi Bangoria (1):
      perf/ioctl: Add check for the sample_period value


 arch/x86/events/core.c                      |  6 +++---
 arch/x86/events/intel/ds.c                  |  9 ++++-----
 arch/x86/events/perf_event.h                | 21 +--------------------
 arch/x86/include/uapi/asm/perf_regs.h       |  3 +++
 arch/x86/kernel/perf_regs.c                 |  7 +++++--
 include/linux/perf_event.h                  |  1 +
 include/linux/perf_regs.h                   |  8 ++++++++
 kernel/events/core.c                        | 23 ++++++++++++++++++-----
 tools/arch/x86/include/uapi/asm/perf_regs.h |  3 +++
 tools/perf/arch/x86/include/perf_regs.h     |  1 -
 tools/perf/arch/x86/util/perf_regs.c        |  4 ++--
 11 files changed, 48 insertions(+), 38 deletions(-)

diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
index f315425d8468..52a97463cb24 100644
--- a/arch/x86/events/core.c
+++ b/arch/x86/events/core.c
@@ -561,14 +561,14 @@ int x86_pmu_hw_config(struct perf_event *event)
        }
 
        /* 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;
        /*
         * Besides the general purpose registers, XMM registers may
         * be collected in PEBS on some platforms, e.g. Icelake
         */
-       if (unlikely(event->attr.sample_regs_intr & PEBS_XMM_REGS)) {
-               if (x86_pmu.pebs_no_xmm_regs)
+       if (unlikely(event->attr.sample_regs_intr & PERF_REG_EXTENDED_MASK)) {
+               if (!(event->pmu->capabilities & PERF_PMU_CAP_EXTENDED_REGS))
                        return -EINVAL;
 
                if (!event->attr.precise_ip)
diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c
index 7acc526b4ad2..505c73dc6a73 100644
--- a/arch/x86/events/intel/ds.c
+++ b/arch/x86/events/intel/ds.c
@@ -987,7 +987,7 @@ static u64 pebs_update_adaptive_cfg(struct perf_event 
*event)
                pebs_data_cfg |= PEBS_DATACFG_GP;
 
        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;
 
        if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
@@ -1964,10 +1964,9 @@ void __init intel_ds_init(void)
        x86_pmu.bts  = boot_cpu_has(X86_FEATURE_BTS);
        x86_pmu.pebs = boot_cpu_has(X86_FEATURE_PEBS);
        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_xmm_regs = 1;
-       }
+
        if (x86_pmu.pebs) {
                char pebs_type = x86_pmu.intel_cap.pebs_trap ?  '+' : '-';
                char *pebs_qual = "";
@@ -2020,9 +2019,9 @@ void __init intel_ds_init(void)
                                        PERF_SAMPLE_TIME;
                                x86_pmu.flags |= PMU_FL_PEBS_ALL;
                                pebs_qual = "-baseline";
+                               x86_get_pmu()->capabilities |= 
PERF_PMU_CAP_EXTENDED_REGS;
                        } else {
                                /* Only basic record supported */
-                               x86_pmu.pebs_no_xmm_regs = 1;
                                x86_pmu.large_pebs_flags &=
                                        ~(PERF_SAMPLE_ADDR |
                                          PERF_SAMPLE_TIME |
diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h
index a6ac2f4f76fc..4e346856ee19 100644
--- a/arch/x86/events/perf_event.h
+++ b/arch/x86/events/perf_event.h
@@ -121,24 +121,6 @@ struct amd_nb {
         (1ULL << PERF_REG_X86_R14)   | \
         (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.
  */
@@ -668,8 +650,7 @@ struct x86_pmu {
                        pebs_broken             :1,
                        pebs_prec_dist          :1,
                        pebs_no_tlb             :1,
-                       pebs_no_isolation       :1,
-                       pebs_no_xmm_regs        :1;
+                       pebs_no_isolation       :1;
        int             pebs_record_size;
        int             pebs_buffer_size;
        int             max_pebs_events;
diff --git a/arch/x86/include/uapi/asm/perf_regs.h 
b/arch/x86/include/uapi/asm/perf_regs.h
index ac67bbea10ca..7c9d2bb3833b 100644
--- a/arch/x86/include/uapi/asm/perf_regs.h
+++ b/arch/x86/include/uapi/asm/perf_regs.h
@@ -52,4 +52,7 @@ enum perf_event_x86_regs {
        /* These include both GPRs and XMMX registers */
        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 */
diff --git a/arch/x86/kernel/perf_regs.c b/arch/x86/kernel/perf_regs.c
index 07c30ee17425..bb7e1132290b 100644
--- a/arch/x86/kernel/perf_regs.c
+++ b/arch/x86/kernel/perf_regs.c
@@ -74,6 +74,9 @@ u64 perf_reg_value(struct pt_regs *regs, int 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
 #define REG_NOSUPPORT ((1ULL << PERF_REG_X86_R8) | \
                       (1ULL << PERF_REG_X86_R9) | \
@@ -86,7 +89,7 @@ u64 perf_reg_value(struct pt_regs *regs, int idx)
 
 int perf_reg_validate(u64 mask)
 {
-       if (!mask || (mask & REG_NOSUPPORT))
+       if (!mask || (mask & (REG_NOSUPPORT | PERF_REG_X86_RESERVED)))
                return -EINVAL;
 
        return 0;
@@ -112,7 +115,7 @@ void perf_get_regs_user(struct perf_regs *regs_user,
 
 int perf_reg_validate(u64 mask)
 {
-       if (!mask || (mask & REG_NOSUPPORT))
+       if (!mask || (mask & (REG_NOSUPPORT | PERF_REG_X86_RESERVED)))
                return -EINVAL;
 
        return 0;
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 0ab99c7b652d..2bca72f3028b 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -241,6 +241,7 @@ struct perf_event;
 #define PERF_PMU_CAP_NO_INTERRUPT              0x01
 #define PERF_PMU_CAP_NO_NMI                    0x02
 #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_ITRACE                    0x20
 #define PERF_PMU_CAP_HETEROGENEOUS_CPUS                0x40
diff --git a/include/linux/perf_regs.h b/include/linux/perf_regs.h
index 476747456bca..2d12e97d5e7b 100644
--- a/include/linux/perf_regs.h
+++ b/include/linux/perf_regs.h
@@ -11,6 +11,11 @@ struct perf_regs {
 
 #ifdef CONFIG_HAVE_PERF_REGS
 #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);
 int perf_reg_validate(u64 mask);
 u64 perf_reg_abi(struct task_struct *task);
@@ -18,6 +23,9 @@ void perf_get_regs_user(struct perf_regs *regs_user,
                        struct pt_regs *regs,
                        struct pt_regs *regs_user_copy);
 #else
+
+#define PERF_REG_EXTENDED_MASK 0
+
 static inline u64 perf_reg_value(struct pt_regs *regs, int idx)
 {
        return 0;
diff --git a/kernel/events/core.c b/kernel/events/core.c
index abbd4b3b96c2..f85929ce13be 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -5005,6 +5005,9 @@ static int perf_event_period(struct perf_event *event, 
u64 __user *arg)
        if (perf_event_check_period(event, value))
                return -EINVAL;
 
+       if (!event->attr.freq && (value & (1ULL << 63)))
+               return -EINVAL;
+
        event_function_call(event, __perf_event_period, &value);
 
        return 0;
@@ -5923,7 +5926,7 @@ static void perf_sample_regs_user(struct perf_regs 
*regs_user,
        if (user_mode(regs)) {
                regs_user->abi = perf_reg_abi(current);
                regs_user->regs = regs;
-       } else if (current->mm) {
+       } else if (!(current->flags & PF_KTHREAD)) {
                perf_get_regs_user(regs_user, regs, regs_user_copy);
        } else {
                regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
@@ -10033,6 +10036,12 @@ void perf_pmu_unregister(struct pmu *pmu)
 }
 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)
 {
        struct perf_event_context *ctx = NULL;
@@ -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);
 
        if (!ret) {
+               if (!(pmu->capabilities & PERF_PMU_CAP_EXTENDED_REGS) &&
+                   has_extended_regs(event))
+                       ret = -EOPNOTSUPP;
+
                if (pmu->capabilities & PERF_PMU_CAP_NO_EXCLUDE &&
-                               event_has_any_exclude_flag(event)) {
-                       if (event->destroy)
-                               event->destroy(event);
+                   event_has_any_exclude_flag(event))
                        ret = -EINVAL;
-               }
+
+               if (ret && event->destroy)
+                       event->destroy(event);
        }
 
        if (ret)
diff --git a/tools/arch/x86/include/uapi/asm/perf_regs.h 
b/tools/arch/x86/include/uapi/asm/perf_regs.h
index ac67bbea10ca..7c9d2bb3833b 100644
--- a/tools/arch/x86/include/uapi/asm/perf_regs.h
+++ b/tools/arch/x86/include/uapi/asm/perf_regs.h
@@ -52,4 +52,7 @@ enum perf_event_x86_regs {
        /* These include both GPRs and XMMX registers */
        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 */
diff --git a/tools/perf/arch/x86/include/perf_regs.h 
b/tools/perf/arch/x86/include/perf_regs.h
index b7cd91a9014f..b7321337d100 100644
--- a/tools/perf/arch/x86/include/perf_regs.h
+++ b/tools/perf/arch/x86/include/perf_regs.h
@@ -9,7 +9,6 @@
 void perf_regs_load(u64 *regs);
 
 #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
 #define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)
 #define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_32
diff --git a/tools/perf/arch/x86/util/perf_regs.c 
b/tools/perf/arch/x86/util/perf_regs.c
index 7886ca5263e3..3666c0076df9 100644
--- a/tools/perf/arch/x86/util/perf_regs.c
+++ b/tools/perf/arch/x86/util/perf_regs.c
@@ -277,7 +277,7 @@ uint64_t arch__intr_reg_mask(void)
                .type                   = PERF_TYPE_HARDWARE,
                .config                 = PERF_COUNT_HW_CPU_CYCLES,
                .sample_type            = PERF_SAMPLE_REGS_INTR,
-               .sample_regs_intr       = PERF_XMM_REGS_MASK,
+               .sample_regs_intr       = PERF_REG_EXTENDED_MASK,
                .precise_ip             = 1,
                .disabled               = 1,
                .exclude_kernel         = 1,
@@ -293,7 +293,7 @@ uint64_t arch__intr_reg_mask(void)
        fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
        if (fd != -1) {
                close(fd);
-               return (PERF_XMM_REGS_MASK | PERF_REGS_MASK);
+               return (PERF_REG_EXTENDED_MASK | PERF_REGS_MASK);
        }
 
        return PERF_REGS_MASK;

Reply via email to