Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 01a4672a authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Reapply "perf: Fix perf_event_validate_size()"



This reverts commit aa6c8427 which is
commit 382c27f4ed28f803b1f1473ac2d8db0afc795a1b upstream.

Bug: 316932704
Change-Id: I69bfbf5180f57592ce285ea14f6f7b7c1b2b0f8f
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent 5a194b81
Loading
Loading
Loading
Loading
+37 −22
Original line number Original line Diff line number Diff line
@@ -1710,28 +1710,31 @@ static inline void perf_event__state_init(struct perf_event *event)
					      PERF_EVENT_STATE_INACTIVE;
					      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 entry = sizeof(u64); /* value */
	int size = 0;
	int size = 0;
	int nr = 1;
	int nr = 1;


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


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


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


	if (event->attr.read_format & PERF_FORMAT_GROUP) {
	if (read_format & PERF_FORMAT_GROUP) {
		nr += nr_siblings;
		nr += nr_siblings;
		size += sizeof(u64);
		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)
static void __perf_event_header_size(struct perf_event *event, u64 sample_type)
@@ -1772,7 +1775,8 @@ static void __perf_event_header_size(struct perf_event *event, u64 sample_type)
 */
 */
static void perf_event__header_size(struct perf_event *event)
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);
				       event->group_leader->nr_siblings);
	__perf_event_header_size(event, event->attr.sample_type);
	__perf_event_header_size(event, event->attr.sample_type);
}
}
@@ -1804,24 +1808,35 @@ static void perf_event__id_header_size(struct perf_event *event)
	event->id_header_size = size;
	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
 * Check that adding an event to the group does not result in anybody
	 * attach the event.
 * 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);
static bool perf_event_validate_size(struct perf_event *event)
	__perf_event_header_size(event, event->attr.sample_type & ~PERF_SAMPLE_READ);
{
	perf_event__id_header_size(event);
	struct perf_event *sibling, *group_leader = event->group_leader;


	/*
	if (__perf_event_read_size(event->attr.read_format,
	 * Sum the lot; should not exceed the 64k limit we have on records.
				   group_leader->nr_siblings + 1) > 16*1024)
	 * Conservative limit to allow for callchains and other variable fields.
		return false;
	 */

	if (event->read_size + event->header_size +
	if (__perf_event_read_size(group_leader->attr.read_format,
	    event->id_header_size + sizeof(struct perf_event_header) >= 16*1024)
				   group_leader->nr_siblings + 1) > 16*1024)
		return false;
		return false;


	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;
	return true;
}
}