Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2020 ARM Limited #define _GNU_SOURCE #include <errno.h> #include <pthread.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <time.h> #include <unistd.h> #include <sys/auxv.h> #include <sys/mman.h> #include <sys/prctl.h> #include <sys/types.h> #include <sys/wait.h> #include "kselftest.h" #include "mte_common_util.h" #include "mte_def.h" #define NUM_ITERATIONS 1024 #define MAX_THREADS 5 #define THREAD_ITERATIONS 1000 void *execute_thread(void *x) { pid_t pid = *((pid_t *)x); pid_t tid = gettid(); uint64_t prctl_tag_mask; uint64_t prctl_set; uint64_t prctl_get; uint64_t prctl_tcf; srand(time(NULL) ^ (pid << 16) ^ (tid << 16)); prctl_tag_mask = rand() & 0xffff; if (prctl_tag_mask % 2) prctl_tcf = PR_MTE_TCF_SYNC; else prctl_tcf = PR_MTE_TCF_ASYNC; prctl_set = PR_TAGGED_ADDR_ENABLE | prctl_tcf | (prctl_tag_mask << PR_MTE_TAG_SHIFT); for (int j = 0; j < THREAD_ITERATIONS; j++) { if (prctl(PR_SET_TAGGED_ADDR_CTRL, prctl_set, 0, 0, 0)) { perror("prctl() failed"); goto fail; } prctl_get = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0); if (prctl_set != prctl_get) { ksft_print_msg("Error: prctl_set: 0x%lx != prctl_get: 0x%lx\n", prctl_set, prctl_get); goto fail; } } return (void *)KSFT_PASS; fail: return (void *)KSFT_FAIL; } int execute_test(pid_t pid) { pthread_t thread_id[MAX_THREADS]; int thread_data[MAX_THREADS]; for (int i = 0; i < MAX_THREADS; i++) pthread_create(&thread_id[i], NULL, execute_thread, (void *)&pid); for (int i = 0; i < MAX_THREADS; i++) pthread_join(thread_id[i], (void *)&thread_data[i]); for (int i = 0; i < MAX_THREADS; i++) if (thread_data[i] == KSFT_FAIL) return KSFT_FAIL; return KSFT_PASS; } int mte_gcr_fork_test(void) { pid_t pid; int results[NUM_ITERATIONS]; pid_t cpid; int res; for (int i = 0; i < NUM_ITERATIONS; i++) { pid = fork(); if (pid < 0) return KSFT_FAIL; if (pid == 0) { cpid = getpid(); res = execute_test(cpid); exit(res); } } for (int i = 0; i < NUM_ITERATIONS; i++) { wait(&res); if (WIFEXITED(res)) results[i] = WEXITSTATUS(res); else --i; } for (int i = 0; i < NUM_ITERATIONS; i++) if (results[i] == KSFT_FAIL) return KSFT_FAIL; return KSFT_PASS; } int main(int argc, char *argv[]) { int err; err = mte_default_setup(); if (err) return err; ksft_set_plan(1); evaluate_test(mte_gcr_fork_test(), "Verify that GCR_EL1 is set correctly on context switch\n"); mte_restore_setup(); ksft_print_cnts(); return ksft_get_fail_cnt() == 0 ? KSFT_PASS : KSFT_FAIL; } |