xref: /xnu-12377.41.6/tests/ecc_test.c (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
1*bbb1b6f9SApple OSS Distributions #include <unistd.h>
2*bbb1b6f9SApple OSS Distributions #include <stdio.h>
3*bbb1b6f9SApple OSS Distributions #include <signal.h>
4*bbb1b6f9SApple OSS Distributions 
5*bbb1b6f9SApple OSS Distributions #include <darwintest.h>
6*bbb1b6f9SApple OSS Distributions #include <darwintest_utils.h>
7*bbb1b6f9SApple OSS Distributions 
8*bbb1b6f9SApple OSS Distributions /*
9*bbb1b6f9SApple OSS Distributions  * We're going to inject ECC errors into shared library text, so don't
10*bbb1b6f9SApple OSS Distributions  * run with other tests.
11*bbb1b6f9SApple OSS Distributions  */
12*bbb1b6f9SApple OSS Distributions T_GLOBAL_META(T_META_RUN_CONCURRENTLY(false),
13*bbb1b6f9SApple OSS Distributions     T_META_OWNER("josephb_22"), T_META_OWNER("y_feigelson"),
14*bbb1b6f9SApple OSS Distributions     T_META_NAMESPACE("xnu.vm"),
15*bbb1b6f9SApple OSS Distributions     T_META_RADAR_COMPONENT_NAME("xnu"),
16*bbb1b6f9SApple OSS Distributions     T_META_RADAR_COMPONENT_VERSION("VM"));
17*bbb1b6f9SApple OSS Distributions 
18*bbb1b6f9SApple OSS Distributions /*
19*bbb1b6f9SApple OSS Distributions  * No system(3c) on watchOS, so provide our own.
20*bbb1b6f9SApple OSS Distributions  * returns -1 if fails to run
21*bbb1b6f9SApple OSS Distributions  * returns 0 if process exits normally.
22*bbb1b6f9SApple OSS Distributions  * returns +n if process exits due to signal N
23*bbb1b6f9SApple OSS Distributions  */
24*bbb1b6f9SApple OSS Distributions static int
my_system(const char * command,const char * arg)25*bbb1b6f9SApple OSS Distributions my_system(const char *command, const char *arg)
26*bbb1b6f9SApple OSS Distributions {
27*bbb1b6f9SApple OSS Distributions 	pid_t pid;
28*bbb1b6f9SApple OSS Distributions 	int status = 0;
29*bbb1b6f9SApple OSS Distributions 	int signal = 0;
30*bbb1b6f9SApple OSS Distributions 	int ret;
31*bbb1b6f9SApple OSS Distributions 	const char *argv[] = {
32*bbb1b6f9SApple OSS Distributions 		command,
33*bbb1b6f9SApple OSS Distributions 		"-v",
34*bbb1b6f9SApple OSS Distributions 		arg,
35*bbb1b6f9SApple OSS Distributions 		NULL
36*bbb1b6f9SApple OSS Distributions 	};
37*bbb1b6f9SApple OSS Distributions 
38*bbb1b6f9SApple OSS Distributions 	if (dt_launch_tool(&pid, (char **)(void *)argv, FALSE, NULL, NULL)) {
39*bbb1b6f9SApple OSS Distributions 		return -1;
40*bbb1b6f9SApple OSS Distributions 	}
41*bbb1b6f9SApple OSS Distributions 
42*bbb1b6f9SApple OSS Distributions 	ret = dt_waitpid(pid, &status, &signal, 100);
43*bbb1b6f9SApple OSS Distributions 	if (signal != 0) {
44*bbb1b6f9SApple OSS Distributions 		return signal;
45*bbb1b6f9SApple OSS Distributions 	} else if (status != 0) {
46*bbb1b6f9SApple OSS Distributions 		return status;
47*bbb1b6f9SApple OSS Distributions 	}
48*bbb1b6f9SApple OSS Distributions 	return 0;
49*bbb1b6f9SApple OSS Distributions }
50*bbb1b6f9SApple OSS Distributions 
51*bbb1b6f9SApple OSS Distributions static int
run_helper(const char * arg)52*bbb1b6f9SApple OSS Distributions run_helper(const char *arg)
53*bbb1b6f9SApple OSS Distributions {
54*bbb1b6f9SApple OSS Distributions 	printf("\nNow running \"%s\":\n", arg);
55*bbb1b6f9SApple OSS Distributions 	return my_system("./ecc_test_helper", arg);
56*bbb1b6f9SApple OSS Distributions }
57*bbb1b6f9SApple OSS Distributions 
58*bbb1b6f9SApple OSS Distributions static void
cleanup_after_injections(void)59*bbb1b6f9SApple OSS Distributions cleanup_after_injections(void)
60*bbb1b6f9SApple OSS Distributions {
61*bbb1b6f9SApple OSS Distributions 	(void)sysctlbyname("vm.retired_pages_end_test", NULL, NULL, NULL, 0);
62*bbb1b6f9SApple OSS Distributions }
63*bbb1b6f9SApple OSS Distributions 
64*bbb1b6f9SApple OSS Distributions 
65*bbb1b6f9SApple OSS Distributions /*
66*bbb1b6f9SApple OSS Distributions  * The tests are run in the following order:
67*bbb1b6f9SApple OSS Distributions  *
68*bbb1b6f9SApple OSS Distributions  * - call foo (i.e. private TEXT page)
69*bbb1b6f9SApple OSS Distributions  * - Inject ECC error into foo, then call foo
70*bbb1b6f9SApple OSS Distributions  *
71*bbb1b6f9SApple OSS Distributions  * - call atan (i.e. shared TEXT page)
72*bbb1b6f9SApple OSS Distributions  * - inject ecc error into atan, then call atan
73*bbb1b6f9SApple OSS Distributions  *
74*bbb1b6f9SApple OSS Distributions  * atan() was picked as a shared region function that isn't likely used by any normal daemons.
75*bbb1b6f9SApple OSS Distributions  *
76*bbb1b6f9SApple OSS Distributions  * - reference to clean DATA page with injected error
77*bbb1b6f9SApple OSS Distributions  *
78*bbb1b6f9SApple OSS Distributions  * - reference to dirty DATA page with injected error
79*bbb1b6f9SApple OSS Distributions  *
80*bbb1b6f9SApple OSS Distributions  * - reference to clean private anonymous mmap'd page with injected error
81*bbb1b6f9SApple OSS Distributions  *
82*bbb1b6f9SApple OSS Distributions  * - reference to dirty private anonymous mmap'd page with injected error
83*bbb1b6f9SApple OSS Distributions  *
84*bbb1b6f9SApple OSS Distributions  * - copyout to a page with injected error
85*bbb1b6f9SApple OSS Distributions  */
86*bbb1b6f9SApple OSS Distributions static void
test_body(void)87*bbb1b6f9SApple OSS Distributions test_body(void)
88*bbb1b6f9SApple OSS Distributions {
89*bbb1b6f9SApple OSS Distributions 	int ret;
90*bbb1b6f9SApple OSS Distributions 
91*bbb1b6f9SApple OSS Distributions 	T_ATEND(cleanup_after_injections);
92*bbb1b6f9SApple OSS Distributions 
93*bbb1b6f9SApple OSS Distributions 	/*
94*bbb1b6f9SApple OSS Distributions 	 * test of process TEXT page
95*bbb1b6f9SApple OSS Distributions 	 * since the page is not writeable (therefore clean), we expect to recover
96*bbb1b6f9SApple OSS Distributions 	 */
97*bbb1b6f9SApple OSS Distributions 	ret = run_helper("Yfoo");
98*bbb1b6f9SApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(ret, 0, "First call of foo");
99*bbb1b6f9SApple OSS Distributions 
100*bbb1b6f9SApple OSS Distributions 	ret = run_helper("Xfoo");
101*bbb1b6f9SApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(ret, 0, "Failed to recover from UE in clean app text page");
102*bbb1b6f9SApple OSS Distributions 
103*bbb1b6f9SApple OSS Distributions 	ret = run_helper("Yfoo");
104*bbb1b6f9SApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(ret, 0, "Fixed call of foo");
105*bbb1b6f9SApple OSS Distributions 
106*bbb1b6f9SApple OSS Distributions 	/*
107*bbb1b6f9SApple OSS Distributions 	 * test of shared library TEXT page
108*bbb1b6f9SApple OSS Distributions 	 * since the page is not writeable (therefore clean), we expect to recover
109*bbb1b6f9SApple OSS Distributions 	 */
110*bbb1b6f9SApple OSS Distributions 	ret = run_helper("Yatan");
111*bbb1b6f9SApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(ret, 0, "First call of atan");
112*bbb1b6f9SApple OSS Distributions 
113*bbb1b6f9SApple OSS Distributions 	ret = run_helper("Xatan");
114*bbb1b6f9SApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(ret, 0, "Failed to recover from UE in clean shared region page");
115*bbb1b6f9SApple OSS Distributions 
116*bbb1b6f9SApple OSS Distributions 	ret = run_helper("Yatan");
117*bbb1b6f9SApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(ret, 0, "Fixed call of atan");
118*bbb1b6f9SApple OSS Distributions 
119*bbb1b6f9SApple OSS Distributions 	/*
120*bbb1b6f9SApple OSS Distributions 	 * test of clean DATA page
121*bbb1b6f9SApple OSS Distributions 	 * since the page is clean, we expect to recover
122*bbb1b6f9SApple OSS Distributions 	 */
123*bbb1b6f9SApple OSS Distributions 	ret = run_helper("Xclean");
124*bbb1b6f9SApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(ret, 0, "Failed to recover from UE in clean page");
125*bbb1b6f9SApple OSS Distributions 
126*bbb1b6f9SApple OSS Distributions 	/*
127*bbb1b6f9SApple OSS Distributions 	 * test of dirty DATA page
128*bbb1b6f9SApple OSS Distributions 	 * since the page is dirty, we expect the app to SIGBUS
129*bbb1b6f9SApple OSS Distributions 	 */
130*bbb1b6f9SApple OSS Distributions 	ret = run_helper("Xdirty");
131*bbb1b6f9SApple OSS Distributions 	T_QUIET; T_ASSERT_NE(ret, 0, "Expected to fail from UE in dirty DATA page");
132*bbb1b6f9SApple OSS Distributions 
133*bbb1b6f9SApple OSS Distributions 	/*
134*bbb1b6f9SApple OSS Distributions 	 * test of clean dynamically allocated page
135*bbb1b6f9SApple OSS Distributions 	 * since the page is clean, we expect to recover
136*bbb1b6f9SApple OSS Distributions 	 *
137*bbb1b6f9SApple OSS Distributions 	 * Test is disabled - rdar://124132874 (XNU ECC unit tests - "Xmmap_clean" fails)
138*bbb1b6f9SApple OSS Distributions 	 */
139*bbb1b6f9SApple OSS Distributions 	// ret = run_helper("Xmmap_clean");
140*bbb1b6f9SApple OSS Distributions 	// T_QUIET; T_ASSERT_EQ(ret, 0, "Failed to recover from ECC to clean dynamically allocated page");
141*bbb1b6f9SApple OSS Distributions 
142*bbb1b6f9SApple OSS Distributions 	/*
143*bbb1b6f9SApple OSS Distributions 	 * test of dirty dynamically allocated page
144*bbb1b6f9SApple OSS Distributions 	 * since the page is dirty, we expect the app to SIGBUS
145*bbb1b6f9SApple OSS Distributions 	 */
146*bbb1b6f9SApple OSS Distributions 	ret = run_helper("Xmmap_dirty");
147*bbb1b6f9SApple OSS Distributions 	T_QUIET; T_ASSERT_NE(ret, 0, "Expected to fail from UE in dirty dynamically allocated page");
148*bbb1b6f9SApple OSS Distributions 
149*bbb1b6f9SApple OSS Distributions 	/*
150*bbb1b6f9SApple OSS Distributions 	 * test of ecc during copyout
151*bbb1b6f9SApple OSS Distributions 	 *
152*bbb1b6f9SApple OSS Distributions 	 * although the page is dirty, the page fault error is handled by failing
153*bbb1b6f9SApple OSS Distributions 	 * the copyout syscall.
154*bbb1b6f9SApple OSS Distributions 	 */
155*bbb1b6f9SApple OSS Distributions 	ret = run_helper("Xcopyout");
156*bbb1b6f9SApple OSS Distributions 	T_QUIET; T_ASSERT_NE(ret, 0, "Uncorrected ECC copyout didn't fail");
157*bbb1b6f9SApple OSS Distributions }
158*bbb1b6f9SApple OSS Distributions 
159*bbb1b6f9SApple OSS Distributions static void
cleanup_ecc_test(void)160*bbb1b6f9SApple OSS Distributions cleanup_ecc_test(void)
161*bbb1b6f9SApple OSS Distributions {
162*bbb1b6f9SApple OSS Distributions 	uint value;
163*bbb1b6f9SApple OSS Distributions 	size_t s = sizeof value;
164*bbb1b6f9SApple OSS Distributions 
165*bbb1b6f9SApple OSS Distributions 	// Set testing mode back to default(ACC)
166*bbb1b6f9SApple OSS Distributions 	value = 0;
167*bbb1b6f9SApple OSS Distributions 	(void)sysctlbyname("vm.test_ecc_dcs", NULL, NULL, &value, s);
168*bbb1b6f9SApple OSS Distributions 
169*bbb1b6f9SApple OSS Distributions 	// Restore side effects to default(enabled)
170*bbb1b6f9SApple OSS Distributions 	value = 1;
171*bbb1b6f9SApple OSS Distributions 	(void)sysctlbyname("vm.test_ecc_sideeffects", NULL, NULL, &value, s);
172*bbb1b6f9SApple OSS Distributions }
173*bbb1b6f9SApple OSS Distributions 
174*bbb1b6f9SApple OSS Distributions static void
run_test(bool use_dcs)175*bbb1b6f9SApple OSS Distributions run_test(bool use_dcs)
176*bbb1b6f9SApple OSS Distributions {
177*bbb1b6f9SApple OSS Distributions 	int err;
178*bbb1b6f9SApple OSS Distributions 	uint value = 0;
179*bbb1b6f9SApple OSS Distributions 	size_t s = sizeof value;
180*bbb1b6f9SApple OSS Distributions 
181*bbb1b6f9SApple OSS Distributions 	T_ATEND(cleanup_ecc_test);
182*bbb1b6f9SApple OSS Distributions 
183*bbb1b6f9SApple OSS Distributions 	// Set testing mode to ACC(0) or DCS(1)
184*bbb1b6f9SApple OSS Distributions 	value = (uint)use_dcs;
185*bbb1b6f9SApple OSS Distributions 	err = sysctlbyname("vm.test_ecc_dcs", NULL, NULL, &value, s);
186*bbb1b6f9SApple OSS Distributions 	if (err) {
187*bbb1b6f9SApple OSS Distributions 		T_SKIP("Failed to clear dcs mode");
188*bbb1b6f9SApple OSS Distributions 	}
189*bbb1b6f9SApple OSS Distributions 
190*bbb1b6f9SApple OSS Distributions 	// Set testing mode to uncorrected.
191*bbb1b6f9SApple OSS Distributions 	value = 0;
192*bbb1b6f9SApple OSS Distributions 	err = sysctlbyname("vm.test_corrected_ecc", NULL, NULL, &value, s);
193*bbb1b6f9SApple OSS Distributions 	if (err) {
194*bbb1b6f9SApple OSS Distributions 		T_SKIP("Failed to set uncorrected mode");
195*bbb1b6f9SApple OSS Distributions 	}
196*bbb1b6f9SApple OSS Distributions 
197*bbb1b6f9SApple OSS Distributions 	// Disable side effects for the duration of the test
198*bbb1b6f9SApple OSS Distributions 	value = 0;
199*bbb1b6f9SApple OSS Distributions 	err = sysctlbyname("vm.test_ecc_sideeffects", NULL, NULL, &value, s);
200*bbb1b6f9SApple OSS Distributions 	if (err) {
201*bbb1b6f9SApple OSS Distributions 		T_SKIP("Failed to disable side effects");
202*bbb1b6f9SApple OSS Distributions 	}
203*bbb1b6f9SApple OSS Distributions 
204*bbb1b6f9SApple OSS Distributions 	test_body();
205*bbb1b6f9SApple OSS Distributions }
206*bbb1b6f9SApple OSS Distributions 
207*bbb1b6f9SApple OSS Distributions T_DECL(ecc_uncorrected_test, "test detection and handling of non-fatal ECC uncorrected errors",
208*bbb1b6f9SApple OSS Distributions     T_META_IGNORECRASHES(".*ecc_test_helper.*"),
209*bbb1b6f9SApple OSS Distributions     T_META_ASROOT(true),
210*bbb1b6f9SApple OSS Distributions     T_META_ENABLED(false /* TARGET_CPU_ARM64 && TARGET_OS_OSX */), /* rdar://133461215 */
211*bbb1b6f9SApple OSS Distributions     T_META_REQUIRES_SYSCTL_EQ("vm.retired_pages_end_test", 0),
212*bbb1b6f9SApple OSS Distributions     T_META_TAG_VM_NOT_ELIGIBLE)
213*bbb1b6f9SApple OSS Distributions {
214*bbb1b6f9SApple OSS Distributions 	run_test(false);
215*bbb1b6f9SApple OSS Distributions }
216*bbb1b6f9SApple OSS Distributions 
217*bbb1b6f9SApple OSS Distributions T_DECL(dcs_uncorrected_test, "test detection and handling from non-fatal ECC uncorrected errors (injected via DCS)",
218*bbb1b6f9SApple OSS Distributions     T_META_IGNORECRASHES(".*ecc_test_helper.*"),
219*bbb1b6f9SApple OSS Distributions     T_META_ASROOT(true),
220*bbb1b6f9SApple OSS Distributions     T_META_ENABLED(false /* TARGET_CPU_ARM64 && TARGET_OS_OSX */), /* rdar://133461215 */
221*bbb1b6f9SApple OSS Distributions     T_META_REQUIRES_SYSCTL_EQ("vm.retired_pages_end_test", 0),
222*bbb1b6f9SApple OSS Distributions     T_META_TAG_VM_NOT_ELIGIBLE)
223*bbb1b6f9SApple OSS Distributions {
224*bbb1b6f9SApple OSS Distributions 	run_test(true);
225*bbb1b6f9SApple OSS Distributions }
226