From nobody Tue Dec 16 16:41:23 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E0465C4167B for ; Thu, 30 Nov 2023 13:28:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345540AbjK3N2W (ORCPT ); Thu, 30 Nov 2023 08:28:22 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37174 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232169AbjK3N2T (ORCPT ); Thu, 30 Nov 2023 08:28:19 -0500 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 24A32D6C; Thu, 30 Nov 2023 05:28:25 -0800 (PST) Date: Thu, 30 Nov 2023 13:28:22 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1701350903; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=mOpN8Iak2/OJw05hoCr+GK2iIlc++ht5sIA0P0Wo5cg=; b=f6K4ws7QVU4nznJOytCRVktEIpwL4LNXK9dmPw7I9wNMqPLoRR4b4bCvjScWfz2BbVCzKp nG+NHGAr0ma6g5RRwqcmT59JbD03TZHLUL/Xt9t7BbEHveHRtX2fyryMMmkrl6ucbGOad/ 7Myhv1BR7dQ1Sq7ncW05PLKU/m4AhXn8FNWzfzStmgDFVWwf2dheqodf12x9D8yVgfsaHC +EOlgt/97wt4KTv9xTMTx40oRaSOpoMlKSNt2O2lN+oWuFtEpkKVlIThtwfvbJkyPeTRtW yVOPyq3zRZqrJV6XJDLEnexL/K032sOBQcvcHiAPJb95IElN5aTmh2VeJk0TAg== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1701350903; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=mOpN8Iak2/OJw05hoCr+GK2iIlc++ht5sIA0P0Wo5cg=; b=Y6PpYNDXabZvv6HzS1CME6T/8rs8zDdZnHwfvwt5iQprAaD74fqI4UUlcChCIxnMHN0ZNE NEi/XFktlt3yWJBg== From: "tip-bot2 for Peter Zijlstra" Sender: tip-bot2@linutronix.de Reply-to: linux-kernel@vger.kernel.org To: linux-tip-commits@vger.kernel.org Subject: [tip: perf/urgent] perf: Fix perf_event_validate_size() Cc: Budimir Markovic , "Peter Zijlstra (Intel)" , x86@kernel.org, linux-kernel@vger.kernel.org MIME-Version: 1.0 Message-ID: <170135090300.398.16580844443906542392.tip-bot2@tip-bot2> Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The following commit has been merged into the perf/urgent branch of tip: Commit-ID: 382c27f4ed28f803b1f1473ac2d8db0afc795a1b Gitweb: https://git.kernel.org/tip/382c27f4ed28f803b1f1473ac2d8db0af= c795a1b Author: Peter Zijlstra AuthorDate: Wed, 29 Nov 2023 15:24:52 +01:00 Committer: Peter Zijlstra CommitterDate: Wed, 29 Nov 2023 15:43:50 +01:00 perf: Fix perf_event_validate_size() Budimir noted that perf_event_validate_size() only checks the size of the newly added event, even though the sizes of all existing events can also change due to not all events having the same read_format. When we attach the new event, perf_group_attach(), we do re-compute the size for all events. Fixes: a723968c0ed3 ("perf: Fix u16 overflows") Reported-by: Budimir Markovic Signed-off-by: Peter Zijlstra (Intel) --- kernel/events/core.c | 61 ++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index b704d83..c9d123e 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -1814,31 +1814,34 @@ static inline void perf_event__state_init(struct pe= rf_event *event) PERF_EVENT_STATE_INACTIVE; } =20 -static void __perf_event_read_size(struct perf_event *event, int nr_siblin= gs) +static int __perf_event_read_size(u64 read_format, int nr_siblings) { int entry =3D sizeof(u64); /* value */ int size =3D 0; int nr =3D 1; =20 - if (event->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) + if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) size +=3D sizeof(u64); =20 - if (event->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) + if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) size +=3D sizeof(u64); =20 - if (event->attr.read_format & PERF_FORMAT_ID) + if (read_format & PERF_FORMAT_ID) entry +=3D sizeof(u64); =20 - if (event->attr.read_format & PERF_FORMAT_LOST) + if (read_format & PERF_FORMAT_LOST) entry +=3D sizeof(u64); =20 - if (event->attr.read_format & PERF_FORMAT_GROUP) { + if (read_format & PERF_FORMAT_GROUP) { nr +=3D nr_siblings; size +=3D sizeof(u64); } =20 - size +=3D entry * nr; - event->read_size =3D size; + /* + * Since perf_event_validate_size() limits this to 16k and inhibits + * adding more siblings, this will never overflow. + */ + return size + nr * entry; } =20 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_even= t *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 =3D + __perf_event_read_size(event->attr.read_format, + event->group_leader->nr_siblings); __perf_event_header_size(event, event->attr.sample_type); } =20 @@ -1920,24 +1924,35 @@ static void perf_event__id_header_size(struct perf_= event *event) event->id_header_size =3D size; } =20 +/* + * 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 16= k, + * read_size being the one term that grows with groups size. Since read_si= ze + * 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_RE= AD); - perf_event__id_header_size(event); + struct perf_event *sibling, *group_leader =3D event->group_leader; =20 - /* - * 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) >=3D 16*1024) + if (__perf_event_read_size(event->attr.read_format, + group_leader->nr_siblings + 1) > 16*1024) return false; =20 + 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; }