mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 20:22:09 +00:00
perf tools fixes for v5.16: 3rd batch
- Prevent out-of-bounds access to per sample registers. - Fix NULL vs IS_ERR_OR_NULL() checking on the python binding. - Intel PT fixes, half of those are one-liners: - Fix some PGE (packet generation enable/control flow packets) usage. - Fix sync state when a PSB (synchronization) packet is found. - Fix intel_pt_fup_event() assumptions about setting state type. - Fix state setting when receiving overflow (OVF) packet. - Fix next 'err' value, walking trace. - Fix missing 'instruction' events with 'q' option. - Fix error timestamp setting on the decoder error path. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQR2GiIUctdOfX2qHhGyPKLppCJ+JwUCYbTE4gAKCRCyPKLppCJ+ JyuQAQC6hgdIIY+1aXlTer4OKep8AdnH5y6q1GLxcNX0UX/iUgD+OjxBFiFk50Ix jCWFjM1rsDHLJbPZmztRX4IxNHFJzAg= =ZkBH -----END PGP SIGNATURE----- Merge tag 'perf-tools-fixes-for-v5.16-2021-12-11' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux Pull perf tools fixes from Arnaldo Carvalho de Melo: - Prevent out-of-bounds access to per sample registers. - Fix NULL vs IS_ERR_OR_NULL() checking on the python binding. - Intel PT fixes, half of those are one-liners: - Fix some PGE (packet generation enable/control flow packets) usage. - Fix sync state when a PSB (synchronization) packet is found. - Fix intel_pt_fup_event() assumptions about setting state type. - Fix state setting when receiving overflow (OVF) packet. - Fix next 'err' value, walking trace. - Fix missing 'instruction' events with 'q' option. - Fix error timestamp setting on the decoder error path. * tag 'perf-tools-fixes-for-v5.16-2021-12-11' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux: perf python: Fix NULL vs IS_ERR_OR_NULL() checking perf intel-pt: Fix error timestamp setting on the decoder error path perf intel-pt: Fix missing 'instruction' events with 'q' option perf intel-pt: Fix next 'err' value, walking trace perf intel-pt: Fix state setting when receiving overflow (OVF) packet perf intel-pt: Fix intel_pt_fup_event() assumptions about setting state type perf intel-pt: Fix sync state when a PSB (synchronization) packet is found perf intel-pt: Fix some PGE (packet generation enable/control flow packets) usage perf tools: Prevent out-of-bounds access to registers
This commit is contained in:
commit
bbdff6d583
@ -44,13 +44,16 @@ struct perf_event_attr;
|
||||
/* perf sample has 16 bits size limit */
|
||||
#define PERF_SAMPLE_MAX_SIZE (1 << 16)
|
||||
|
||||
/* number of register is bound by the number of bits in regs_dump::mask (64) */
|
||||
#define PERF_SAMPLE_REGS_CACHE_SIZE (8 * sizeof(u64))
|
||||
|
||||
struct regs_dump {
|
||||
u64 abi;
|
||||
u64 mask;
|
||||
u64 *regs;
|
||||
|
||||
/* Cached values/mask filled by first register access. */
|
||||
u64 cache_regs[PERF_REGS_MAX];
|
||||
u64 cache_regs[PERF_SAMPLE_REGS_CACHE_SIZE];
|
||||
u64 cache_mask;
|
||||
};
|
||||
|
||||
|
@ -1205,61 +1205,69 @@ out_no_progress:
|
||||
|
||||
static bool intel_pt_fup_event(struct intel_pt_decoder *decoder)
|
||||
{
|
||||
enum intel_pt_sample_type type = decoder->state.type;
|
||||
bool ret = false;
|
||||
|
||||
decoder->state.type &= ~INTEL_PT_BRANCH;
|
||||
|
||||
if (decoder->set_fup_tx_flags) {
|
||||
decoder->set_fup_tx_flags = false;
|
||||
decoder->tx_flags = decoder->fup_tx_flags;
|
||||
decoder->state.type = INTEL_PT_TRANSACTION;
|
||||
decoder->state.type |= INTEL_PT_TRANSACTION;
|
||||
if (decoder->fup_tx_flags & INTEL_PT_ABORT_TX)
|
||||
decoder->state.type |= INTEL_PT_BRANCH;
|
||||
decoder->state.from_ip = decoder->ip;
|
||||
decoder->state.to_ip = 0;
|
||||
decoder->state.flags = decoder->fup_tx_flags;
|
||||
return true;
|
||||
ret = true;
|
||||
}
|
||||
if (decoder->set_fup_ptw) {
|
||||
decoder->set_fup_ptw = false;
|
||||
decoder->state.type = INTEL_PT_PTW;
|
||||
decoder->state.type |= INTEL_PT_PTW;
|
||||
decoder->state.flags |= INTEL_PT_FUP_IP;
|
||||
decoder->state.from_ip = decoder->ip;
|
||||
decoder->state.to_ip = 0;
|
||||
decoder->state.ptw_payload = decoder->fup_ptw_payload;
|
||||
return true;
|
||||
ret = true;
|
||||
}
|
||||
if (decoder->set_fup_mwait) {
|
||||
decoder->set_fup_mwait = false;
|
||||
decoder->state.type = INTEL_PT_MWAIT_OP;
|
||||
decoder->state.from_ip = decoder->ip;
|
||||
decoder->state.to_ip = 0;
|
||||
decoder->state.type |= INTEL_PT_MWAIT_OP;
|
||||
decoder->state.mwait_payload = decoder->fup_mwait_payload;
|
||||
ret = true;
|
||||
}
|
||||
if (decoder->set_fup_pwre) {
|
||||
decoder->set_fup_pwre = false;
|
||||
decoder->state.type |= INTEL_PT_PWR_ENTRY;
|
||||
decoder->state.type &= ~INTEL_PT_BRANCH;
|
||||
decoder->state.from_ip = decoder->ip;
|
||||
decoder->state.to_ip = 0;
|
||||
decoder->state.pwre_payload = decoder->fup_pwre_payload;
|
||||
ret = true;
|
||||
}
|
||||
if (decoder->set_fup_exstop) {
|
||||
decoder->set_fup_exstop = false;
|
||||
decoder->state.type |= INTEL_PT_EX_STOP;
|
||||
decoder->state.type &= ~INTEL_PT_BRANCH;
|
||||
decoder->state.flags |= INTEL_PT_FUP_IP;
|
||||
decoder->state.from_ip = decoder->ip;
|
||||
decoder->state.to_ip = 0;
|
||||
ret = true;
|
||||
}
|
||||
if (decoder->set_fup_bep) {
|
||||
decoder->set_fup_bep = false;
|
||||
decoder->state.type |= INTEL_PT_BLK_ITEMS;
|
||||
decoder->state.type &= ~INTEL_PT_BRANCH;
|
||||
ret = true;
|
||||
}
|
||||
if (decoder->overflow) {
|
||||
decoder->overflow = false;
|
||||
if (!ret && !decoder->pge) {
|
||||
if (decoder->hop) {
|
||||
decoder->state.type = 0;
|
||||
decoder->pkt_state = INTEL_PT_STATE_RESAMPLE;
|
||||
}
|
||||
decoder->pge = true;
|
||||
decoder->state.type |= INTEL_PT_BRANCH | INTEL_PT_TRACE_BEGIN;
|
||||
decoder->state.from_ip = 0;
|
||||
decoder->state.to_ip = decoder->ip;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (ret) {
|
||||
decoder->state.from_ip = decoder->ip;
|
||||
decoder->state.to_ip = 0;
|
||||
ret = true;
|
||||
} else {
|
||||
decoder->state.type = type;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -1608,7 +1616,16 @@ static int intel_pt_overflow(struct intel_pt_decoder *decoder)
|
||||
intel_pt_clear_tx_flags(decoder);
|
||||
intel_pt_set_nr(decoder);
|
||||
decoder->timestamp_insn_cnt = 0;
|
||||
decoder->pkt_state = INTEL_PT_STATE_ERR_RESYNC;
|
||||
decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
|
||||
decoder->state.from_ip = decoder->ip;
|
||||
decoder->ip = 0;
|
||||
decoder->pge = false;
|
||||
decoder->set_fup_tx_flags = false;
|
||||
decoder->set_fup_ptw = false;
|
||||
decoder->set_fup_mwait = false;
|
||||
decoder->set_fup_pwre = false;
|
||||
decoder->set_fup_exstop = false;
|
||||
decoder->set_fup_bep = false;
|
||||
decoder->overflow = true;
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
@ -2666,6 +2683,8 @@ static int intel_pt_scan_for_psb(struct intel_pt_decoder *decoder);
|
||||
/* Hop mode: Ignore TNT, do not walk code, but get ip from FUPs and TIPs */
|
||||
static int intel_pt_hop_trace(struct intel_pt_decoder *decoder, bool *no_tip, int *err)
|
||||
{
|
||||
*err = 0;
|
||||
|
||||
/* Leap from PSB to PSB, getting ip from FUP within PSB+ */
|
||||
if (decoder->leap && !decoder->in_psb && decoder->packet.type != INTEL_PT_PSB) {
|
||||
*err = intel_pt_scan_for_psb(decoder);
|
||||
@ -2678,6 +2697,7 @@ static int intel_pt_hop_trace(struct intel_pt_decoder *decoder, bool *no_tip, in
|
||||
return HOP_IGNORE;
|
||||
|
||||
case INTEL_PT_TIP_PGD:
|
||||
decoder->pge = false;
|
||||
if (!decoder->packet.count) {
|
||||
intel_pt_set_nr(decoder);
|
||||
return HOP_IGNORE;
|
||||
@ -2705,18 +2725,21 @@ static int intel_pt_hop_trace(struct intel_pt_decoder *decoder, bool *no_tip, in
|
||||
if (!decoder->packet.count)
|
||||
return HOP_IGNORE;
|
||||
intel_pt_set_ip(decoder);
|
||||
if (intel_pt_fup_event(decoder))
|
||||
return HOP_RETURN;
|
||||
if (!decoder->branch_enable)
|
||||
if (decoder->set_fup_mwait || decoder->set_fup_pwre)
|
||||
*no_tip = true;
|
||||
if (!decoder->branch_enable || !decoder->pge)
|
||||
*no_tip = true;
|
||||
if (*no_tip) {
|
||||
decoder->state.type = INTEL_PT_INSTRUCTION;
|
||||
decoder->state.from_ip = decoder->ip;
|
||||
decoder->state.to_ip = 0;
|
||||
intel_pt_fup_event(decoder);
|
||||
return HOP_RETURN;
|
||||
}
|
||||
intel_pt_fup_event(decoder);
|
||||
decoder->state.type |= INTEL_PT_INSTRUCTION | INTEL_PT_BRANCH;
|
||||
*err = intel_pt_walk_fup_tip(decoder);
|
||||
if (!*err)
|
||||
if (!*err && decoder->state.to_ip)
|
||||
decoder->pkt_state = INTEL_PT_STATE_RESAMPLE;
|
||||
return HOP_RETURN;
|
||||
|
||||
@ -2897,7 +2920,7 @@ static bool intel_pt_psb_with_fup(struct intel_pt_decoder *decoder, int *err)
|
||||
{
|
||||
struct intel_pt_psb_info data = { .fup = false };
|
||||
|
||||
if (!decoder->branch_enable || !decoder->pge)
|
||||
if (!decoder->branch_enable)
|
||||
return false;
|
||||
|
||||
intel_pt_pkt_lookahead(decoder, intel_pt_psb_lookahead_cb, &data);
|
||||
@ -2924,6 +2947,7 @@ static int intel_pt_walk_trace(struct intel_pt_decoder *decoder)
|
||||
if (err)
|
||||
return err;
|
||||
next:
|
||||
err = 0;
|
||||
if (decoder->cyc_threshold) {
|
||||
if (decoder->sample_cyc && last_packet_type != INTEL_PT_CYC)
|
||||
decoder->sample_cyc = false;
|
||||
@ -2962,6 +2986,7 @@ next:
|
||||
|
||||
case INTEL_PT_TIP_PGE: {
|
||||
decoder->pge = true;
|
||||
decoder->overflow = false;
|
||||
intel_pt_mtc_cyc_cnt_pge(decoder);
|
||||
intel_pt_set_nr(decoder);
|
||||
if (decoder->packet.count == 0) {
|
||||
@ -2999,7 +3024,7 @@ next:
|
||||
break;
|
||||
}
|
||||
intel_pt_set_last_ip(decoder);
|
||||
if (!decoder->branch_enable) {
|
||||
if (!decoder->branch_enable || !decoder->pge) {
|
||||
decoder->ip = decoder->last_ip;
|
||||
if (intel_pt_fup_event(decoder))
|
||||
return 0;
|
||||
@ -3467,10 +3492,10 @@ static int intel_pt_sync_ip(struct intel_pt_decoder *decoder)
|
||||
decoder->set_fup_pwre = false;
|
||||
decoder->set_fup_exstop = false;
|
||||
decoder->set_fup_bep = false;
|
||||
decoder->overflow = false;
|
||||
|
||||
if (!decoder->branch_enable) {
|
||||
decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
|
||||
decoder->overflow = false;
|
||||
decoder->state.type = 0; /* Do not have a sample */
|
||||
return 0;
|
||||
}
|
||||
@ -3485,7 +3510,6 @@ static int intel_pt_sync_ip(struct intel_pt_decoder *decoder)
|
||||
decoder->pkt_state = INTEL_PT_STATE_RESAMPLE;
|
||||
else
|
||||
decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
|
||||
decoder->overflow = false;
|
||||
|
||||
decoder->state.from_ip = 0;
|
||||
decoder->state.to_ip = decoder->ip;
|
||||
@ -3607,7 +3631,7 @@ static int intel_pt_sync(struct intel_pt_decoder *decoder)
|
||||
}
|
||||
|
||||
decoder->have_last_ip = true;
|
||||
decoder->pkt_state = INTEL_PT_STATE_NO_IP;
|
||||
decoder->pkt_state = INTEL_PT_STATE_IN_SYNC;
|
||||
|
||||
err = intel_pt_walk_psb(decoder);
|
||||
if (err)
|
||||
@ -3704,7 +3728,8 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder)
|
||||
|
||||
if (err) {
|
||||
decoder->state.err = intel_pt_ext_err(err);
|
||||
decoder->state.from_ip = decoder->ip;
|
||||
if (err != -EOVERFLOW)
|
||||
decoder->state.from_ip = decoder->ip;
|
||||
intel_pt_update_sample_time(decoder);
|
||||
decoder->sample_tot_cyc_cnt = decoder->tot_cyc_cnt;
|
||||
intel_pt_set_nr(decoder);
|
||||
|
@ -2565,6 +2565,7 @@ static int intel_pt_run_decoder(struct intel_pt_queue *ptq, u64 *timestamp)
|
||||
ptq->sync_switch = false;
|
||||
intel_pt_next_tid(pt, ptq);
|
||||
}
|
||||
ptq->timestamp = state->est_timestamp;
|
||||
if (pt->synth_opts.errors) {
|
||||
err = intel_ptq_synth_error(ptq, state);
|
||||
if (err)
|
||||
|
@ -25,6 +25,9 @@ int perf_reg_value(u64 *valp, struct regs_dump *regs, int id)
|
||||
int i, idx = 0;
|
||||
u64 mask = regs->mask;
|
||||
|
||||
if ((u64)id >= PERF_SAMPLE_REGS_CACHE_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
if (regs->cache_mask & (1ULL << id))
|
||||
goto out;
|
||||
|
||||
|
@ -461,7 +461,7 @@ get_tracepoint_field(struct pyrf_event *pevent, PyObject *attr_name)
|
||||
struct tep_event *tp_format;
|
||||
|
||||
tp_format = trace_event__tp_format_id(evsel->core.attr.config);
|
||||
if (!tp_format)
|
||||
if (IS_ERR_OR_NULL(tp_format))
|
||||
return NULL;
|
||||
|
||||
evsel->tp_format = tp_format;
|
||||
|
Loading…
Reference in New Issue
Block a user