aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-10 07:02:35 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-05-10 07:02:35 +0000
commitaefbaa1226662f338aaedc302c701e73f12d200a (patch)
treedf1ccb26decb5dd8062ef10828afbe499f3fe3b6
parent0aa4d57dd55d71c1fa040da4f132537d0aa8ea41 (diff)
parentd01e24273830a794e73d0d67b9ec9c248f2b211e (diff)
downloadlinux-kselftest-android13-mainline-conscrypt-release.tar.gz
Snap for 8564071 from d01e24273830a794e73d0d67b9ec9c248f2b211e to mainline-conscrypt-releaseaml_con_331413000aml_con_331411000aml_con_331312000aml_con_331115000aml_con_331011010android13-mainline-conscrypt-release
Change-Id: I0964be31deb4005bae5fdea45d3e3b2503abf725
-rw-r--r--Android.bp30
-rw-r--r--OWNERS1
-rw-r--r--android/README.md3
-rw-r--r--android/kselftest_test_list.mk3
-rw-r--r--android/patches/0019-userfaultfd.patch261
-rw-r--r--android/patches/0020-selftests-binderfs-fix-Wunused-label-error.patch31
-rw-r--r--android/patches/0021-selftests-binderfs-skip-unprivileged-test-when-USER_.patch36
-rw-r--r--android/patches/0023-ANDROID-kvm-Test-that-pVM-memory-is-wiped-during-tea.patch246
-rw-r--r--android/patches/0025-selftests-userfaultfd-skip-if-unavailable.patch33
-rw-r--r--tools/testing/selftests/filesystems/binderfs/binderfs_test.c8
-rw-r--r--tools/testing/selftests/kvm/aarch64/pvm_wipe_mem.c174
-rw-r--r--tools/testing/selftests/vm/userfaultfd.c106
12 files changed, 900 insertions, 32 deletions
diff --git a/Android.bp b/Android.bp
index e56904c3722e..e9e4d049591a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -76,7 +76,6 @@ cc_defaults {
"-Wno-parentheses-equality",
"-Wno-pointer-arith",
"-Wno-sign-compare",
- "-Wno-unused-parameter",
"-Wno-shift-negative-value",
"-Wno-switch",
"-Wno-absolute-value",
@@ -96,6 +95,14 @@ cc_defaults {
test_per_src: true,
}
+// binderfs test
+cc_test {
+ name: "kselftest_binderfs_tests",
+ relative_install_path: "linux-kselftest/filesystems/binderfs",
+ srcs: ["tools/testing/selftests/filesystems/binderfs/binderfs_test.c"],
+ defaults: ["kselftest_defaults"],
+}
+
// breakpoints test
cc_test {
name: "kselftest_breakpoints_tests",
@@ -118,6 +125,11 @@ cc_test {
"tools/testing/selftests/breakpoints/breakpoint_test.c",
],
},
+ x86_64: {
+ srcs: [
+ "tools/testing/selftests/breakpoints/breakpoint_test.c",
+ ],
+ },
},
}
@@ -332,6 +344,21 @@ cc_test {
defaults: ["kselftest_defaults"],
}
+// KVM test
+cc_test {
+ name: "kselftest_kvm_arm64_tests",
+ relative_install_path: "linux-kselftest/kvm/aarch64",
+ local_include_dirs: [ "tools/testing/selftests"],
+ enabled: false,
+ arch: {
+ arm64: {
+ enabled: true,
+ srcs: ["tools/testing/selftests/kvm/aarch64/pvm_wipe_mem.c"],
+ },
+ },
+ defaults: ["kselftest_defaults"],
+}
+
// Lib test
sh_test {
name: "kselftest_lib_printf",
@@ -575,6 +602,7 @@ cc_test {
"tools/testing/selftests/vm/mlock-random-test.c",
"tools/testing/selftests/vm/mlock2-tests.c",
"tools/testing/selftests/vm/on-fault-limit.c",
+ "tools/testing/selftests/vm/userfaultfd.c",
"tools/testing/selftests/vm/thuge-gen.c",
"tools/testing/selftests/vm/transhuge-stress.c",
],
diff --git a/OWNERS b/OWNERS
index 64bf926733d4..3ae489ae8e6c 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,2 +1,3 @@
drosen@google.com
+smuckle@google.com
willmcvicker@google.com
diff --git a/android/README.md b/android/README.md
index 2c94e05b4cdf..7a12a1d3aa21 100644
--- a/android/README.md
+++ b/android/README.md
@@ -334,9 +334,6 @@ kernel module is not required by Android.
The hugepage-mmap, hugepage-shm, compaction, and map_hugetlb tests rely on
hugetlbfs/hugetlb page support which is not required by Android.
-The userfaultfd test relies on the userfaultfd syscall which is not required by
-Android.
-
### watchdog/
The watchdog test depends on CONFIG_WATCHDOG which is not required by Android.
diff --git a/android/kselftest_test_list.mk b/android/kselftest_test_list.mk
index 5445bd12d26f..46b9b92c58fb 100644
--- a/android/kselftest_test_list.mk
+++ b/android/kselftest_test_list.mk
@@ -12,6 +12,7 @@ kselftest_modules := \
# From Android.bp
kselftest_modules += \
+ kselftest_binderfs_tests_binderfs_test \
kselftest_breakpoints_tests_breakpoint_test \
kselftest_breakpoints_tests_breakpoint_test_arm64 \
kselftest_breakpoints_tests_step_after_suspend_test \
@@ -30,6 +31,7 @@ kselftest_modules += \
kselftest_intel_pstate_tests_aperf \
kselftest_intel_pstate_tests_msr \
kselftest_kcmp_tests_kcmp_test \
+ kselftest_kvm_arm64_tests_pvm_wipe_mem \
kselftest_net_tests_psock_tpacket \
kselftest_net_tests_socket \
kselftest_net_tests_reuseaddr_conflict \
@@ -52,6 +54,7 @@ kselftest_modules += \
kselftest_vdso_test \
kselftest_vm_tests_mlock2-tests \
kselftest_vm_tests_on-fault-limit \
+ kselftest_vm_tests_userfaultfd \
kselftest_vm64_tests_virtual_address_range \
kselftest_x86_ptrace_syscall \
kselftest_x86_check_initial_reg_state \
diff --git a/android/patches/0019-userfaultfd.patch b/android/patches/0019-userfaultfd.patch
new file mode 100644
index 000000000000..67fe8edc9848
--- /dev/null
+++ b/android/patches/0019-userfaultfd.patch
@@ -0,0 +1,261 @@
+--- b/tools/testing/selftests/vm/userfaultfd.c
++++ b/tools/testing/selftests/vm/userfaultfd.c
+@@ -82,9 +82,11 @@
+ static char *huge_fd_off0;
+ static unsigned long long *count_verify;
+ static int uffd, uffd_flags, finished, *pipefd;
++static volatile bool ready_for_fork;
+ static char *area_src, *area_src_alias, *area_dst, *area_dst_alias;
+ static char *zeropage;
+ pthread_attr_t attr;
++pthread_key_t long_jmp_key;
+
+ /* pthread_mutex_t starts at page offset 0 */
+ #define area_mutex(___area, ___nr) \
+@@ -139,8 +141,11 @@
+
+ static void anon_allocate_area(void **alloc_area)
+ {
+- if (posix_memalign(alloc_area, page_size, nr_pages * page_size)) {
+- fprintf(stderr, "out of memory\n");
++ // We can't use posix_memalign due to pointer-tagging used in bionic.
++ *alloc_area = mmap(NULL, nr_pages * page_size, PROT_READ | PROT_WRITE,
++ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
++ if (*alloc_area == MAP_FAILED) {
++ fprintf(stderr, "anon memory mmap failed\n");
+ *alloc_area = NULL;
+ }
+ }
+@@ -284,23 +289,11 @@
+ static void *locking_thread(void *arg)
+ {
+ unsigned long cpu = (unsigned long) arg;
+- struct random_data rand;
+ unsigned long page_nr = *(&(page_nr)); /* uninitialized warning */
+- int32_t rand_nr;
+ unsigned long long count;
+- char randstate[64];
+- unsigned int seed;
+ time_t start;
+
+- if (bounces & BOUNCE_RANDOM) {
+- seed = (unsigned int) time(NULL) - bounces;
+- if (!(bounces & BOUNCE_RACINGFAULTS))
+- seed += cpu;
+- bzero(&rand, sizeof(rand));
+- bzero(&randstate, sizeof(randstate));
+- if (initstate_r(seed, randstate, sizeof(randstate), &rand))
+- fprintf(stderr, "srandom_r error\n"), exit(1);
+- } else {
++ if (!(bounces & BOUNCE_RANDOM)) {
+ page_nr = -bounces;
+ if (!(bounces & BOUNCE_RACINGFAULTS))
+ page_nr += cpu * nr_pages_per_cpu;
+@@ -308,13 +301,9 @@
+
+ while (!finished) {
+ if (bounces & BOUNCE_RANDOM) {
+- if (random_r(&rand, &rand_nr))
+- fprintf(stderr, "random_r 1 error\n"), exit(1);
+- page_nr = rand_nr;
+- if (sizeof(page_nr) > sizeof(rand_nr)) {
+- if (random_r(&rand, &rand_nr))
+- fprintf(stderr, "random_r 2 error\n"), exit(1);
+- page_nr |= (((unsigned long) rand_nr) << 16) <<
++ page_nr = random();
++ if (sizeof(page_nr) > sizeof(uint32_t)) {
++ page_nr |= (((unsigned long) random()) << 16) <<
+ 16;
+ }
+ } else
+@@ -501,6 +490,9 @@
+ pollfd[1].fd = pipefd[cpu*2];
+ pollfd[1].events = POLLIN;
+
++ // Notify the main thread that it can now fork.
++ ready_for_fork = true;
++
+ for (;;) {
+ ret = poll(pollfd, 2, -1);
+ if (!ret)
+@@ -548,18 +540,31 @@
+
+ pthread_mutex_t uffd_read_mutex = PTHREAD_MUTEX_INITIALIZER;
+
++static void sigusr1_handler(int signum, siginfo_t *siginfo, void *ptr)
++{
++ jmp_buf *env;
++ env = pthread_getspecific(long_jmp_key);
++ longjmp(*env, 1);
++}
++
+ static void *uffd_read_thread(void *arg)
+ {
+ unsigned long *this_cpu_userfaults;
+ struct uffd_msg msg;
++ jmp_buf env;
++ int setjmp_ret;
++
++ pthread_setspecific(long_jmp_key, &env);
+
+ this_cpu_userfaults = (unsigned long *) arg;
+ *this_cpu_userfaults = 0;
+
+ pthread_mutex_unlock(&uffd_read_mutex);
+- /* from here cancellation is ok */
+
+- for (;;) {
++ // One first return setjmp return 0. On second (fake) return from
++ // longjmp() it returns the provided value, which will be 1 in our case.
++ setjmp_ret = setjmp(env);
++ while (!setjmp_ret) {
+ if (uffd_read_msg(uffd, &msg))
+ continue;
+ (*this_cpu_userfaults) += uffd_handle_page_fault(&msg);
+@@ -608,6 +613,7 @@
+ background_thread, (void *)cpu))
+ return 1;
+ }
++
+ for (cpu = 0; cpu < nr_cpus; cpu++)
+ if (pthread_join(background_threads[cpu], NULL))
+ return 1;
+@@ -640,7 +646,7 @@
+ if (pthread_join(uffd_threads[cpu], &_userfaults[cpu]))
+ return 1;
+ } else {
+- if (pthread_cancel(uffd_threads[cpu]))
++ if (pthread_kill(uffd_threads[cpu], SIGUSR1))
+ return 1;
+ if (pthread_join(uffd_threads[cpu], NULL))
+ return 1;
+@@ -654,7 +660,7 @@
+ {
+ struct uffdio_api uffdio_api;
+
+- uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
++ uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY);
+ if (uffd < 0) {
+ fprintf(stderr,
+ "userfaultfd syscall not available in this kernel\n");
+@@ -914,6 +920,10 @@
+ pid_t pid;
+ char c;
+
++ // All the syscalls below up to pthread_create will ensure that this
++ // write is completed before, the uffd_thread sets it to true.
++ ready_for_fork = false;
++
+ printf("testing events (fork, remap, remove): ");
+ fflush(stdout);
+
+@@ -942,6 +952,11 @@
+ if (pthread_create(&uffd_mon, &attr, uffd_poll_thread, NULL))
+ perror("uffd_poll_thread create"), exit(1);
+
++ // Wait for the poll_thread to start executing before forking. This is
++ // required to avoid a deadlock, which can happen if poll_thread doesn't
++ // start getting executed by the time fork is invoked.
++ while (!ready_for_fork);
++
+ pid = fork();
+ if (pid < 0)
+ perror("fork"), exit(1);
+@@ -974,6 +989,10 @@
+ pid_t pid;
+ char c;
+
++ // All the syscalls below up to pthread_create will ensure that this
++ // write is completed before, the uffd_thread sets it to true.
++ ready_for_fork = false;
++
+ printf("testing signal delivery: ");
+ fflush(stdout);
+
+@@ -1007,6 +1026,11 @@
+ if (pthread_create(&uffd_mon, &attr, uffd_poll_thread, NULL))
+ perror("uffd_poll_thread create"), exit(1);
+
++ // Wait for the poll_thread to start executing before forking. This is
++ // required to avoid a deadlock, which can happen if poll_thread doesn't
++ // start getting executed by the time fork is invoked.
++ while (!ready_for_fork);
++
+ pid = fork();
+ if (pid < 0)
+ perror("fork"), exit(1);
+@@ -1036,6 +1060,7 @@
+ char *tmp_area;
+ unsigned long nr;
+ struct uffdio_register uffdio_register;
++ struct sigaction act;
+ unsigned long cpu;
+ int err;
+ unsigned long userfaults[nr_cpus];
+@@ -1094,6 +1119,17 @@
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 16*1024*1024);
+
++ // For handling thread termination of read thread in the absense of
++ // pthread_cancel().
++ pthread_key_create(&long_jmp_key, NULL);
++ memset(&act, 0, sizeof(act));
++ act.sa_sigaction = sigusr1_handler;
++ act.sa_flags = SA_SIGINFO;
++ if (sigaction(SIGUSR1, &act, 0)) {
++ perror("sigaction");
++ return 1;
++ }
++
+ err = 0;
+ while (bounces--) {
+ unsigned long expected_ioctls;
+@@ -1215,6 +1251,8 @@
+ printf("\n");
+ }
+
++ pthread_key_delete(long_jmp_key);
++
+ if (err)
+ return err;
+
+@@ -1291,6 +1329,9 @@
+
+ int main(int argc, char **argv)
+ {
++ char randstate[64];
++ unsigned int seed;
++
+ if (argc < 4)
+ usage();
+
+@@ -1332,6 +1373,12 @@
+ }
+ printf("nr_pages: %lu, nr_pages_per_cpu: %lu\n",
+ nr_pages, nr_pages_per_cpu);
++
++ seed = (unsigned int) time(NULL);
++ bzero(&randstate, sizeof(randstate));
++ if (!initstate(seed, randstate, sizeof(randstate)))
++ fprintf(stderr, "srandom_r error\n"), exit(1);
++
+ return userfaultfd_stress();
+ }
+
+--- a/tools/testing/selftests/vm/userfaultfd.c
++++ b/tools/testing/selftests/vm/userfaultfd.c
+@@ -662,8 +662,13 @@ static int userfaultfd_open(int features)
+
+ uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY);
+ if (uffd < 0) {
++ if (errno == ENOSYS) {
++ fprintf(stderr,
++ "userfaultfd syscall not available in this kernel\n");
++ exit(KSFT_PASS);
++ }
+ fprintf(stderr,
+- "userfaultfd syscall not available in this kernel\n");
++ "userfaultfd syscall failed with errno: %d\n", errno);
+ return 1;
+ }
+ uffd_flags = fcntl(uffd, F_GETFD, NULL);
diff --git a/android/patches/0020-selftests-binderfs-fix-Wunused-label-error.patch b/android/patches/0020-selftests-binderfs-fix-Wunused-label-error.patch
new file mode 100644
index 000000000000..8b872f18e51f
--- /dev/null
+++ b/android/patches/0020-selftests-binderfs-fix-Wunused-label-error.patch
@@ -0,0 +1,31 @@
+From c4970a0b5461b65ce3b7d1c40a76672bd18d3ba5 Mon Sep 17 00:00:00 2001
+From: Carlos Llamas <cmllamas@google.com>
+Date: Mon, 26 Jul 2021 17:06:02 +0000
+Subject: [PATCH 1/2] selftests/binderfs: fix Wunused-label error
+
+Fix the following build issue:
+ tools/testing/selftests/filesystems/binderfs/binderfs_test.c:244:1:
+ error: unused label 'on_error' [-Werror,-Wunused-label]
+ on_error:
+ ^~~~~~~~~
+
+Signed-off-by: Carlos Llamas <cmllamas@google.com>
+---
+ tools/testing/selftests/filesystems/binderfs/binderfs_test.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/tools/testing/selftests/filesystems/binderfs/binderfs_test.c b/tools/testing/selftests/filesystems/binderfs/binderfs_test.c
+index 8c2ed962e1c7..540ad4840495 100644
+--- a/tools/testing/selftests/filesystems/binderfs/binderfs_test.c
++++ b/tools/testing/selftests/filesystems/binderfs/binderfs_test.c
+@@ -241,7 +241,6 @@ static void __do_binderfs_test(void)
+ /* binder-control device removal failed as expected */
+ ksft_inc_xfail_cnt();
+
+-on_error:
+ ret = umount2("/dev/binderfs", MNT_DETACH);
+ keep ?: rmdir_protect_errno("/dev/binderfs");
+ if (ret < 0)
+--
+2.32.0.432.gabb21c7263-goog
+
diff --git a/android/patches/0021-selftests-binderfs-skip-unprivileged-test-when-USER_.patch b/android/patches/0021-selftests-binderfs-skip-unprivileged-test-when-USER_.patch
new file mode 100644
index 000000000000..8a5af5794c01
--- /dev/null
+++ b/android/patches/0021-selftests-binderfs-skip-unprivileged-test-when-USER_.patch
@@ -0,0 +1,36 @@
+From e51806a0b6918cefbd068cbb8100f410e7b01970 Mon Sep 17 00:00:00 2001
+From: Carlos Llamas <cmllamas@google.com>
+Date: Mon, 26 Jul 2021 17:12:42 +0000
+Subject: [PATCH 2/2] selftests/binderfs: skip unprivileged test when !USER_NS
+
+Binderfs unprivileged test requires CONFIG_USER_NS to be set. However,
+this option is not required by Android platforms. Lets skip the test
+as the underlying routine __do_binderfs_test() has already been checked
+by the binderfs_test_privileged() anyway.
+
+Signed-off-by: Carlos Llamas <cmllamas@google.com>
+---
+ .../testing/selftests/filesystems/binderfs/binderfs_test.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/tools/testing/selftests/filesystems/binderfs/binderfs_test.c b/tools/testing/selftests/filesystems/binderfs/binderfs_test.c
+index 540ad4840495..397bf265ba97 100644
+--- a/tools/testing/selftests/filesystems/binderfs/binderfs_test.c
++++ b/tools/testing/selftests/filesystems/binderfs/binderfs_test.c
+@@ -262,6 +262,13 @@ static void binderfs_test_privileged()
+
+ static void binderfs_test_unprivileged()
+ {
++ /* This test depends on USER_NS which is not required by Android */
++ if (access("/proc/self/ns/user", F_OK) != 0) {
++ ksft_test_result_skip("%s: user namespace not supported\n",
++ __func__);
++ return;
++ }
++
+ change_to_userns();
+ __do_binderfs_test();
+ }
+--
+2.32.0.432.gabb21c7263-goog
+
diff --git a/android/patches/0023-ANDROID-kvm-Test-that-pVM-memory-is-wiped-during-tea.patch b/android/patches/0023-ANDROID-kvm-Test-that-pVM-memory-is-wiped-during-tea.patch
new file mode 100644
index 000000000000..590ee72368dc
--- /dev/null
+++ b/android/patches/0023-ANDROID-kvm-Test-that-pVM-memory-is-wiped-during-tea.patch
@@ -0,0 +1,246 @@
+From a9dc703806031c8535c84c9905979f86dfaec1d3 Mon Sep 17 00:00:00 2001
+From: Quentin Perret <qperret@google.com>
+Date: Thu, 17 Feb 2022 19:34:27 +0000
+Subject: [PATCH] ANDROID: kvm: Test that pVM memory is wiped during teardown
+
+In protected KVM mode, we expect the hypervisor to protect guest secrets
+when they are torn down. Add a test checking this property by running a
+minimal guest, and checking that the content of memory has been wiped by
+the hypervisor after teardown.
+
+Note: although some of the pKVM code has already landed upstream, the
+functionality tested here hasn't at the time of writing. Once it does,
+this test should be sent upstream for review to replace this ANDROID
+patch.
+
+Bug: 218934075
+Signed-off-by: Quentin Perret <qperret@google.com>
+Change-Id: I4a347908d189f2c4835fd576b26fae7c10ec9b22
+---
+ Android.bp | 15 ++
+ android/kselftest_test_list.mk | 1 +
+ .../selftests/kvm/aarch64/pvm_wipe_mem.c | 174 ++++++++++++++++++
+ 3 files changed, 190 insertions(+)
+ create mode 100644 tools/testing/selftests/kvm/aarch64/pvm_wipe_mem.c
+
+diff --git a/Android.bp b/Android.bp
+index 0b9166c56315..08805a161450 100644
+--- a/Android.bp
++++ b/Android.bp
+@@ -340,6 +340,21 @@ cc_test {
+ defaults: ["kselftest_defaults"],
+ }
+
++// KVM test
++cc_test {
++ name: "kselftest_kvm_arm64_tests",
++ relative_install_path: "linux-kselftest/kvm/aarch64",
++ local_include_dirs: [ "tools/testing/selftests"],
++ enabled: false,
++ arch: {
++ arm64: {
++ enabled: true,
++ srcs: ["tools/testing/selftests/kvm/aarch64/pvm_wipe_mem.c"],
++ },
++ },
++ defaults: ["kselftest_defaults"],
++}
++
+ // Lib test
+ sh_test {
+ name: "kselftest_lib_printf",
+diff --git a/android/kselftest_test_list.mk b/android/kselftest_test_list.mk
+index 07df6fc5d758..46b9b92c58fb 100644
+--- a/android/kselftest_test_list.mk
++++ b/android/kselftest_test_list.mk
+@@ -31,6 +31,7 @@ kselftest_modules += \
+ kselftest_intel_pstate_tests_aperf \
+ kselftest_intel_pstate_tests_msr \
+ kselftest_kcmp_tests_kcmp_test \
++ kselftest_kvm_arm64_tests_pvm_wipe_mem \
+ kselftest_net_tests_psock_tpacket \
+ kselftest_net_tests_socket \
+ kselftest_net_tests_reuseaddr_conflict \
+diff --git a/tools/testing/selftests/kvm/aarch64/pvm_wipe_mem.c b/tools/testing/selftests/kvm/aarch64/pvm_wipe_mem.c
+new file mode 100644
+index 000000000000..4af8ca3c4bad
+--- /dev/null
++++ b/tools/testing/selftests/kvm/aarch64/pvm_wipe_mem.c
+@@ -0,0 +1,174 @@
++// SPDX-License-Identifier: GPL-2.0-only
++/*
++ * Test checking that memory of protected guests is wiped after teardown.
++ *
++ * Copyright (C) 2022, Google LLC.
++ */
++
++#define _GNU_SOURCE
++
++#include <err.h>
++#include <errno.h>
++#include <fcntl.h>
++#include <stdio.h>
++#include <stdint.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++
++#include <linux/kvm.h>
++#include <sys/ioctl.h>
++#include <sys/mman.h>
++
++#include "kselftest.h"
++
++#define KVM_VM_TYPE_ARM_PROTECTED (1UL << 31)
++
++#define REG_X(number) (0x6030000000100000ULL + (number) * 2UL)
++#define REG_PC 0x6030000000100040ULL
++
++static void set_one_reg(int vcpufd, uint64_t reg_id, uint64_t val)
++{
++ uint64_t reg_data;
++ struct kvm_one_reg reg;
++ int ret;
++
++ reg.addr = (__u64) &reg_data;
++ reg_data = val;
++ reg.id = reg_id;
++
++ ret = ioctl(vcpufd, KVM_SET_ONE_REG, &reg);
++ if (ret < 0)
++ ksft_exit_fail_msg("Failed to set reg: %d\n", ret);
++}
++
++static int get_kvm(void)
++{
++ size_t run_size;
++ int kvm, ret;
++
++ kvm = open("/dev/kvm", O_RDWR | O_CLOEXEC);
++ if (kvm < 0)
++ ksft_exit_skip("KVM not supported\n");
++
++ ret = ioctl(kvm, KVM_GET_API_VERSION, NULL);
++ if (ret != 12)
++ ksft_exit_fail_msg("KVM_GET_API_VERSION %d, expected 12", ret);
++
++ run_size = ioctl(kvm, KVM_GET_VCPU_MMAP_SIZE, NULL);
++ if (run_size < sizeof(struct kvm_run))
++ ksft_exit_fail_msg("KVM_GET_VCPU_MMAP_SIZE unexpectedly small\n");
++
++ return kvm;
++}
++
++static int create_protected_vm(int kvm)
++{
++ int vmfd = ioctl(kvm, KVM_CREATE_VM, KVM_VM_TYPE_ARM_PROTECTED);
++
++ if (vmfd < 0)
++ ksft_exit_skip("Protected guests not supported: %d\n", vmfd);
++
++ return vmfd;
++}
++
++static int create_vcpu(int vmfd, struct kvm_run **run)
++{
++ struct kvm_vcpu_init vcpu_init;
++ int vcpufd, ret;
++
++ ret = ioctl(vmfd, KVM_ARM_PREFERRED_TARGET, &vcpu_init);
++ if (ret)
++ ksft_exit_fail_msg("Failed to set kvm_vcpu_init %d\n", ret);
++
++ vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, (unsigned long)0);
++ if (vcpufd < 0)
++ ksft_exit_fail_msg("Failed to create VCPU: %d\n", vcpufd);
++
++ *run = mmap(NULL, sizeof(**run), PROT_READ | PROT_WRITE, MAP_SHARED, vcpufd, 0);
++ if (!run)
++ ksft_exit_fail_msg("Failed to mmap vcpu_run struct\n");
++
++ ret = ioctl(vcpufd, KVM_ARM_VCPU_INIT, &vcpu_init);
++ if (ret)
++ ksft_exit_fail_msg("Failed to initialize VCPU %d\n", ret);
++
++ return vcpufd;
++}
++
++static void teardown(int kvm, int vmfd, int vcpufd, struct kvm_run *run)
++{
++ int ret = munmap(run, sizeof(*run));
++
++ if (ret)
++ ksft_exit_fail_msg("Failed to unmap vCPU run: %d\n", ret);
++
++ ret = close(vcpufd);
++ if (ret)
++ ksft_exit_fail_msg("Failed to destroy VCPU: %d\n", ret);
++
++ ret = close(vmfd);
++ if (ret)
++ ksft_exit_fail_msg("Failed to destroy VM: %d\n", ret);
++
++ ret = close(kvm);
++ if (ret)
++ ksft_exit_fail_msg("Failed to close KVM fd: %d\n", ret);
++}
++
++int main(void)
++{
++ struct kvm_userspace_memory_region region;
++ long page_size = sysconf(_SC_PAGESIZE);
++ int ret, kvm, vmfd, vcpufd;
++ uint32_t guest_code[2];
++ struct kvm_run *run;
++ uint8_t *guest_mem;
++ size_t run_size;
++
++ kvm = get_kvm();
++ vmfd = create_protected_vm(kvm);
++ vcpufd = create_vcpu(vmfd, &run);
++
++ /* Create a one-page memslot for the guest */
++ guest_mem = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
++ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
++ if (guest_mem == MAP_FAILED)
++ ksft_exit_fail_msg("Failed to mmap guest memory\n");
++ region = (struct kvm_userspace_memory_region) {
++ .slot = 0,
++ .guest_phys_addr = 1UL << 30,
++ .memory_size = page_size,
++ .userspace_addr = (uint64_t)guest_mem,
++ };
++
++ /* Copy some code in guest memory. */
++ guest_code[0] = 0xf9400001; /* 1: ldr x1, [x0] */
++ guest_code[1] = 0x17ffffff; /* b 1b */
++ memcpy(guest_mem, guest_code, sizeof(guest_code));
++ ret = ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &region);
++ if (ret)
++ ksft_exit_fail_msg("Failed to set memory region: %d\n", ret);
++
++ /*
++ * Get the VCPU to run one instruction, to be sure the page containing
++ * the code has been faulted in.
++ */
++ set_one_reg(vcpufd, REG_PC, region.guest_phys_addr);
++ set_one_reg(vcpufd, REG_X(0), region.guest_phys_addr + region.memory_size);
++ ret = ioctl(vcpufd, KVM_RUN, NULL);
++ if (ret)
++ ksft_exit_fail_msg("Failed to run vcpu: %d\n", ret);
++ if (run->exit_reason != KVM_EXIT_MMIO)
++ ksft_exit_fail_msg("Unexpected KVM exit reason: %u\n", run->exit_reason);
++
++ /*
++ * Tear the guest down, and check that the donated memory has been
++ * wiped by the hypervisor.
++ */
++ teardown(kvm, vmfd, vcpufd, run);
++ if (!memcmp(guest_mem, guest_code, sizeof(guest_code)))
++ ksft_exit_fail_msg("Protected guest memory has not been poisoned\n");
++
++ ksft_exit_pass();
++}
+--
+2.35.1.473.g83b2b277ed-goog
+
diff --git a/android/patches/0025-selftests-userfaultfd-skip-if-unavailable.patch b/android/patches/0025-selftests-userfaultfd-skip-if-unavailable.patch
new file mode 100644
index 000000000000..0920fb307ed0
--- /dev/null
+++ b/android/patches/0025-selftests-userfaultfd-skip-if-unavailable.patch
@@ -0,0 +1,33 @@
+From 30c060a86f0e56c19e18ade48c0ee7592edfc317 Mon Sep 17 00:00:00 2001
+From: Edward Liaw <edliaw@google.com>
+Date: Thu, 24 Mar 2022 00:29:56 +0000
+Subject: [PATCH] selftests: userfaultfd skip if unavailable
+
+Skip userfaultfd selftest if the syscall is not available for this
+kernel.
+
+Bug: 207175332
+Bug: 206503000
+Test: atest vts_linux_kselftest_arm_64:vm_userfaultfd_shmem_arm_64
+Change-Id: I60e4d6cc5b3886048ffa1995e4b090f6fbe26b3d
+Signed-off-by: Edward Liaw <edliaw@google.com>
+---
+ tools/testing/selftests/vm/userfaultfd.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c
+index ffc78f3..17947fe 100644
+--- a/tools/testing/selftests/vm/userfaultfd.c
++++ b/tools/testing/selftests/vm/userfaultfd.c
+@@ -665,7 +665,7 @@ static int userfaultfd_open(int features)
+ if (errno == ENOSYS) {
+ fprintf(stderr,
+ "userfaultfd syscall not available in this kernel\n");
+- exit(KSFT_PASS);
++ exit(KSFT_SKIP);
+ }
+ fprintf(stderr,
+ "userfaultfd syscall failed with errno: %d\n", errno);
+--
+2.35.1.1021.g381101b075-goog
+
diff --git a/tools/testing/selftests/filesystems/binderfs/binderfs_test.c b/tools/testing/selftests/filesystems/binderfs/binderfs_test.c
index 8c2ed962e1c7..397bf265ba97 100644
--- a/tools/testing/selftests/filesystems/binderfs/binderfs_test.c
+++ b/tools/testing/selftests/filesystems/binderfs/binderfs_test.c
@@ -241,7 +241,6 @@ static void __do_binderfs_test(void)
/* binder-control device removal failed as expected */
ksft_inc_xfail_cnt();
-on_error:
ret = umount2("/dev/binderfs", MNT_DETACH);
keep ?: rmdir_protect_errno("/dev/binderfs");
if (ret < 0)
@@ -263,6 +262,13 @@ static void binderfs_test_privileged()
static void binderfs_test_unprivileged()
{
+ /* This test depends on USER_NS which is not required by Android */
+ if (access("/proc/self/ns/user", F_OK) != 0) {
+ ksft_test_result_skip("%s: user namespace not supported\n",
+ __func__);
+ return;
+ }
+
change_to_userns();
__do_binderfs_test();
}
diff --git a/tools/testing/selftests/kvm/aarch64/pvm_wipe_mem.c b/tools/testing/selftests/kvm/aarch64/pvm_wipe_mem.c
new file mode 100644
index 000000000000..4af8ca3c4bad
--- /dev/null
+++ b/tools/testing/selftests/kvm/aarch64/pvm_wipe_mem.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Test checking that memory of protected guests is wiped after teardown.
+ *
+ * Copyright (C) 2022, Google LLC.
+ */
+
+#define _GNU_SOURCE
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <linux/kvm.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include "kselftest.h"
+
+#define KVM_VM_TYPE_ARM_PROTECTED (1UL << 31)
+
+#define REG_X(number) (0x6030000000100000ULL + (number) * 2UL)
+#define REG_PC 0x6030000000100040ULL
+
+static void set_one_reg(int vcpufd, uint64_t reg_id, uint64_t val)
+{
+ uint64_t reg_data;
+ struct kvm_one_reg reg;
+ int ret;
+
+ reg.addr = (__u64) &reg_data;
+ reg_data = val;
+ reg.id = reg_id;
+
+ ret = ioctl(vcpufd, KVM_SET_ONE_REG, &reg);
+ if (ret < 0)
+ ksft_exit_fail_msg("Failed to set reg: %d\n", ret);
+}
+
+static int get_kvm(void)
+{
+ size_t run_size;
+ int kvm, ret;
+
+ kvm = open("/dev/kvm", O_RDWR | O_CLOEXEC);
+ if (kvm < 0)
+ ksft_exit_skip("KVM not supported\n");
+
+ ret = ioctl(kvm, KVM_GET_API_VERSION, NULL);
+ if (ret != 12)
+ ksft_exit_fail_msg("KVM_GET_API_VERSION %d, expected 12", ret);
+
+ run_size = ioctl(kvm, KVM_GET_VCPU_MMAP_SIZE, NULL);
+ if (run_size < sizeof(struct kvm_run))
+ ksft_exit_fail_msg("KVM_GET_VCPU_MMAP_SIZE unexpectedly small\n");
+
+ return kvm;
+}
+
+static int create_protected_vm(int kvm)
+{
+ int vmfd = ioctl(kvm, KVM_CREATE_VM, KVM_VM_TYPE_ARM_PROTECTED);
+
+ if (vmfd < 0)
+ ksft_exit_skip("Protected guests not supported: %d\n", vmfd);
+
+ return vmfd;
+}
+
+static int create_vcpu(int vmfd, struct kvm_run **run)
+{
+ struct kvm_vcpu_init vcpu_init;
+ int vcpufd, ret;
+
+ ret = ioctl(vmfd, KVM_ARM_PREFERRED_TARGET, &vcpu_init);
+ if (ret)
+ ksft_exit_fail_msg("Failed to set kvm_vcpu_init %d\n", ret);
+
+ vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, (unsigned long)0);
+ if (vcpufd < 0)
+ ksft_exit_fail_msg("Failed to create VCPU: %d\n", vcpufd);
+
+ *run = mmap(NULL, sizeof(**run), PROT_READ | PROT_WRITE, MAP_SHARED, vcpufd, 0);
+ if (!run)
+ ksft_exit_fail_msg("Failed to mmap vcpu_run struct\n");
+
+ ret = ioctl(vcpufd, KVM_ARM_VCPU_INIT, &vcpu_init);
+ if (ret)
+ ksft_exit_fail_msg("Failed to initialize VCPU %d\n", ret);
+
+ return vcpufd;
+}
+
+static void teardown(int kvm, int vmfd, int vcpufd, struct kvm_run *run)
+{
+ int ret = munmap(run, sizeof(*run));
+
+ if (ret)
+ ksft_exit_fail_msg("Failed to unmap vCPU run: %d\n", ret);
+
+ ret = close(vcpufd);
+ if (ret)
+ ksft_exit_fail_msg("Failed to destroy VCPU: %d\n", ret);
+
+ ret = close(vmfd);
+ if (ret)
+ ksft_exit_fail_msg("Failed to destroy VM: %d\n", ret);
+
+ ret = close(kvm);
+ if (ret)
+ ksft_exit_fail_msg("Failed to close KVM fd: %d\n", ret);
+}
+
+int main(void)
+{
+ struct kvm_userspace_memory_region region;
+ long page_size = sysconf(_SC_PAGESIZE);
+ int ret, kvm, vmfd, vcpufd;
+ uint32_t guest_code[2];
+ struct kvm_run *run;
+ uint8_t *guest_mem;
+ size_t run_size;
+
+ kvm = get_kvm();
+ vmfd = create_protected_vm(kvm);
+ vcpufd = create_vcpu(vmfd, &run);
+
+ /* Create a one-page memslot for the guest */
+ guest_mem = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ if (guest_mem == MAP_FAILED)
+ ksft_exit_fail_msg("Failed to mmap guest memory\n");
+ region = (struct kvm_userspace_memory_region) {
+ .slot = 0,
+ .guest_phys_addr = 1UL << 30,
+ .memory_size = page_size,
+ .userspace_addr = (uint64_t)guest_mem,
+ };
+
+ /* Copy some code in guest memory. */
+ guest_code[0] = 0xf9400001; /* 1: ldr x1, [x0] */
+ guest_code[1] = 0x17ffffff; /* b 1b */
+ memcpy(guest_mem, guest_code, sizeof(guest_code));
+ ret = ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &region);
+ if (ret)
+ ksft_exit_fail_msg("Failed to set memory region: %d\n", ret);
+
+ /*
+ * Get the VCPU to run one instruction, to be sure the page containing
+ * the code has been faulted in.
+ */
+ set_one_reg(vcpufd, REG_PC, region.guest_phys_addr);
+ set_one_reg(vcpufd, REG_X(0), region.guest_phys_addr + region.memory_size);
+ ret = ioctl(vcpufd, KVM_RUN, NULL);
+ if (ret)
+ ksft_exit_fail_msg("Failed to run vcpu: %d\n", ret);
+ if (run->exit_reason != KVM_EXIT_MMIO)
+ ksft_exit_fail_msg("Unexpected KVM exit reason: %u\n", run->exit_reason);
+
+ /*
+ * Tear the guest down, and check that the donated memory has been
+ * wiped by the hypervisor.
+ */
+ teardown(kvm, vmfd, vcpufd, run);
+ if (!memcmp(guest_mem, guest_code, sizeof(guest_code)))
+ ksft_exit_fail_msg("Protected guest memory has not been poisoned\n");
+
+ ksft_exit_pass();
+}
diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c
index d3362777a425..17947feb6d8e 100644
--- a/tools/testing/selftests/vm/userfaultfd.c
+++ b/tools/testing/selftests/vm/userfaultfd.c
@@ -82,9 +82,11 @@ static int huge_fd;
static char *huge_fd_off0;
static unsigned long long *count_verify;
static int uffd, uffd_flags, finished, *pipefd;
+static volatile bool ready_for_fork;
static char *area_src, *area_src_alias, *area_dst, *area_dst_alias;
static char *zeropage;
pthread_attr_t attr;
+pthread_key_t long_jmp_key;
/* pthread_mutex_t starts at page offset 0 */
#define area_mutex(___area, ___nr) \
@@ -139,8 +141,11 @@ static int anon_release_pages(char *rel_area)
static void anon_allocate_area(void **alloc_area)
{
- if (posix_memalign(alloc_area, page_size, nr_pages * page_size)) {
- fprintf(stderr, "out of memory\n");
+ // We can't use posix_memalign due to pointer-tagging used in bionic.
+ *alloc_area = mmap(NULL, nr_pages * page_size, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ if (*alloc_area == MAP_FAILED) {
+ fprintf(stderr, "anon memory mmap failed\n");
*alloc_area = NULL;
}
}
@@ -284,23 +289,11 @@ static int my_bcmp(char *str1, char *str2, size_t n)
static void *locking_thread(void *arg)
{
unsigned long cpu = (unsigned long) arg;
- struct random_data rand;
unsigned long page_nr = *(&(page_nr)); /* uninitialized warning */
- int32_t rand_nr;
unsigned long long count;
- char randstate[64];
- unsigned int seed;
time_t start;
- if (bounces & BOUNCE_RANDOM) {
- seed = (unsigned int) time(NULL) - bounces;
- if (!(bounces & BOUNCE_RACINGFAULTS))
- seed += cpu;
- bzero(&rand, sizeof(rand));
- bzero(&randstate, sizeof(randstate));
- if (initstate_r(seed, randstate, sizeof(randstate), &rand))
- fprintf(stderr, "srandom_r error\n"), exit(1);
- } else {
+ if (!(bounces & BOUNCE_RANDOM)) {
page_nr = -bounces;
if (!(bounces & BOUNCE_RACINGFAULTS))
page_nr += cpu * nr_pages_per_cpu;
@@ -308,13 +301,9 @@ static void *locking_thread(void *arg)
while (!finished) {
if (bounces & BOUNCE_RANDOM) {
- if (random_r(&rand, &rand_nr))
- fprintf(stderr, "random_r 1 error\n"), exit(1);
- page_nr = rand_nr;
- if (sizeof(page_nr) > sizeof(rand_nr)) {
- if (random_r(&rand, &rand_nr))
- fprintf(stderr, "random_r 2 error\n"), exit(1);
- page_nr |= (((unsigned long) rand_nr) << 16) <<
+ page_nr = random();
+ if (sizeof(page_nr) > sizeof(uint32_t)) {
+ page_nr |= (((unsigned long) random()) << 16) <<
16;
}
} else
@@ -501,6 +490,9 @@ static void *uffd_poll_thread(void *arg)
pollfd[1].fd = pipefd[cpu*2];
pollfd[1].events = POLLIN;
+ // Notify the main thread that it can now fork.
+ ready_for_fork = true;
+
for (;;) {
ret = poll(pollfd, 2, -1);
if (!ret)
@@ -548,18 +540,31 @@ static void *uffd_poll_thread(void *arg)
pthread_mutex_t uffd_read_mutex = PTHREAD_MUTEX_INITIALIZER;
+static void sigusr1_handler(int signum, siginfo_t *siginfo, void *ptr)
+{
+ jmp_buf *env;
+ env = pthread_getspecific(long_jmp_key);
+ longjmp(*env, 1);
+}
+
static void *uffd_read_thread(void *arg)
{
unsigned long *this_cpu_userfaults;
struct uffd_msg msg;
+ jmp_buf env;
+ int setjmp_ret;
+
+ pthread_setspecific(long_jmp_key, &env);
this_cpu_userfaults = (unsigned long *) arg;
*this_cpu_userfaults = 0;
pthread_mutex_unlock(&uffd_read_mutex);
- /* from here cancellation is ok */
- for (;;) {
+ // One first return setjmp return 0. On second (fake) return from
+ // longjmp() it returns the provided value, which will be 1 in our case.
+ setjmp_ret = setjmp(env);
+ while (!setjmp_ret) {
if (uffd_read_msg(uffd, &msg))
continue;
(*this_cpu_userfaults) += uffd_handle_page_fault(&msg);
@@ -608,6 +613,7 @@ static int stress(unsigned long *userfaults)
background_thread, (void *)cpu))
return 1;
}
+
for (cpu = 0; cpu < nr_cpus; cpu++)
if (pthread_join(background_threads[cpu], NULL))
return 1;
@@ -640,7 +646,7 @@ static int stress(unsigned long *userfaults)
if (pthread_join(uffd_threads[cpu], &_userfaults[cpu]))
return 1;
} else {
- if (pthread_cancel(uffd_threads[cpu]))
+ if (pthread_kill(uffd_threads[cpu], SIGUSR1))
return 1;
if (pthread_join(uffd_threads[cpu], NULL))
return 1;
@@ -654,10 +660,15 @@ static int userfaultfd_open(int features)
{
struct uffdio_api uffdio_api;
- uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
+ uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY);
if (uffd < 0) {
+ if (errno == ENOSYS) {
+ fprintf(stderr,
+ "userfaultfd syscall not available in this kernel\n");
+ exit(KSFT_SKIP);
+ }
fprintf(stderr,
- "userfaultfd syscall not available in this kernel\n");
+ "userfaultfd syscall failed with errno: %d\n", errno);
return 1;
}
uffd_flags = fcntl(uffd, F_GETFD, NULL);
@@ -914,6 +925,10 @@ static int userfaultfd_events_test(void)
pid_t pid;
char c;
+ // All the syscalls below up to pthread_create will ensure that this
+ // write is completed before, the uffd_thread sets it to true.
+ ready_for_fork = false;
+
printf("testing events (fork, remap, remove): ");
fflush(stdout);
@@ -942,6 +957,11 @@ static int userfaultfd_events_test(void)
if (pthread_create(&uffd_mon, &attr, uffd_poll_thread, NULL))
perror("uffd_poll_thread create"), exit(1);
+ // Wait for the poll_thread to start executing before forking. This is
+ // required to avoid a deadlock, which can happen if poll_thread doesn't
+ // start getting executed by the time fork is invoked.
+ while (!ready_for_fork);
+
pid = fork();
if (pid < 0)
perror("fork"), exit(1);
@@ -974,6 +994,10 @@ static int userfaultfd_sig_test(void)
pid_t pid;
char c;
+ // All the syscalls below up to pthread_create will ensure that this
+ // write is completed before, the uffd_thread sets it to true.
+ ready_for_fork = false;
+
printf("testing signal delivery: ");
fflush(stdout);
@@ -1007,6 +1031,11 @@ static int userfaultfd_sig_test(void)
if (pthread_create(&uffd_mon, &attr, uffd_poll_thread, NULL))
perror("uffd_poll_thread create"), exit(1);
+ // Wait for the poll_thread to start executing before forking. This is
+ // required to avoid a deadlock, which can happen if poll_thread doesn't
+ // start getting executed by the time fork is invoked.
+ while (!ready_for_fork);
+
pid = fork();
if (pid < 0)
perror("fork"), exit(1);
@@ -1036,6 +1065,7 @@ static int userfaultfd_stress(void)
char *tmp_area;
unsigned long nr;
struct uffdio_register uffdio_register;
+ struct sigaction act;
unsigned long cpu;
int err;
unsigned long userfaults[nr_cpus];
@@ -1094,6 +1124,17 @@ static int userfaultfd_stress(void)
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 16*1024*1024);
+ // For handling thread termination of read thread in the absense of
+ // pthread_cancel().
+ pthread_key_create(&long_jmp_key, NULL);
+ memset(&act, 0, sizeof(act));
+ act.sa_sigaction = sigusr1_handler;
+ act.sa_flags = SA_SIGINFO;
+ if (sigaction(SIGUSR1, &act, 0)) {
+ perror("sigaction");
+ return 1;
+ }
+
err = 0;
while (bounces--) {
unsigned long expected_ioctls;
@@ -1215,6 +1256,8 @@ static int userfaultfd_stress(void)
printf("\n");
}
+ pthread_key_delete(long_jmp_key);
+
if (err)
return err;
@@ -1291,6 +1334,9 @@ static void sigalrm(int sig)
int main(int argc, char **argv)
{
+ char randstate[64];
+ unsigned int seed;
+
if (argc < 4)
usage();
@@ -1332,6 +1378,12 @@ int main(int argc, char **argv)
}
printf("nr_pages: %lu, nr_pages_per_cpu: %lu\n",
nr_pages, nr_pages_per_cpu);
+
+ seed = (unsigned int) time(NULL);
+ bzero(&randstate, sizeof(randstate));
+ if (!initstate(seed, randstate, sizeof(randstate)))
+ fprintf(stderr, "srandom_r error\n"), exit(1);
+
return userfaultfd_stress();
}