• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * KSM - NULL pointer dereference in ksm_do_scan() (CVE-2011-2183)
3  *
4  * This is a testcase from upstream commit:
5  * 2b472611a32a72f4a118c069c2d62a1a3f087afd.
6  *
7  * an exiting task can race against ksmd::scan_get_next_rmap_item
8  * (http://lkml.org/lkml/2011/6/1/742) easily triggering a NULL pointer
9  * dereference in ksmd.
10  * ksm_scan.mm_slot == &ksm_mm_head with only one registered mm
11  *
12  * CPU 1 (__ksm_exit)          CPU 2 (scan_get_next_rmap_item)
13  *                             list_empty() is false
14  * lock                        slot == &ksm_mm_head
15  * list_del(slot->mm_list)
16  * (list now empty)
17  * unlock
18  *                              lock
19  *                              slot = list_entry(slot->mm_list.next)
20  *                              (list is empty, so slot is still ksm_mm_head)
21  *                              unlock
22  *                              slot->mm == NULL ... Oops
23  *
24  * Close this race by revalidating that the new slot is not simply the list
25  * head again.
26  *
27  * Test Prerequisites:
28  *
29  * *) ksm and ksmtuned daemons need to be disabled. Otherwise, it could
30  *    distrub the testing as they also change some ksm tunables depends
31  *    on current workloads.
32  *
33  * Copyright (C) 2011  Red Hat, Inc.
34  *
35  * This program is free software; you can redistribute it and/or
36  * modify it under the terms of version 2 of the GNU General Public
37  * License as published by the Free Software Foundation.
38  *
39  * This program is distributed in the hope that it would be useful,
40  * but WITHOUT ANY WARRANTY; without even the implied warranty of
41  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
42  *
43  * Further, this software is distributed without any warranty that it
44  * is free of the rightful claim of any third person regarding
45  * infringement or the like.  Any license provided herein, whether
46  * implied or otherwise, applies only to this software file.  Patent
47  * licenses, if any, provided herein do not apply to combinations of
48  * this program with other software, or any other product whatsoever.
49  *
50  * You should have received a copy of the GNU General Public License
51  * along with this program; if not, write the Free Software
52  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
53  * 02110-1301, USA.
54  */
55 
56 #include <sys/types.h>
57 #include <sys/mman.h>
58 #include <sys/stat.h>
59 #include <sys/wait.h>
60 #include <errno.h>
61 #include <fcntl.h>
62 #include <signal.h>
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <string.h>
66 #include <unistd.h>
67 #include "test.h"
68 #include "mem.h"
69 
70 char *TCID = "ksm05";
71 int TST_TOTAL = 1;
72 
73 #ifdef HAVE_MADV_MERGEABLE
74 
75 static int ksm_run_orig;
76 
77 static void sighandler(int sig);
78 
main(int argc,char * argv[])79 int main(int argc, char *argv[])
80 {
81 	int lc, status, ret;
82 	long ps;
83 	pid_t pid;
84 	void *ptr;
85 
86 	tst_parse_opts(argc, argv, NULL, NULL);
87 
88 	ps = sysconf(_SC_PAGESIZE);
89 	setup();
90 
91 	for (lc = 0; TEST_LOOPING(lc); lc++) {
92 		tst_count = 0;
93 
94 		switch (pid = fork()) {
95 		case -1:
96 			tst_brkm(TBROK | TERRNO, cleanup, "fork");
97 		case 0:
98 			ret = posix_memalign(&ptr, ps, ps);
99 			if (ret) {
100 				tst_brkm(TBROK, cleanup, "posix_memalign(): %s",
101 				         tst_strerrno(ret));
102 			}
103 			if (madvise(ptr, ps, MADV_MERGEABLE) < 0)
104 				tst_brkm(TBROK | TERRNO, cleanup, "madvise");
105 			*(char *)NULL = 0;	/* SIGSEGV occurs as expected. */
106 			exit(0);
107 		default:
108 			break;
109 		}
110 		if (waitpid(pid, &status, WUNTRACED | WCONTINUED) == -1)
111 			tst_brkm(TBROK | TERRNO, cleanup, "waitpid");
112 		if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
113 			tst_brkm(TBROK, cleanup,
114 				 "invalid signal received: %d", status);
115 	}
116 
117 	tst_resm(TPASS, "still alive.");
118 	cleanup();
119 	tst_exit();
120 }
121 
sighandler(int sig)122 static void sighandler(int sig)
123 {
124 	_exit((sig == SIGSEGV) ? 0 : sig);
125 }
126 
setup(void)127 void setup(void)
128 {
129 	tst_require_root();
130 
131 	if (tst_kvercmp(2, 6, 32) < 0)
132 		tst_brkm(TCONF, NULL, "2.6.32 or greater kernel required.");
133 
134 	if (access(PATH_KSM, F_OK) == -1)
135 		tst_brkm(TCONF, NULL, "KSM configuration is not enabled");
136 
137 	tst_sig(FORK, sighandler, cleanup);
138 
139 	TEST_PAUSE;
140 
141 	/* save original /sys/kernel/mm/ksm/run value */
142 	SAFE_FILE_SCANF(NULL, PATH_KSM "run", "%d", &ksm_run_orig);
143 
144 	/* echo 1 > /sys/kernel/mm/ksm/run */
145 	SAFE_FILE_PRINTF(NULL, PATH_KSM "run", "1");
146 }
147 
cleanup(void)148 void cleanup(void)
149 {
150 	/* restore /sys/kernel/mm/ksm/run value */
151 	FILE_PRINTF(PATH_KSM "run", "%d", ksm_run_orig);
152 }
153 #else
main(void)154 int main(void)
155 {
156 	tst_brkm(TCONF, NULL, "no MADV_MERGEABLE found.");
157 }
158 #endif
159