Unverified Commit 95ce3ab2 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!3577 perf/core: Fix CVE-2023-6931

Merge Pull Request from: @ci-robot 
 
PR sync from: Yang Jihong <yangjihong1@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/KN7GASKE4UDSAEOGGBD3JFF64T2BOTET/ 
Mark Rutland (1):
  perf: Fix perf_event_validate_size() lockdep splat

Peter Zijlstra (1):
  perf: Fix perf_event_validate_size()


-- 
2.34.1
 
https://gitee.com/src-openeuler/kernel/issues/I8PT55 
 
Link:https://gitee.com/openeuler/kernel/pulls/3577

 

Reviewed-by: default avatarXu Kuohai <xukuohai@huawei.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parents ddadd420 8a9977c1
Loading
Loading
Loading
Loading
+46 −21
Original line number Diff line number Diff line
@@ -1826,28 +1826,31 @@ static inline void perf_event__state_init(struct perf_event *event)
					      PERF_EVENT_STATE_INACTIVE;
}

static void __perf_event_read_size(struct perf_event *event, int nr_siblings)
static int __perf_event_read_size(u64 read_format, int nr_siblings)
{
	int entry = sizeof(u64); /* value */
	int size = 0;
	int nr = 1;

	if (event->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
	if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
		size += sizeof(u64);

	if (event->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
	if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
		size += sizeof(u64);

	if (event->attr.read_format & PERF_FORMAT_ID)
	if (read_format & PERF_FORMAT_ID)
		entry += sizeof(u64);

	if (event->attr.read_format & PERF_FORMAT_GROUP) {
	if (read_format & PERF_FORMAT_GROUP) {
		nr += nr_siblings;
		size += sizeof(u64);
	}

	size += entry * nr;
	event->read_size = size;
	/*
	 * Since perf_event_validate_size() limits this to 16k and inhibits
	 * adding more siblings, this will never overflow.
	 */
	return size + nr * entry;
}

static void __perf_event_header_size(struct perf_event *event, u64 sample_type)
@@ -1891,7 +1894,8 @@ static void __perf_event_header_size(struct perf_event *event, u64 sample_type)
 */
static void perf_event__header_size(struct perf_event *event)
{
	__perf_event_read_size(event,
	event->read_size =
		__perf_event_read_size(event->attr.read_format,
				       event->group_leader->nr_siblings);
	__perf_event_header_size(event, event->attr.sample_type);
}
@@ -1923,23 +1927,44 @@ static void perf_event__id_header_size(struct perf_event *event)
	event->id_header_size = size;
}

static bool perf_event_validate_size(struct perf_event *event)
{
/*
	 * The values computed here will be over-written when we actually
	 * attach the event.
 * Check that adding an event to the group does not result in anybody
 * overflowing the 64k event limit imposed by the output buffer.
 *
 * Specifically, check that the read_size for the event does not exceed 16k,
 * read_size being the one term that grows with groups size. Since read_size
 * depends on per-event read_format, also (re)check the existing events.
 *
 * This leaves 48k for the constant size fields and things like callchains,
 * branch stacks and register sets.
 */
	__perf_event_read_size(event, event->group_leader->nr_siblings + 1);
	__perf_event_header_size(event, event->attr.sample_type & ~PERF_SAMPLE_READ);
	perf_event__id_header_size(event);
static bool perf_event_validate_size(struct perf_event *event)
{
	struct perf_event *sibling, *group_leader = event->group_leader;

	if (__perf_event_read_size(event->attr.read_format,
				   group_leader->nr_siblings + 1) > 16*1024)
		return false;

	if (__perf_event_read_size(group_leader->attr.read_format,
				   group_leader->nr_siblings + 1) > 16*1024)
		return false;

	/*
	 * Sum the lot; should not exceed the 64k limit we have on records.
	 * Conservative limit to allow for callchains and other variable fields.
	 * When creating a new group leader, group_leader->ctx is initialized
	 * after the size has been validated, but we cannot safely use
	 * for_each_sibling_event() until group_leader->ctx is set. A new group
	 * leader cannot have any siblings yet, so we can safely skip checking
	 * the non-existent siblings.
	 */
	if (event->read_size + event->header_size +
	    event->id_header_size + sizeof(struct perf_event_header) >= 16*1024)
	if (event == group_leader)
		return true;

	for_each_sibling_event(sibling, group_leader) {
		if (__perf_event_read_size(sibling->attr.read_format,
					   group_leader->nr_siblings + 1) > 16*1024)
			return false;
	}

	return true;
}