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