xref: /aosp_15_r20/external/ltp/testcases/kernel/mem/ksm/ksm05.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
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 void sighandler(int sig);
47 
test_ksm(void)48 static void test_ksm(void)
49 {
50 	int status;
51 	long ps;
52 	pid_t pid;
53 	void *ptr;
54 	struct sigaction sa;
55 
56 	memset (&sa, '\0', sizeof(sa));
57 	sa.sa_handler = sighandler;
58 	sa.sa_flags = 0;
59 	TEST(sigaction(SIGSEGV, &sa, NULL));
60 	if (TST_RET == -1)
61 		tst_brk(TBROK | TRERRNO,
62 				"SIGSEGV signal setup failed");
63 
64 	ps = sysconf(_SC_PAGESIZE);
65 
66 	pid = SAFE_FORK();
67 	if (pid == 0) {
68 		ptr = SAFE_MEMALIGN(ps, ps);
69 		if (madvise(ptr, ps, MADV_MERGEABLE) < 0)
70 			tst_brk(TBROK | TERRNO, "madvise");
71 		*(volatile char *)NULL = 0; /* SIGSEGV occurs as expected. */
72 	}
73 	SAFE_WAITPID(pid, &status, WUNTRACED | WCONTINUED);
74 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
75 		tst_brk(TBROK, "invalid signal received: %d", status);
76 
77 	tst_res(TPASS, "still alive.");
78 }
79 
sighandler(int sig)80 static void sighandler(int sig)
81 {
82 	_exit((sig == SIGSEGV) ? 0 : sig);
83 }
84 
85 static struct tst_test test = {
86 	.needs_root = 1,
87 	.forks_child = 1,
88 	.test_all = test_ksm,
89 	.save_restore = (const struct tst_path_val[]) {
90 		{"/sys/kernel/mm/ksm/run", "1", TST_SR_TBROK},
91 		{"/sys/kernel/mm/ksm/smart_scan", "0",
92 			TST_SR_SKIP_MISSING | TST_SR_TBROK_RO},
93 		{}
94 	},
95 	.needs_kconfigs = (const char *const[]){
96 		"CONFIG_KSM=y",
97 		NULL
98 	},
99 	.tags = (const struct tst_tag[]) {
100 		{"CVE", "2011-2183"},
101 		{}
102 	}
103 };
104 
105 #else
106 	TST_TEST_TCONF("no MADV_MERGEABLE found.");
107 #endif
108