Commit bbdff6d5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'perf-tools-fixes-for-v5.16-2021-12-11' of...

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
parents eccea80b 9937e8da
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -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;
};

+55 −30
Original line number Diff line number Diff line
@@ -1205,61 +1205,69 @@ static int intel_pt_walk_insn(struct intel_pt_decoder *decoder,

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 @@ static int intel_pt_walk_trace(struct intel_pt_decoder *decoder)

		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 @@ static int intel_pt_walk_trace(struct intel_pt_decoder *decoder)
				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,6 +3728,7 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder)

	if (err) {
		decoder->state.err = intel_pt_ext_err(err);
		if (err != -EOVERFLOW)
			decoder->state.from_ip = decoder->ip;
		intel_pt_update_sample_time(decoder);
		decoder->sample_tot_cyc_cnt = decoder->tot_cyc_cnt;
+1 −0
Original line number Diff line number Diff line
@@ -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)
+3 −0
Original line number Diff line number Diff line
@@ -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;

+1 −1
Original line number Diff line number Diff line
@@ -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;