mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-24 04:34:08 +08:00
- Make sure perf event size validation is done on every event in the
group -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEzv7L6UO9uDPlPSfHEsHwGGHeVUoFAmV1mfQACgkQEsHwGGHe VUrW9w/9EVMf1/cu1rY4XN68NbOgdfoic2oPan60WJwiYhYto9uA1quR4Q8ziwVh UbuO4e0up1ZCUzutZGFnx0ZHrlQIb0/YTQj8kDKX6m7g8s2Vers7YbkRwneDsNqA JDp58yGXdc1TipVYrKqa0leNrezvaEeoVFPIPKoelzi3673xrlslRseJ/n7vJd4u SnMjT7LQZIlEe/pecz01nHAo6SSwfI/Ynh2WSorHnhSTuE5gMUzJwBYSXvpZ2gyg 207keTiIcrvxgT+a32NMeEYsFFFvpYKFHI5nxxV1pB8AWXdWaNpuYHNItTDIh81D fSb8hu+EpNSWtZYzXl/esgULfMgHXez+4VknTpX/vsbfcV1Yif4aHlZP8tgP6gZ5 QyA2NMA5vJypjzLsAgCyZjpTyEVPYQ3f4+iYg4EGlMlgLgoXtHIV+zP765SzDVkC yPO4xVf+Ypo9AKcGKjBrxyMlRq40zos40k6l2yOjSUlTE2IfOLMhjgVHeLcgD+uv E9pi0/KtfGvrm3nWgIhDtcvd5Jg6vrilaRWl9bAN6g6xgaqLPXuIZbOjPaRpKSNa L32XBMg5fUt4eesZv458qu4Zw1ybHCd6qoe3OieFzW5ocR61O946MHX3kkbpmsWC PzH1mBsPa3F8/utJ06p+9pank3M5yKHdkDPQXfSvImuZ3DPKEGI= =QxHj -----END PGP SIGNATURE----- Merge tag 'perf_urgent_for_v6.7_rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull perf event fix from Borislav Petkov: - Make sure perf event size validation is done on every event in the group * tag 'perf_urgent_for_v6.7_rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: perf: Fix perf_event_validate_size()
This commit is contained in:
commit
537ccb5d28
@ -1814,31 +1814,34 @@ 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_LOST)
|
||||
if (read_format & PERF_FORMAT_LOST)
|
||||
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)
|
||||
@ -1888,8 +1891,9 @@ 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->group_leader->nr_siblings);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1920,24 +1924,35 @@ static void perf_event__id_header_size(struct perf_event *event)
|
||||
event->id_header_size = size;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
static bool perf_event_validate_size(struct perf_event *event)
|
||||
{
|
||||
/*
|
||||
* The values computed here will be over-written when we actually
|
||||
* attach the event.
|
||||
*/
|
||||
__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);
|
||||
struct perf_event *sibling, *group_leader = event->group_leader;
|
||||
|
||||
/*
|
||||
* Sum the lot; should not exceed the 64k limit we have on records.
|
||||
* Conservative limit to allow for callchains and other variable fields.
|
||||
*/
|
||||
if (event->read_size + event->header_size +
|
||||
event->id_header_size + sizeof(struct perf_event_header) >= 16*1024)
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user