[PATCH] selftests/perf_events: test text_poke permissions
From: Sahaj Chaudhari
Date: Wed Oct 07 2026 - 02:56:14 EST
Verify that a privileged task can open a text-poke perf event while an
unprivileged task is denied.
Skip if text-poke is unsupported or perf settings prevent the check.
Signed-off-by: Sahaj Chaudhari <sahaj123.sc@xxxxxxxxx>
---
.../testing/selftests/perf_events/.gitignore | 1 +
tools/testing/selftests/perf_events/Makefile | 2 +-
.../perf_events/text_poke_permissions.c | 99 +++++++++++++++++++
3 files changed, 101 insertions(+), 1 deletion(-)
create mode 100644 tools/testing/selftests/perf_events/text_poke_permissions.c
diff --git a/tools/testing/selftests/perf_events/.gitignore b/tools/testing/selftests/perf_events/.gitignore
index 4931b3b6bbd39..2a475f176feed 100644
--- a/tools/testing/selftests/perf_events/.gitignore
+++ b/tools/testing/selftests/perf_events/.gitignore
@@ -3,3 +3,4 @@ sigtrap_threads
remove_on_exec
watermark_signal
mmap
+text_poke_permissions
diff --git a/tools/testing/selftests/perf_events/Makefile b/tools/testing/selftests/perf_events/Makefile
index 2e5d85770dfea..02aa6e7c6e9a2 100644
--- a/tools/testing/selftests/perf_events/Makefile
+++ b/tools/testing/selftests/perf_events/Makefile
@@ -2,5 +2,5 @@
CFLAGS += -Wl,-no-as-needed -Wall $(KHDR_INCLUDES)
LDFLAGS += -lpthread
-TEST_GEN_PROGS := sigtrap_threads remove_on_exec watermark_signal mmap
+TEST_GEN_PROGS := sigtrap_threads remove_on_exec watermark_signal mmap text_poke_permissions
include ../lib.mk
diff --git a/tools/testing/selftests/perf_events/text_poke_permissions.c b/tools/testing/selftests/perf_events/text_poke_permissions.c
new file mode 100644
index 0000000000000..c42af32c32c4d
--- /dev/null
+++ b/tools/testing/selftests/perf_events/text_poke_permissions.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/perf_event.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "kselftest.h"
+
+static int perf_event_open_text_poke(void)
+{
+ struct perf_event_attr attr = {
+ .type = PERF_TYPE_SOFTWARE,
+ .size = sizeof(attr),
+ .config = PERF_COUNT_SW_CPU_CLOCK,
+ .disabled = 1,
+ .exclude_kernel = 1,
+ .text_poke = 1,
+ };
+
+ return syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0);
+}
+
+static int read_perf_paranoid(int *value)
+{
+ FILE *file;
+
+ file = fopen("/proc/sys/kernel/perf_event_paranoid", "r");
+ if (!file)
+ return -1;
+
+ if (fscanf(file, "%d", value) != 1) {
+ fclose(file);
+ return -1;
+ }
+ fclose(file);
+ return 0;
+}
+
+int main(void)
+{
+ pid_t child;
+ int fd, status, paranoid;
+
+ ksft_print_header();
+ if (geteuid() != 0)
+ ksft_exit_skip("run as root to verify the unprivileged permission check\n");
+
+ if (read_perf_paranoid(¶noid))
+ ksft_exit_skip("cannot read perf_event_paranoid\n");
+ if (paranoid <= 1)
+ ksft_exit_skip("perf_event_paranoid must be greater than 1\n");
+
+ fd = perf_event_open_text_poke();
+ if (fd < 0) {
+ if (errno == EINVAL || errno == E2BIG)
+ ksft_exit_skip("kernel does not support perf text-poke events\n");
+ if (errno == EACCES || errno == EPERM)
+ ksft_exit_skip("root cannot open the probe perf event\n");
+ ksft_exit_fail_perror("perf_event_open probe");
+ }
+ close(fd);
+
+ ksft_set_plan(1);
+ child = fork();
+ if (child < 0)
+ ksft_exit_fail_perror("fork");
+ if (child == 0) {
+ if (setgid(65534) || setuid(65534))
+ _exit(2);
+ fd = perf_event_open_text_poke();
+ if (fd >= 0) {
+ close(fd);
+ _exit(0);
+ }
+ if (errno == EACCES || errno == EPERM)
+ _exit(1);
+ _exit(2);
+ }
+
+ if (waitpid(child, &status, 0) != child)
+ ksft_exit_fail_perror("waitpid");
+ if (!WIFEXITED(status))
+ ksft_test_result_fail("permission-check child did not exit normally\n");
+ else if (WEXITSTATUS(status) == 1)
+ ksft_test_result_pass("unprivileged text-poke perf event is denied\n");
+ else if (WEXITSTATUS(status) == 0)
+ ksft_test_result_fail("unprivileged task opened a text-poke perf event\n");
+ else
+ ksft_test_result_fail("child failed to test text-poke permissions\n");
+
+ ksft_finished();
+}
--
2.43.0