1 /* 2 * Copyright (c) 2016 Richard Palethorpe <richiejp (at) f-m.fm> 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 /* 19 * Check that accessing a page marked with MADV_HWPOISON results in SIGBUS. 20 * 21 * Test flow: create child process, 22 * map and write to memory, 23 * mark memory with MADV_HWPOISON, 24 * access memory, 25 * if SIGBUS is delivered to child the test passes else it fails 26 * 27 * If the underlying page type of the memory we have mapped does not support 28 * poisoning then the test will fail. We try to map and write to the memory in 29 * such a way that by the time madvise is called the virtual memory address 30 * points to a supported page. However there may be some rare circumstances 31 * where the test produces the wrong result because we have somehow obtained 32 * an unsupported page. In such cases madvise will probably return success, 33 * but no SIGBUS will be produced. 34 * 35 * For more information see <linux source>/Documentation/vm/hwpoison.txt. 36 */ 37 38 #include <stdlib.h> 39 #include <stdio.h> 40 #include <sys/wait.h> 41 #include <fcntl.h> 42 #include <unistd.h> 43 #include <signal.h> 44 #include <errno.h> 45 #include <string.h> 46 47 #include "tst_test.h" 48 #include "lapi/mmap.h" 49 50 static void run_child(void) 51 { 52 const size_t msize = getpagesize(); 53 void *mem = NULL; 54 55 tst_res(TINFO, 56 "mmap(0, %zu, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)", 57 msize); 58 mem = SAFE_MMAP(NULL, 59 msize, 60 PROT_READ | PROT_WRITE, 61 MAP_ANONYMOUS | MAP_PRIVATE, 62 -1, 63 0); 64 memset(mem, 'L', msize); 65 66 tst_res(TINFO, "madvise(%p, %zu, MADV_HWPOISON)", mem, msize); 67 if (madvise(mem, msize, MADV_HWPOISON) == -1) { 68 if (errno == EINVAL) { 69 tst_res(TCONF | TERRNO, 70 "CONFIG_MEMORY_FAILURE probably not set in kconfig"); 71 } else { 72 tst_res(TFAIL | TERRNO, "Could not poison memory"); 73 } 74 exit(0); 75 } 76 77 *((char *)mem) = 'd'; 78 79 tst_res(TFAIL, "Did not receive SIGBUS on accessing poisoned page"); 80 } 81 82 static void run(void) 83 { 84 int status; 85 pid_t pid; 86 87 pid = SAFE_FORK(); 88 if (pid == 0) { 89 run_child(); 90 exit(0); 91 } 92 93 SAFE_WAITPID(pid, &status, 0); 94 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGBUS) { 95 tst_res(TPASS, "Received SIGBUS after accessing poisoned page"); 96 return; 97 } 98 99 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) 100 return; 101 102 tst_res(TFAIL, "Child %s", tst_strstatus(status)); 103 } 104 105 static struct tst_test test = { 106 .test_all = run, 107 .min_kver = "2.6.31", 108 .needs_root = 1, 109 .forks_child = 1 110 }; 111 112