summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/openat2/rename_attack_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/testing/selftests/openat2/rename_attack_test.c')
-rw-r--r--tools/testing/selftests/openat2/rename_attack_test.c160
1 files changed, 0 insertions, 160 deletions
diff --git a/tools/testing/selftests/openat2/rename_attack_test.c b/tools/testing/selftests/openat2/rename_attack_test.c
deleted file mode 100644
index 0a770728b436..000000000000
--- a/tools/testing/selftests/openat2/rename_attack_test.c
+++ /dev/null
@@ -1,160 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Author: Aleksa Sarai <cyphar@cyphar.com>
- * Copyright (C) 2018-2019 SUSE LLC.
- */
-
-#define _GNU_SOURCE
-#include <errno.h>
-#include <fcntl.h>
-#include <sched.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/mount.h>
-#include <sys/mman.h>
-#include <sys/prctl.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <string.h>
-#include <syscall.h>
-#include <limits.h>
-#include <unistd.h>
-
-#include "../kselftest.h"
-#include "helpers.h"
-
-/* Construct a test directory with the following structure:
- *
- * root/
- * |-- a/
- * | `-- c/
- * `-- b/
- */
-int setup_testdir(void)
-{
- int dfd;
- char dirname[] = "/tmp/ksft-openat2-rename-attack.XXXXXX";
-
- /* Make the top-level directory. */
- if (!mkdtemp(dirname))
- ksft_exit_fail_msg("setup_testdir: failed to create tmpdir\n");
- dfd = open(dirname, O_PATH | O_DIRECTORY);
- if (dfd < 0)
- ksft_exit_fail_msg("setup_testdir: failed to open tmpdir\n");
-
- E_mkdirat(dfd, "a", 0755);
- E_mkdirat(dfd, "b", 0755);
- E_mkdirat(dfd, "a/c", 0755);
-
- return dfd;
-}
-
-/* Swap @dirfd/@a and @dirfd/@b constantly. Parent must kill this process. */
-pid_t spawn_attack(int dirfd, char *a, char *b)
-{
- pid_t child = fork();
- if (child != 0)
- return child;
-
- /* If the parent (the test process) dies, kill ourselves too. */
- E_prctl(PR_SET_PDEATHSIG, SIGKILL);
-
- /* Swap @a and @b. */
- for (;;)
- renameat2(dirfd, a, dirfd, b, RENAME_EXCHANGE);
- exit(1);
-}
-
-#define NUM_RENAME_TESTS 2
-#define ROUNDS 400000
-
-const char *flagname(int resolve)
-{
- switch (resolve) {
- case RESOLVE_IN_ROOT:
- return "RESOLVE_IN_ROOT";
- case RESOLVE_BENEATH:
- return "RESOLVE_BENEATH";
- }
- return "(unknown)";
-}
-
-void test_rename_attack(int resolve)
-{
- int dfd, afd;
- pid_t child;
- void (*resultfn)(const char *msg, ...) = ksft_test_result_pass;
- int escapes = 0, other_errs = 0, exdevs = 0, eagains = 0, successes = 0;
-
- struct open_how how = {
- .flags = O_PATH,
- .resolve = resolve,
- };
-
- if (!openat2_supported) {
- how.resolve = 0;
- ksft_print_msg("openat2(2) unsupported -- using openat(2) instead\n");
- }
-
- dfd = setup_testdir();
- afd = openat(dfd, "a", O_PATH);
- if (afd < 0)
- ksft_exit_fail_msg("test_rename_attack: failed to open 'a'\n");
-
- child = spawn_attack(dfd, "a/c", "b");
-
- for (int i = 0; i < ROUNDS; i++) {
- int fd;
- char *victim_path = "c/../../c/../../c/../../c/../../c/../../c/../../c/../../c/../../c/../../c/../../c/../../c/../../c/../../c/../../c/../../c/../../c/../../c/../../c/../..";
-
- if (openat2_supported)
- fd = sys_openat2(afd, victim_path, &how);
- else
- fd = sys_openat(afd, victim_path, &how);
-
- if (fd < 0) {
- if (fd == -EAGAIN)
- eagains++;
- else if (fd == -EXDEV)
- exdevs++;
- else if (fd == -ENOENT)
- escapes++; /* escaped outside and got ENOENT... */
- else
- other_errs++; /* unexpected error */
- } else {
- if (fdequal(fd, afd, NULL))
- successes++;
- else
- escapes++; /* we got an unexpected fd */
- }
- close(fd);
- }
-
- if (escapes > 0)
- resultfn = ksft_test_result_fail;
- ksft_print_msg("non-escapes: EAGAIN=%d EXDEV=%d E<other>=%d success=%d\n",
- eagains, exdevs, other_errs, successes);
- resultfn("rename attack with %s (%d runs, got %d escapes)\n",
- flagname(resolve), ROUNDS, escapes);
-
- /* Should be killed anyway, but might as well make sure. */
- E_kill(child, SIGKILL);
-}
-
-#define NUM_TESTS NUM_RENAME_TESTS
-
-int main(int argc, char **argv)
-{
- ksft_print_header();
- ksft_set_plan(NUM_TESTS);
-
- test_rename_attack(RESOLVE_BENEATH);
- test_rename_attack(RESOLVE_IN_ROOT);
-
- if (ksft_get_fail_cnt() + ksft_get_error_cnt() > 0)
- ksft_exit_fail();
- else
- ksft_exit_pass();
-}