Skip to content

Commit 537ccb5

Browse files
committed
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()
2 parents 5412fed + 382c27f commit 537ccb5

File tree

1 file changed

+38
-23
lines changed

1 file changed

+38
-23
lines changed

kernel/events/core.c

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1814,31 +1814,34 @@ static inline void perf_event__state_init(struct perf_event *event)
18141814
PERF_EVENT_STATE_INACTIVE;
18151815
}
18161816

1817-
static void __perf_event_read_size(struct perf_event *event, int nr_siblings)
1817+
static int __perf_event_read_size(u64 read_format, int nr_siblings)
18181818
{
18191819
int entry = sizeof(u64); /* value */
18201820
int size = 0;
18211821
int nr = 1;
18221822

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

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

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

1832-
if (event->attr.read_format & PERF_FORMAT_LOST)
1832+
if (read_format & PERF_FORMAT_LOST)
18331833
entry += sizeof(u64);
18341834

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

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

18441847
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)
18881891
*/
18891892
static void perf_event__header_size(struct perf_event *event)
18901893
{
1891-
__perf_event_read_size(event,
1892-
event->group_leader->nr_siblings);
1894+
event->read_size =
1895+
__perf_event_read_size(event->attr.read_format,
1896+
event->group_leader->nr_siblings);
18931897
__perf_event_header_size(event, event->attr.sample_type);
18941898
}
18951899

@@ -1920,24 +1924,35 @@ static void perf_event__id_header_size(struct perf_event *event)
19201924
event->id_header_size = size;
19211925
}
19221926

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

1933-
/*
1934-
* Sum the lot; should not exceed the 64k limit we have on records.
1935-
* Conservative limit to allow for callchains and other variable fields.
1936-
*/
1937-
if (event->read_size + event->header_size +
1938-
event->id_header_size + sizeof(struct perf_event_header) >= 16*1024)
1942+
if (__perf_event_read_size(event->attr.read_format,
1943+
group_leader->nr_siblings + 1) > 16*1024)
19391944
return false;
19401945

1946+
if (__perf_event_read_size(group_leader->attr.read_format,
1947+
group_leader->nr_siblings + 1) > 16*1024)
1948+
return false;
1949+
1950+
for_each_sibling_event(sibling, group_leader) {
1951+
if (__perf_event_read_size(sibling->attr.read_format,
1952+
group_leader->nr_siblings + 1) > 16*1024)
1953+
return false;
1954+
}
1955+
19411956
return true;
19421957
}
19431958

0 commit comments

Comments
 (0)