1 /* 2 * Copyright (C) 2012 Red Hat, Inc. 3 * This program is free software; you can redistribute it and/or 4 * modify it under the terms of version 2 of the GNU General Public 5 * License as published by the Free Software Foundation. 6 * 7 * This program is distributed in the hope that it would be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 10 * 11 * Further, this software is distributed without any warranty that it 12 * is free of the rightful claim of any third person regarding 13 * infringement or the like. Any license provided herein, whether 14 * implied or otherwise, applies only to this software file. Patent 15 * licenses, if any, provided herein do not apply to combinations of 16 * this program with other software, or any other product whatsoever. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 21 * 02110-1301, USA. 22 * 23 * thp03 - Case for spliting unaligned memory. 24 * - System will panic if failed. 25 * 26 * Modified form a reproducer for 27 * https://patchwork.kernel.org/patch/1358441/ 28 * Kernel Commit id: 027ef6c87853b0a9df53175063028edb4950d476 29 * There was a bug in THP, will crash happened due to the following 30 * reason according to developers: 31 * 32 * most VM places are using pmd_none but a few are still using 33 * pmd_present. The meaning is about the same for the pmd. However 34 * pmd_present would return the wrong value on PROT_NONE ranges or in 35 * case of a non reproducible race with split_huge_page. 36 * When the code using pmd_present gets a false negative, the kernel will 37 * crash. It's just an annoying DoS with a BUG_ON triggering: no memory 38 * corruption and no data corruption (nor userland nor kernel). 39 */ 40 41 #include <sys/mman.h> 42 #include <sys/types.h> 43 #include <sys/wait.h> 44 #include <fcntl.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <errno.h> 48 #include "mem.h" 49 #include "safe_macros.h" 50 #include "test.h" 51 52 char *TCID = "thp03"; 53 int TST_TOTAL = 1; 54 55 #ifdef MADV_MERGEABLE 56 57 static void thp_test(void); 58 59 static long hugepage_size; 60 static long unaligned_size; 61 static long page_size; 62 63 int main(int argc, char **argv) 64 { 65 int lc; 66 67 tst_parse_opts(argc, argv, NULL, NULL); 68 69 setup(); 70 71 for (lc = 0; TEST_LOOPING(lc); lc++) { 72 tst_count = 0; 73 74 thp_test(); 75 } 76 tst_resm(TPASS, "system didn't crash, pass."); 77 cleanup(); 78 tst_exit(); 79 } 80 81 static void thp_test(void) 82 { 83 void *p; 84 85 p = mmap(NULL, unaligned_size, PROT_READ | PROT_WRITE, 86 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 87 if (p == MAP_FAILED) 88 tst_brkm(TBROK | TERRNO, cleanup, "mmap"); 89 90 memset(p, 0x00, unaligned_size); 91 if (mprotect(p, unaligned_size, PROT_NONE) == -1) 92 tst_brkm(TBROK | TERRNO, cleanup, "mprotect"); 93 94 if (madvise(p + hugepage_size, page_size, MADV_MERGEABLE) == -1) { 95 if (errno == EINVAL) { 96 tst_brkm(TCONF, cleanup, 97 "MADV_MERGEABLE is not enabled/supported"); 98 } else { 99 tst_brkm(TBROK | TERRNO, cleanup, "madvise"); 100 } 101 } 102 103 switch (fork()) { 104 case -1: 105 tst_brkm(TBROK | TERRNO, cleanup, "fork"); 106 case 0: 107 exit(0); 108 default: 109 if (waitpid(-1, NULL, 0) == -1) 110 tst_brkm(TBROK | TERRNO, cleanup, "waitpid"); 111 } 112 } 113 114 void setup(void) 115 { 116 if (access(PATH_THP, F_OK) == -1) 117 tst_brkm(TCONF, NULL, "THP not enabled in kernel?"); 118 119 hugepage_size = read_meminfo("Hugepagesize:") * KB; 120 unaligned_size = hugepage_size * 4 - 1; 121 page_size = SAFE_SYSCONF(NULL, _SC_PAGESIZE); 122 123 tst_sig(FORK, DEF_HANDLER, cleanup); 124 TEST_PAUSE; 125 } 126 127 void cleanup(void) 128 { 129 } 130 131 #else 132 int main(void) 133 { 134 tst_brkm(TCONF, NULL, "Kernel doesn't support MADV_MERGEABLE" 135 " or you need to update your glibc-headers"); 136 } 137 #endif 138