1 /* 2 * Copyright (C) 2011-2017 Red Hat, Inc. 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 12 * the GNU General Public License for more details. 13 */ 14 15 /* Description: 16 * 17 * This is a reproducer of CVE-2011-0999, which fixed by mainline commit 18 * a7d6e4ecdb7648478ddec76d30d87d03d6e22b31: 19 * 20 * "Transparent hugepages can only be created if rmap is fully 21 * functional. So we must prevent hugepages to be created while 22 * is_vma_temporary_stack() is true." 23 * 24 * It will cause a panic something like this, if the patch didn't get 25 * applied: 26 * 27 * kernel BUG at mm/huge_memory.c:1260! 28 * invalid opcode: 0000 [#1] SMP 29 * last sysfs file: /sys/devices/system/cpu/cpu23/cache/index2/shared_cpu_map 30 * .... 31 * 32 * Due to commit da029c11e6b1 which reduced the stack size considerably, we 33 * now perform a binary search to find the largest possible argument we can 34 * use. Only the first iteration of the test performs the search; subsequent 35 * iterations use the result of the search which is stored in some shared 36 * memory. 37 */ 38 39 #include <errno.h> 40 #include <sys/types.h> 41 #include <sys/resource.h> 42 #include <sys/wait.h> 43 #include <stdio.h> 44 #include <string.h> 45 #include <stdlib.h> 46 #include <unistd.h> 47 #include "tst_test.h" 48 #include "mem.h" 49 #include "tst_minmax.h" 50 51 #define ARGS_SZ (256 * 32) 52 53 static struct bisection { 54 long left; 55 long right; 56 long mid; 57 } *bst; 58 59 static char *args[ARGS_SZ]; 60 static char *arg; 61 62 static void thp_test(void) 63 { 64 long prev_left; 65 int pid; 66 67 while (bst->right - bst->left > 1) { 68 pid_t pid = SAFE_FORK(); 69 70 if (!pid) { 71 /* We set mid to left assuming exec will succeed. If 72 * exec fails with E2BIG (and thus returns) then we 73 * restore left and set right to mid instead. 74 */ 75 prev_left = bst->left; 76 bst->mid = (bst->left + bst->right) / 2; 77 bst->left = bst->mid; 78 args[bst->mid] = NULL; 79 80 TEST(execvp("true", args)); 81 if (TST_ERR != E2BIG) 82 tst_brk(TBROK | TTERRNO, "execvp(\"true\", ...)"); 83 bst->left = prev_left; 84 bst->right = bst->mid; 85 exit(0); 86 } 87 88 tst_reap_children(); 89 tst_res(TINFO, "left: %ld, right: %ld, mid: %ld", 90 bst->left, bst->right, bst->mid); 91 } 92 93 /* We end with mid == right or mid == left where right - left = 94 * 1. Regardless we must use left because right is only set to values 95 * which are too large. 96 */ 97 pid = SAFE_FORK(); 98 if (pid == 0) { 99 args[bst->left] = NULL; 100 TEST(execvp("true", args)); 101 if (TST_ERR != E2BIG) 102 tst_brk(TBROK | TTERRNO, "execvp(\"true\", ...)"); 103 exit(0); 104 } 105 tst_reap_children(); 106 107 tst_res(TPASS, "system didn't crash."); 108 } 109 110 static void setup(void) 111 { 112 struct rlimit rl = { 113 .rlim_cur = RLIM_INFINITY, 114 .rlim_max = RLIM_INFINITY, 115 }; 116 int i; 117 long arg_len, arg_count; 118 119 bst = SAFE_MMAP(NULL, sizeof(*bst), 120 PROT_READ | PROT_WRITE, 121 MAP_SHARED | MAP_ANONYMOUS, -1, 0); 122 bst->left = 0; 123 bst->right = ARGS_SZ; 124 125 arg_len = sysconf(_SC_PAGESIZE); 126 arg = SAFE_MALLOC(arg_len); 127 memset(arg, 'c', arg_len - 1); 128 arg[arg_len - 1] = '\0'; 129 130 args[0] = "true"; 131 arg_count = ARGS_SZ; 132 tst_res(TINFO, "Using %ld args of size %ld", arg_count, arg_len); 133 for (i = 1; i < arg_count; i++) 134 args[i] = arg; 135 136 SAFE_SETRLIMIT(RLIMIT_STACK, &rl); 137 } 138 139 static void cleanup(void) 140 { 141 free(arg); 142 } 143 144 static struct tst_test test = { 145 .needs_root = 1, 146 .forks_child = 1, 147 .setup = setup, 148 .cleanup = cleanup, 149 .test_all = thp_test, 150 }; 151