• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * KSM - NULL pointer dereference in ksm_do_scan() (CVE-2011-2183)
15  *
16  * This is a testcase from upstream commit:
17  * 2b472611a32a72f4a118c069c2d62a1a3f087afd.
18  *
19  * an exiting task can race against ksmd::scan_get_next_rmap_item
20  * (http://lkml.org/lkml/2011/6/1/742) easily triggering a NULL pointer
21  * dereference in ksmd.
22  * ksm_scan.mm_slot == &ksm_mm_head with only one registered mm
23  *
24  * CPU 1 (__ksm_exit)          CPU 2 (scan_get_next_rmap_item)
25  *                             list_empty() is false
26  * lock                        slot == &ksm_mm_head
27  * list_del(slot->mm_list)
28  * (list now empty)
29  * unlock
30  *                              lock
31  *                              slot = list_entry(slot->mm_list.next)
32  *                              (list is empty, so slot is still ksm_mm_head)
33  *                              unlock
34  *                              slot->mm == NULL ... Oops
35  *
36  * Close this race by revalidating that the new slot is not simply the list
37  * head again.
38  *
39  * Test Prerequisites:
40  *
41  * *) ksm and ksmtuned daemons need to be disabled. Otherwise, it could
42  *    distrub the testing as they also change some ksm tunables depends
43  *    on current workloads.
44  */
45 
46 #include <sys/wait.h>
47 #include <signal.h>
48 #include <stdlib.h>
49 #include <errno.h>
50 #include "tst_test.h"
51 #include "mem.h"
52 
53 #ifdef HAVE_MADV_MERGEABLE
54 
55 static int ksm_run_orig = -1;
56 static void sighandler(int sig);
57 
test_ksm(void)58 static void test_ksm(void)
59 {
60 	int status;
61 	long ps;
62 	pid_t pid;
63 	void *ptr;
64 	struct sigaction sa;
65 
66 	memset (&sa, '\0', sizeof(sa));
67 	sa.sa_handler = sighandler;
68 	sa.sa_flags = 0;
69 	TEST(sigaction(SIGSEGV, &sa, NULL));
70 	if (TST_RET == -1)
71 		tst_brk(TBROK | TRERRNO,
72 				"SIGSEGV signal setup failed");
73 
74 	ps = sysconf(_SC_PAGESIZE);
75 
76 	pid = SAFE_FORK();
77 	if (pid == 0) {
78 		ptr = SAFE_MEMALIGN(ps, ps);
79 		if (madvise(ptr, ps, MADV_MERGEABLE) < 0)
80 			tst_brk(TBROK | TERRNO, "madvise");
81 		*(volatile char *)NULL = 0; /* SIGSEGV occurs as expected. */
82 	}
83 	SAFE_WAITPID(pid, &status, WUNTRACED | WCONTINUED);
84 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
85 		tst_brk(TBROK, "invalid signal received: %d", status);
86 
87 	tst_res(TPASS, "still alive.");
88 }
89 
sighandler(int sig)90 static void sighandler(int sig)
91 {
92 	_exit((sig == SIGSEGV) ? 0 : sig);
93 }
94 
setup(void)95 static void setup(void)
96 {
97 	if (access(PATH_KSM, F_OK) == -1)
98 		tst_brk(TCONF, "KSM configuration is not enabled");
99 
100 	/* save original /sys/kernel/mm/ksm/run value */
101 	SAFE_FILE_SCANF(PATH_KSM "run", "%d", &ksm_run_orig);
102 
103 	/* echo 1 > /sys/kernel/mm/ksm/run */
104 	SAFE_FILE_PRINTF(PATH_KSM "run", "1");
105 }
106 
cleanup(void)107 static void cleanup(void)
108 {
109 	/* restore /sys/kernel/mm/ksm/run value */
110 	if (ksm_run_orig > 0)
111 		FILE_PRINTF(PATH_KSM "run", "%d", ksm_run_orig);
112 }
113 
114 static struct tst_test test = {
115 	.needs_root = 1,
116 	.forks_child = 1,
117 	.setup = setup,
118 	.cleanup = cleanup,
119 	.test_all = test_ksm,
120 	.min_kver = "2.6.32",
121 };
122 
123 #else
124 	TST_TEST_TCONF("no MADV_MERGEABLE found.");
125 #endif
126