1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: LGPL-2.1-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (C) 2005-2006 IBM Corporation. 4f08c3bdfSopenharmony_ci * Author: David Gibson & Adam Litke 5f08c3bdfSopenharmony_ci */ 6f08c3bdfSopenharmony_ci 7f08c3bdfSopenharmony_ci/*\ 8f08c3bdfSopenharmony_ci * [Description] 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * This test uses mprotect to change protection of hugepage mapping and 11f08c3bdfSopenharmony_ci * perform read/write operation. It checks if the operation results in 12f08c3bdfSopenharmony_ci * expected behaviour as per the protection. 13f08c3bdfSopenharmony_ci */ 14f08c3bdfSopenharmony_ci#include <setjmp.h> 15f08c3bdfSopenharmony_ci#include "hugetlb.h" 16f08c3bdfSopenharmony_ci 17f08c3bdfSopenharmony_ci#define MNTPOINT "hugetlbfs/" 18f08c3bdfSopenharmony_ci#define RANDOM_CONSTANT 0x1234ABCD 19f08c3bdfSopenharmony_ci 20f08c3bdfSopenharmony_cistatic int fd = -1; 21f08c3bdfSopenharmony_cistatic sigjmp_buf sig_escape; 22f08c3bdfSopenharmony_cistatic void *sig_expected = MAP_FAILED; 23f08c3bdfSopenharmony_cistatic long hpage_size; 24f08c3bdfSopenharmony_cistatic void *addr; 25f08c3bdfSopenharmony_ci 26f08c3bdfSopenharmony_cistatic struct tcase { 27f08c3bdfSopenharmony_ci char *tname; 28f08c3bdfSopenharmony_ci unsigned long len1; 29f08c3bdfSopenharmony_ci int prot1; 30f08c3bdfSopenharmony_ci char *prot1_str; 31f08c3bdfSopenharmony_ci unsigned long len2; 32f08c3bdfSopenharmony_ci int prot2; 33f08c3bdfSopenharmony_ci char *prot2_str; 34f08c3bdfSopenharmony_ci} tcases[] = { 35f08c3bdfSopenharmony_ci {"R->RW", 1, PROT_READ, "PROT_READ", 36f08c3bdfSopenharmony_ci 1, PROT_READ|PROT_WRITE, "PROT_READ|PROT_WRITE"}, 37f08c3bdfSopenharmony_ci 38f08c3bdfSopenharmony_ci {"RW->R", 1, PROT_READ|PROT_WRITE, "PROT_READ|PROT_WRITE", 39f08c3bdfSopenharmony_ci 1, PROT_READ, "PROT_READ"}, 40f08c3bdfSopenharmony_ci 41f08c3bdfSopenharmony_ci {"R->RW 1/2", 2, PROT_READ, "PROT_READ", 42f08c3bdfSopenharmony_ci 1, PROT_READ|PROT_WRITE, "PROT_READ|PROT_WRITE"}, 43f08c3bdfSopenharmony_ci 44f08c3bdfSopenharmony_ci {"RW->R 1/2", 2, PROT_READ|PROT_WRITE, "PROT_READ|PROT_WRITE", 45f08c3bdfSopenharmony_ci 1, PROT_READ, "PROT_READ"}, 46f08c3bdfSopenharmony_ci 47f08c3bdfSopenharmony_ci {"NONE->R", 1, PROT_NONE, "PROT_NONE", 48f08c3bdfSopenharmony_ci 1, PROT_READ, "PROT_READ"}, 49f08c3bdfSopenharmony_ci 50f08c3bdfSopenharmony_ci {"NONE->RW", 1, PROT_NONE, "PROT_NONE", 51f08c3bdfSopenharmony_ci 1, PROT_READ|PROT_WRITE, "PROT_READ|PROT_WRITE"}, 52f08c3bdfSopenharmony_ci}; 53f08c3bdfSopenharmony_ci 54f08c3bdfSopenharmony_cistatic void sig_handler(int signum, siginfo_t *si, void *uc) 55f08c3bdfSopenharmony_ci{ 56f08c3bdfSopenharmony_ci (void)uc; 57f08c3bdfSopenharmony_ci 58f08c3bdfSopenharmony_ci if (signum == SIGSEGV) { 59f08c3bdfSopenharmony_ci tst_res(TINFO, "SIGSEGV at %p (sig_expected=%p)", si->si_addr, 60f08c3bdfSopenharmony_ci sig_expected); 61f08c3bdfSopenharmony_ci if (si->si_addr == sig_expected) 62f08c3bdfSopenharmony_ci siglongjmp(sig_escape, 1); 63f08c3bdfSopenharmony_ci tst_res(TFAIL, "SIGSEGV somewhere unexpected"); 64f08c3bdfSopenharmony_ci } else { 65f08c3bdfSopenharmony_ci tst_res(TFAIL, "Unexpected signal %s", strsignal(signum)); 66f08c3bdfSopenharmony_ci } 67f08c3bdfSopenharmony_ci} 68f08c3bdfSopenharmony_ci 69f08c3bdfSopenharmony_cistatic int test_read(void *p) 70f08c3bdfSopenharmony_ci{ 71f08c3bdfSopenharmony_ci volatile unsigned long *pl = p; 72f08c3bdfSopenharmony_ci unsigned long x; 73f08c3bdfSopenharmony_ci 74f08c3bdfSopenharmony_ci if (sigsetjmp(sig_escape, 1)) { 75f08c3bdfSopenharmony_ci /* We got a SEGV */ 76f08c3bdfSopenharmony_ci sig_expected = MAP_FAILED; 77f08c3bdfSopenharmony_ci return -1; 78f08c3bdfSopenharmony_ci } 79f08c3bdfSopenharmony_ci 80f08c3bdfSopenharmony_ci sig_expected = p; 81f08c3bdfSopenharmony_ci barrier(); 82f08c3bdfSopenharmony_ci x = *pl; 83f08c3bdfSopenharmony_ci tst_res(TINFO, "Read back %lu", x); 84f08c3bdfSopenharmony_ci barrier(); 85f08c3bdfSopenharmony_ci sig_expected = MAP_FAILED; 86f08c3bdfSopenharmony_ci return 0; 87f08c3bdfSopenharmony_ci} 88f08c3bdfSopenharmony_ci 89f08c3bdfSopenharmony_cistatic int test_write(void *p, unsigned long val) 90f08c3bdfSopenharmony_ci{ 91f08c3bdfSopenharmony_ci volatile unsigned long *pl = p; 92f08c3bdfSopenharmony_ci unsigned long x; 93f08c3bdfSopenharmony_ci 94f08c3bdfSopenharmony_ci if (sigsetjmp(sig_escape, 1)) { 95f08c3bdfSopenharmony_ci /* We got a SEGV */ 96f08c3bdfSopenharmony_ci sig_expected = MAP_FAILED; 97f08c3bdfSopenharmony_ci return -1; 98f08c3bdfSopenharmony_ci } 99f08c3bdfSopenharmony_ci 100f08c3bdfSopenharmony_ci sig_expected = p; 101f08c3bdfSopenharmony_ci barrier(); 102f08c3bdfSopenharmony_ci *pl = val; 103f08c3bdfSopenharmony_ci x = *pl; 104f08c3bdfSopenharmony_ci barrier(); 105f08c3bdfSopenharmony_ci sig_expected = MAP_FAILED; 106f08c3bdfSopenharmony_ci 107f08c3bdfSopenharmony_ci return (x != val); 108f08c3bdfSopenharmony_ci} 109f08c3bdfSopenharmony_ci 110f08c3bdfSopenharmony_cistatic int test_prot(void *p, int prot, char *prot_str) 111f08c3bdfSopenharmony_ci{ 112f08c3bdfSopenharmony_ci int r, w; 113f08c3bdfSopenharmony_ci 114f08c3bdfSopenharmony_ci r = test_read(p); 115f08c3bdfSopenharmony_ci tst_res(TINFO, "On Read: %d", r); 116f08c3bdfSopenharmony_ci w = test_write(p, RANDOM_CONSTANT); 117f08c3bdfSopenharmony_ci tst_res(TINFO, "On Write: %d", w); 118f08c3bdfSopenharmony_ci 119f08c3bdfSopenharmony_ci if (prot & PROT_READ) { 120f08c3bdfSopenharmony_ci if (r != 0) { 121f08c3bdfSopenharmony_ci tst_res(TFAIL, "read failed on mmap(prot %s)", prot_str); 122f08c3bdfSopenharmony_ci return -1; 123f08c3bdfSopenharmony_ci } 124f08c3bdfSopenharmony_ci } else { 125f08c3bdfSopenharmony_ci if (r != -1) { 126f08c3bdfSopenharmony_ci tst_res(TFAIL, "read succeeded on mmap(prot %s)", prot_str); 127f08c3bdfSopenharmony_ci return -1; 128f08c3bdfSopenharmony_ci } 129f08c3bdfSopenharmony_ci } 130f08c3bdfSopenharmony_ci 131f08c3bdfSopenharmony_ci if (prot & PROT_WRITE) { 132f08c3bdfSopenharmony_ci switch (w) { 133f08c3bdfSopenharmony_ci case -1: 134f08c3bdfSopenharmony_ci tst_res(TFAIL, "write failed on mmap(prot %s)", prot_str); 135f08c3bdfSopenharmony_ci return -1; 136f08c3bdfSopenharmony_ci case 0: 137f08c3bdfSopenharmony_ci break; 138f08c3bdfSopenharmony_ci case 1: 139f08c3bdfSopenharmony_ci tst_res(TFAIL, "write mismatch on mmap(prot %s)", prot_str); 140f08c3bdfSopenharmony_ci return -1; 141f08c3bdfSopenharmony_ci default: 142f08c3bdfSopenharmony_ci tst_res(TWARN, "Bug in test"); 143f08c3bdfSopenharmony_ci return -1; 144f08c3bdfSopenharmony_ci } 145f08c3bdfSopenharmony_ci } else { 146f08c3bdfSopenharmony_ci switch (w) { 147f08c3bdfSopenharmony_ci case -1: 148f08c3bdfSopenharmony_ci break; 149f08c3bdfSopenharmony_ci case 0: 150f08c3bdfSopenharmony_ci tst_res(TFAIL, "write succeeded on mmap(prot %s)", prot_str); 151f08c3bdfSopenharmony_ci return -1; 152f08c3bdfSopenharmony_ci case 1: 153f08c3bdfSopenharmony_ci tst_res(TFAIL, "write mismatch on mmap(prot %s)", prot_str); 154f08c3bdfSopenharmony_ci return -1; 155f08c3bdfSopenharmony_ci default: 156f08c3bdfSopenharmony_ci tst_res(TWARN, "Bug in test"); 157f08c3bdfSopenharmony_ci break; 158f08c3bdfSopenharmony_ci } 159f08c3bdfSopenharmony_ci } 160f08c3bdfSopenharmony_ci 161f08c3bdfSopenharmony_ci return 0; 162f08c3bdfSopenharmony_ci} 163f08c3bdfSopenharmony_ci 164f08c3bdfSopenharmony_cistatic void run_test(unsigned int i) 165f08c3bdfSopenharmony_ci{ 166f08c3bdfSopenharmony_ci void *p; 167f08c3bdfSopenharmony_ci int ret; 168f08c3bdfSopenharmony_ci struct tcase *tc = &tcases[i]; 169f08c3bdfSopenharmony_ci 170f08c3bdfSopenharmony_ci tst_res(TINFO, "Test Name: %s", tc->tname); 171f08c3bdfSopenharmony_ci 172f08c3bdfSopenharmony_ci p = SAFE_MMAP(NULL, tc->len1*hpage_size, tc->prot1, MAP_SHARED, fd, 0); 173f08c3bdfSopenharmony_ci 174f08c3bdfSopenharmony_ci ret = test_prot(p, tc->prot1, tc->prot1_str); 175f08c3bdfSopenharmony_ci if (ret) 176f08c3bdfSopenharmony_ci goto cleanup; 177f08c3bdfSopenharmony_ci 178f08c3bdfSopenharmony_ci ret = mprotect(p, tc->len2*hpage_size, tc->prot2); 179f08c3bdfSopenharmony_ci if (ret != 0) { 180f08c3bdfSopenharmony_ci tst_res(TFAIL|TERRNO, "%s: mprotect(prot %s)", 181f08c3bdfSopenharmony_ci tc->tname, tc->prot2_str); 182f08c3bdfSopenharmony_ci goto cleanup; 183f08c3bdfSopenharmony_ci } 184f08c3bdfSopenharmony_ci 185f08c3bdfSopenharmony_ci ret = test_prot(p, tc->prot2, tc->prot2_str); 186f08c3bdfSopenharmony_ci if (ret) 187f08c3bdfSopenharmony_ci goto cleanup; 188f08c3bdfSopenharmony_ci 189f08c3bdfSopenharmony_ci if (tc->len2 < tc->len1) 190f08c3bdfSopenharmony_ci ret = test_prot(p + tc->len2*hpage_size, tc->prot1, tc->prot1_str); 191f08c3bdfSopenharmony_ci 192f08c3bdfSopenharmony_ci tst_res(TPASS, "Successfully tested mprotect %s", tc->tname); 193f08c3bdfSopenharmony_ci 194f08c3bdfSopenharmony_cicleanup: 195f08c3bdfSopenharmony_ci SAFE_MUNMAP(p, tc->len1*hpage_size); 196f08c3bdfSopenharmony_ci} 197f08c3bdfSopenharmony_ci 198f08c3bdfSopenharmony_cistatic void setup(void) 199f08c3bdfSopenharmony_ci{ 200f08c3bdfSopenharmony_ci struct sigaction sa = { 201f08c3bdfSopenharmony_ci .sa_sigaction = sig_handler, 202f08c3bdfSopenharmony_ci .sa_flags = SA_SIGINFO, 203f08c3bdfSopenharmony_ci }; 204f08c3bdfSopenharmony_ci 205f08c3bdfSopenharmony_ci hpage_size = tst_get_hugepage_size(); 206f08c3bdfSopenharmony_ci SAFE_SIGACTION(SIGSEGV, &sa, NULL); 207f08c3bdfSopenharmony_ci 208f08c3bdfSopenharmony_ci fd = tst_creat_unlinked(MNTPOINT, 0); 209f08c3bdfSopenharmony_ci addr = SAFE_MMAP(NULL, 2*hpage_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 210f08c3bdfSopenharmony_ci memset(addr, 0, hpage_size); 211f08c3bdfSopenharmony_ci SAFE_MUNMAP(addr, hpage_size); 212f08c3bdfSopenharmony_ci} 213f08c3bdfSopenharmony_ci 214f08c3bdfSopenharmony_cistatic void cleanup(void) 215f08c3bdfSopenharmony_ci{ 216f08c3bdfSopenharmony_ci SAFE_MUNMAP(addr+hpage_size, hpage_size); 217f08c3bdfSopenharmony_ci if (fd >= 0) 218f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 219f08c3bdfSopenharmony_ci} 220f08c3bdfSopenharmony_ci 221f08c3bdfSopenharmony_cistatic struct tst_test test = { 222f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(tcases), 223f08c3bdfSopenharmony_ci .needs_root = 1, 224f08c3bdfSopenharmony_ci .mntpoint = MNTPOINT, 225f08c3bdfSopenharmony_ci .needs_hugetlbfs = 1, 226f08c3bdfSopenharmony_ci .needs_tmpdir = 1, 227f08c3bdfSopenharmony_ci .setup = setup, 228f08c3bdfSopenharmony_ci .cleanup = cleanup, 229f08c3bdfSopenharmony_ci .test = run_test, 230f08c3bdfSopenharmony_ci .hugepages = {2, TST_NEEDS}, 231f08c3bdfSopenharmony_ci}; 232