• 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_DECL_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 
86 static struct tst_test test = {
87 	.needs_root = 1,
88 	.forks_child = 1,
89 	.test_all = test_ksm,
90 	.save_restore = (const struct tst_path_val[]) {
91 		{"/sys/kernel/mm/ksm/run", "1", TST_SR_TBROK},
92 		{}
93 	},
94 	.needs_kconfigs = (const char *const[]){
95 		"CONFIG_KSM=y",
96 		NULL
97 	},
98 	.tags = (const struct tst_tag[]) {
99 		{"CVE", "2011-2183"},
100 		{}
101 	}
102 };
103 
104 #else
105 	TST_TEST_TCONF("no MADV_MERGEABLE found.");
106 #endif
107