Skip to content

Commit a723968

Browse files
Peter ZijlstraIngo Molnar
authored andcommitted
perf: Fix u16 overflows
Vince reported that its possible to overflow the various size fields and get weird stuff if you stick too many events in a group. Put a lid on this by requiring the fixed record size not exceed 16k. This is still a fair amount of events (silly amount really) and leaves plenty room for callchains and stack dwarves while also avoiding overflowing the u16 variables. Reported-by: Vince Weaver <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: [email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent f55fc2a commit a723968

File tree

1 file changed

+40
-10
lines changed

1 file changed

+40
-10
lines changed

kernel/events/core.c

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,11 +1243,7 @@ static inline void perf_event__state_init(struct perf_event *event)
12431243
PERF_EVENT_STATE_INACTIVE;
12441244
}
12451245

1246-
/*
1247-
* Called at perf_event creation and when events are attached/detached from a
1248-
* group.
1249-
*/
1250-
static void perf_event__read_size(struct perf_event *event)
1246+
static void __perf_event_read_size(struct perf_event *event, int nr_siblings)
12511247
{
12521248
int entry = sizeof(u64); /* value */
12531249
int size = 0;
@@ -1263,22 +1259,19 @@ static void perf_event__read_size(struct perf_event *event)
12631259
entry += sizeof(u64);
12641260

12651261
if (event->attr.read_format & PERF_FORMAT_GROUP) {
1266-
nr += event->group_leader->nr_siblings;
1262+
nr += nr_siblings;
12671263
size += sizeof(u64);
12681264
}
12691265

12701266
size += entry * nr;
12711267
event->read_size = size;
12721268
}
12731269

1274-
static void perf_event__header_size(struct perf_event *event)
1270+
static void __perf_event_header_size(struct perf_event *event, u64 sample_type)
12751271
{
12761272
struct perf_sample_data *data;
1277-
u64 sample_type = event->attr.sample_type;
12781273
u16 size = 0;
12791274

1280-
perf_event__read_size(event);
1281-
12821275
if (sample_type & PERF_SAMPLE_IP)
12831276
size += sizeof(data->ip);
12841277

@@ -1303,6 +1296,17 @@ static void perf_event__header_size(struct perf_event *event)
13031296
event->header_size = size;
13041297
}
13051298

1299+
/*
1300+
* Called at perf_event creation and when events are attached/detached from a
1301+
* group.
1302+
*/
1303+
static void perf_event__header_size(struct perf_event *event)
1304+
{
1305+
__perf_event_read_size(event,
1306+
event->group_leader->nr_siblings);
1307+
__perf_event_header_size(event, event->attr.sample_type);
1308+
}
1309+
13061310
static void perf_event__id_header_size(struct perf_event *event)
13071311
{
13081312
struct perf_sample_data *data;
@@ -1330,6 +1334,27 @@ static void perf_event__id_header_size(struct perf_event *event)
13301334
event->id_header_size = size;
13311335
}
13321336

1337+
static bool perf_event_validate_size(struct perf_event *event)
1338+
{
1339+
/*
1340+
* The values computed here will be over-written when we actually
1341+
* attach the event.
1342+
*/
1343+
__perf_event_read_size(event, event->group_leader->nr_siblings + 1);
1344+
__perf_event_header_size(event, event->attr.sample_type & ~PERF_SAMPLE_READ);
1345+
perf_event__id_header_size(event);
1346+
1347+
/*
1348+
* Sum the lot; should not exceed the 64k limit we have on records.
1349+
* Conservative limit to allow for callchains and other variable fields.
1350+
*/
1351+
if (event->read_size + event->header_size +
1352+
event->id_header_size + sizeof(struct perf_event_header) >= 16*1024)
1353+
return false;
1354+
1355+
return true;
1356+
}
1357+
13331358
static void perf_group_attach(struct perf_event *event)
13341359
{
13351360
struct perf_event *group_leader = event->group_leader, *pos;
@@ -8302,6 +8327,11 @@ SYSCALL_DEFINE5(perf_event_open,
83028327
mutex_lock(&ctx->mutex);
83038328
}
83048329

8330+
if (!perf_event_validate_size(event)) {
8331+
err = -E2BIG;
8332+
goto err_locked;
8333+
}
8334+
83058335
/*
83068336
* Must be under the same ctx::mutex as perf_install_in_context(),
83078337
* because we need to serialize with concurrent event creation.

0 commit comments

Comments
 (0)