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