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 <[email protected]> --- .../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

