xref: /xnu-10002.61.3/tests/trial_experiments.c (revision 0f4c859e951fba394238ab619495c4e1d54d0f34)
1*0f4c859eSApple OSS Distributions #include <errno.h>
2*0f4c859eSApple OSS Distributions #include <stdlib.h>
3*0f4c859eSApple OSS Distributions #include <libgen.h>
4*0f4c859eSApple OSS Distributions #include <limits.h>
5*0f4c859eSApple OSS Distributions #include <mach-o/dyld.h>
6*0f4c859eSApple OSS Distributions #include <sys/types.h>
7*0f4c859eSApple OSS Distributions #include <sys/sysctl.h>
8*0f4c859eSApple OSS Distributions #include <xlocale.h>
9*0f4c859eSApple OSS Distributions 
10*0f4c859eSApple OSS Distributions #include <darwintest.h>
11*0f4c859eSApple OSS Distributions #include <darwintest_utils.h>
12*0f4c859eSApple OSS Distributions 
13*0f4c859eSApple OSS Distributions #include "drop_priv.h"
14*0f4c859eSApple OSS Distributions #include "test_utils.h"
15*0f4c859eSApple OSS Distributions 
16*0f4c859eSApple OSS Distributions #if ENTITLED
17*0f4c859eSApple OSS Distributions #define SET_TREATMENT_ID set_treatment_id_entitled
18*0f4c859eSApple OSS Distributions #define SET_TREATMENT_ID_DESCR "Can set treatment id with entitlement"
19*0f4c859eSApple OSS Distributions #else /* ENTITLED */
20*0f4c859eSApple OSS Distributions #define SET_TREATMENT_ID set_treatment_id_unentitled
21*0f4c859eSApple OSS Distributions #define SET_TREATMENT_ID_DESCR "Can't set treatment id without entitlement"
22*0f4c859eSApple OSS Distributions #endif /* ENTITLED */
23*0f4c859eSApple OSS Distributions 
24*0f4c859eSApple OSS Distributions T_DECL(SET_TREATMENT_ID, "Verifies that EXPERIMENT sysctls can only be set with the entitlement", T_META_ASROOT(false))
25*0f4c859eSApple OSS Distributions {
26*0f4c859eSApple OSS Distributions #define TEST_STR "testing"
27*0f4c859eSApple OSS Distributions #define IDENTIFIER_LENGTH 36
28*0f4c859eSApple OSS Distributions 
29*0f4c859eSApple OSS Distributions 	int ret;
30*0f4c859eSApple OSS Distributions 	errno_t err;
31*0f4c859eSApple OSS Distributions 	char val[IDENTIFIER_LENGTH + 1] = {0};
32*0f4c859eSApple OSS Distributions 	size_t len = sizeof(val);
33*0f4c859eSApple OSS Distributions 	char new_val[IDENTIFIER_LENGTH + 1] = {0};
34*0f4c859eSApple OSS Distributions 
35*0f4c859eSApple OSS Distributions 	if (!is_development_kernel()) {
36*0f4c859eSApple OSS Distributions 		T_SKIP("skipping test on release kernel");
37*0f4c859eSApple OSS Distributions 	}
38*0f4c859eSApple OSS Distributions 
39*0f4c859eSApple OSS Distributions 	strlcpy(new_val, TEST_STR, sizeof(new_val));
40*0f4c859eSApple OSS Distributions 	if (running_as_root()) {
41*0f4c859eSApple OSS Distributions 		drop_priv();
42*0f4c859eSApple OSS Distributions 	}
43*0f4c859eSApple OSS Distributions 
44*0f4c859eSApple OSS Distributions 	ret = sysctlbyname("kern.trial_treatment_id", val, &len, new_val, strlen(new_val));
45*0f4c859eSApple OSS Distributions 	err = errno;
46*0f4c859eSApple OSS Distributions #if ENTITLED
47*0f4c859eSApple OSS Distributions 	len = sizeof(val);
48*0f4c859eSApple OSS Distributions 	memset(new_val, 0, sizeof(new_val));
49*0f4c859eSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ret, "set kern.trial_treatment_id");
50*0f4c859eSApple OSS Distributions 	/* Cleanup. Set it back to the empty string. */
51*0f4c859eSApple OSS Distributions 	ret = sysctlbyname("kern.trial_treatment_id", val, &len, new_val, 1);
52*0f4c859eSApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "reset kern.trial_treatment_id");
53*0f4c859eSApple OSS Distributions #else
54*0f4c859eSApple OSS Distributions 	T_ASSERT_POSIX_FAILURE(ret, EPERM, "set kern.trial_treatment_id");
55*0f4c859eSApple OSS Distributions #endif /* ENTITLED */
56*0f4c859eSApple OSS Distributions }
57*0f4c859eSApple OSS Distributions 
58*0f4c859eSApple OSS Distributions #if ENTITLED
59*0f4c859eSApple OSS Distributions /* Check min and max value limits on numeric factors */
60*0f4c859eSApple OSS Distributions T_DECL(experiment_factor_numeric_limits,
61*0f4c859eSApple OSS Distributions     "Can only set factors within the legal range.",
62*0f4c859eSApple OSS Distributions     T_META_ASROOT(false))
63*0f4c859eSApple OSS Distributions {
64*0f4c859eSApple OSS Distributions #define kMinVal 5 /* The min value allowed for the testing factor. */
65*0f4c859eSApple OSS Distributions #define kMaxVal 10 /* The max value allowed for the testing factor. */
66*0f4c859eSApple OSS Distributions 	errno_t err;
67*0f4c859eSApple OSS Distributions 	int ret;
68*0f4c859eSApple OSS Distributions 	unsigned int current_val;
69*0f4c859eSApple OSS Distributions 	size_t len = sizeof(current_val);
70*0f4c859eSApple OSS Distributions 	unsigned int new_val;
71*0f4c859eSApple OSS Distributions 
72*0f4c859eSApple OSS Distributions 	if (running_as_root()) {
73*0f4c859eSApple OSS Distributions 		drop_priv();
74*0f4c859eSApple OSS Distributions 	}
75*0f4c859eSApple OSS Distributions 	new_val = kMinVal - 1;
76*0f4c859eSApple OSS Distributions 	ret = sysctlbyname("kern.testing_experiment_factor", &current_val, &len, &new_val, sizeof(new_val));
77*0f4c859eSApple OSS Distributions 	err = errno;
78*0f4c859eSApple OSS Distributions 	T_ASSERT_POSIX_FAILURE(ret, EINVAL, "set kern.testing_experiment_factor below range.");
79*0f4c859eSApple OSS Distributions 
80*0f4c859eSApple OSS Distributions 	new_val = kMaxVal + 1;
81*0f4c859eSApple OSS Distributions 	ret = sysctlbyname("kern.testing_experiment_factor", &current_val, &len, &new_val, sizeof(new_val));
82*0f4c859eSApple OSS Distributions 	err = errno;
83*0f4c859eSApple OSS Distributions 	T_ASSERT_POSIX_FAILURE(ret, EINVAL, "set kern.testing_experiment_factor above range.");
84*0f4c859eSApple OSS Distributions 
85*0f4c859eSApple OSS Distributions 	new_val = kMaxVal;
86*0f4c859eSApple OSS Distributions 	ret = sysctlbyname("kern.testing_experiment_factor", &current_val, &len, &new_val, sizeof(new_val));
87*0f4c859eSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ret, "set kern.testing_experiment_factor at top of range.");
88*0f4c859eSApple OSS Distributions 
89*0f4c859eSApple OSS Distributions 	new_val = kMinVal;
90*0f4c859eSApple OSS Distributions 	ret = sysctlbyname("kern.testing_experiment_factor", &current_val, &len, &new_val, sizeof(new_val));
91*0f4c859eSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ret, "set kern.testing_experiment_factor at bottom of range.");
92*0f4c859eSApple OSS Distributions }
93*0f4c859eSApple OSS Distributions 
94*0f4c859eSApple OSS Distributions static uint64_t original_libmalloc_experiment_value = 0;
95*0f4c859eSApple OSS Distributions 
96*0f4c859eSApple OSS Distributions static void
reset_libmalloc_experiment(void)97*0f4c859eSApple OSS Distributions reset_libmalloc_experiment(void)
98*0f4c859eSApple OSS Distributions {
99*0f4c859eSApple OSS Distributions 	int ret = sysctlbyname("kern.libmalloc_experiments", NULL, NULL, &original_libmalloc_experiment_value, sizeof(original_libmalloc_experiment_value));
100*0f4c859eSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ret, "reset kern.libmalloc_experiments");
101*0f4c859eSApple OSS Distributions }
102*0f4c859eSApple OSS Distributions 
103*0f4c859eSApple OSS Distributions static void
set_libmalloc_experiment(uint64_t val)104*0f4c859eSApple OSS Distributions set_libmalloc_experiment(uint64_t val)
105*0f4c859eSApple OSS Distributions {
106*0f4c859eSApple OSS Distributions 	T_LOG("Setting kern.libmalloc_experiments to %llu", val);
107*0f4c859eSApple OSS Distributions 	size_t len = sizeof(original_libmalloc_experiment_value);
108*0f4c859eSApple OSS Distributions 	int ret = sysctlbyname("kern.libmalloc_experiments", &original_libmalloc_experiment_value, &len, &val, sizeof(val));
109*0f4c859eSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ret, "set kern.libmalloc_experiments");
110*0f4c859eSApple OSS Distributions 	T_ATEND(reset_libmalloc_experiment);
111*0f4c859eSApple OSS Distributions }
112*0f4c859eSApple OSS Distributions 
113*0f4c859eSApple OSS Distributions #define PRINT_APPLE_ARRAY_TOOL "tools/print_apple_array"
114*0f4c859eSApple OSS Distributions /*
115*0f4c859eSApple OSS Distributions  * Spawns a new binary and returns the contents of its apple array
116*0f4c859eSApple OSS Distributions  * (after libsystem initialization).
117*0f4c859eSApple OSS Distributions  */
118*0f4c859eSApple OSS Distributions static char **
get_apple_array(size_t * num_array_entries)119*0f4c859eSApple OSS Distributions get_apple_array(size_t *num_array_entries)
120*0f4c859eSApple OSS Distributions {
121*0f4c859eSApple OSS Distributions 	int ret;
122*0f4c859eSApple OSS Distributions 	char stdout_path[MAXPATHLEN] = "apple_array.txt";
123*0f4c859eSApple OSS Distributions 	dt_resultfile(stdout_path, MAXPATHLEN);
124*0f4c859eSApple OSS Distributions 	int exit_status = 0, signum = 0;
125*0f4c859eSApple OSS Distributions 	char binary_path[MAXPATHLEN], binary_dir[MAXPATHLEN];
126*0f4c859eSApple OSS Distributions 	char *char_ret;
127*0f4c859eSApple OSS Distributions 	const static size_t kMaxNumArguments = 256;
128*0f4c859eSApple OSS Distributions 	size_t linecap = 0;
129*0f4c859eSApple OSS Distributions 	ssize_t linelen = 0;
130*0f4c859eSApple OSS Distributions 	char **apple_array;
131*0f4c859eSApple OSS Distributions 	char **line = NULL;
132*0f4c859eSApple OSS Distributions 	size_t num_lines = 0;
133*0f4c859eSApple OSS Distributions 	FILE *stdout_f = NULL;
134*0f4c859eSApple OSS Distributions 	uint32_t name_size = MAXPATHLEN;
135*0f4c859eSApple OSS Distributions 
136*0f4c859eSApple OSS Distributions 	ret = _NSGetExecutablePath(binary_path, &name_size);
137*0f4c859eSApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(ret, 0, "_NSGetExecutablePath");
138*0f4c859eSApple OSS Distributions 	char_ret = dirname_r(binary_path, binary_dir);
139*0f4c859eSApple OSS Distributions 	T_QUIET; T_ASSERT_TRUE(char_ret != NULL, "dirname_r");
140*0f4c859eSApple OSS Distributions 	snprintf(binary_path, MAXPATHLEN, "%s/%s", binary_dir, PRINT_APPLE_ARRAY_TOOL);
141*0f4c859eSApple OSS Distributions 
142*0f4c859eSApple OSS Distributions 	char *launch_tool_args[] = {
143*0f4c859eSApple OSS Distributions 		binary_path,
144*0f4c859eSApple OSS Distributions 		NULL
145*0f4c859eSApple OSS Distributions 	};
146*0f4c859eSApple OSS Distributions 	pid_t child_pid;
147*0f4c859eSApple OSS Distributions 	ret = dt_launch_tool(&child_pid, launch_tool_args, false, stdout_path, NULL);
148*0f4c859eSApple OSS Distributions 	T_WITH_ERRNO; T_ASSERT_EQ(ret, 0, "dt_launch_tool: %s", binary_path);
149*0f4c859eSApple OSS Distributions 
150*0f4c859eSApple OSS Distributions 	ret = dt_waitpid(child_pid, &exit_status, &signum, 60 * 5);
151*0f4c859eSApple OSS Distributions 	T_ASSERT_EQ(ret, 1, "dt_waitpid");
152*0f4c859eSApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(exit_status, 0, "dt_waitpid: exit_status");
153*0f4c859eSApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(signum, 0, "dt_waitpid: signum");
154*0f4c859eSApple OSS Distributions 
155*0f4c859eSApple OSS Distributions 	stdout_f = fopen(stdout_path, "r");
156*0f4c859eSApple OSS Distributions 	T_WITH_ERRNO; T_ASSERT_NOTNULL(stdout_f, "open(%s)", stdout_path);
157*0f4c859eSApple OSS Distributions 	apple_array = calloc(kMaxNumArguments, sizeof(char *));
158*0f4c859eSApple OSS Distributions 	T_QUIET; T_ASSERT_NOTNULL(apple_array, "calloc: %lu\n", sizeof(char *) * kMaxNumArguments);
159*0f4c859eSApple OSS Distributions 	while (num_lines < kMaxNumArguments) {
160*0f4c859eSApple OSS Distributions 		line = &(apple_array[num_lines++]);
161*0f4c859eSApple OSS Distributions 		linecap = 0;
162*0f4c859eSApple OSS Distributions 		linelen = getline(line, &linecap, stdout_f);
163*0f4c859eSApple OSS Distributions 		if (linelen == -1) {
164*0f4c859eSApple OSS Distributions 			break;
165*0f4c859eSApple OSS Distributions 		}
166*0f4c859eSApple OSS Distributions 	}
167*0f4c859eSApple OSS Distributions 	*num_array_entries = num_lines - 1;
168*0f4c859eSApple OSS Distributions 
169*0f4c859eSApple OSS Distributions 	ret = fclose(stdout_f);
170*0f4c859eSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(ret, "fclose(%s)", stdout_path);
171*0f4c859eSApple OSS Distributions 
172*0f4c859eSApple OSS Distributions 	return apple_array;
173*0f4c859eSApple OSS Distributions }
174*0f4c859eSApple OSS Distributions 
175*0f4c859eSApple OSS Distributions #define LIBMALLOC_EXPERIMENT_FACTORS_KEY "MallocExperiment="
176*0f4c859eSApple OSS Distributions 
177*0f4c859eSApple OSS Distributions /*
178*0f4c859eSApple OSS Distributions  * Get the value of the MallocExperiment key in the apple array.
179*0f4c859eSApple OSS Distributions  * Returns true iff the key is present.
180*0f4c859eSApple OSS Distributions  */
181*0f4c859eSApple OSS Distributions static bool
get_libmalloc_experiment_factors(char ** apple_array,size_t num_array_entries,uint64_t * factors)182*0f4c859eSApple OSS Distributions get_libmalloc_experiment_factors(char **apple_array, size_t num_array_entries, uint64_t *factors)
183*0f4c859eSApple OSS Distributions {
184*0f4c859eSApple OSS Distributions 	bool found = false;
185*0f4c859eSApple OSS Distributions 	for (size_t i = 0; i < num_array_entries; i++) {
186*0f4c859eSApple OSS Distributions 		char *str = apple_array[i];
187*0f4c859eSApple OSS Distributions 		if (strstr(str, LIBMALLOC_EXPERIMENT_FACTORS_KEY)) {
188*0f4c859eSApple OSS Distributions 			found = true;
189*0f4c859eSApple OSS Distributions 			if (factors != NULL) {
190*0f4c859eSApple OSS Distributions 				str = strchr(str, '=');
191*0f4c859eSApple OSS Distributions 				T_ASSERT_NOTNULL(str, "skip over =");
192*0f4c859eSApple OSS Distributions 				++str;
193*0f4c859eSApple OSS Distributions 				*factors = strtoull_l(str, NULL, 16, NULL);
194*0f4c859eSApple OSS Distributions 			}
195*0f4c859eSApple OSS Distributions 			break;
196*0f4c859eSApple OSS Distributions 		}
197*0f4c859eSApple OSS Distributions 	}
198*0f4c859eSApple OSS Distributions 	return found;
199*0f4c859eSApple OSS Distributions }
200*0f4c859eSApple OSS Distributions 
201*0f4c859eSApple OSS Distributions T_DECL(libmalloc_experiment,
202*0f4c859eSApple OSS Distributions     "libmalloc experiment flags show up in apple array if we're doing an experiment",
203*0f4c859eSApple OSS Distributions     T_META_ASROOT(false))
204*0f4c859eSApple OSS Distributions {
205*0f4c859eSApple OSS Distributions 	uint64_t new_val, apple_array_val = 0;
206*0f4c859eSApple OSS Distributions 	size_t num_array_entries = 0;
207*0f4c859eSApple OSS Distributions 	char **apple_array;
208*0f4c859eSApple OSS Distributions 	bool found = false;
209*0f4c859eSApple OSS Distributions 
210*0f4c859eSApple OSS Distributions 	if (running_as_root()) {
211*0f4c859eSApple OSS Distributions 		drop_priv();
212*0f4c859eSApple OSS Distributions 	}
213*0f4c859eSApple OSS Distributions 	new_val = (1ULL << 63) - 1;
214*0f4c859eSApple OSS Distributions 	set_libmalloc_experiment(new_val);
215*0f4c859eSApple OSS Distributions 
216*0f4c859eSApple OSS Distributions 	apple_array = get_apple_array(&num_array_entries);
217*0f4c859eSApple OSS Distributions 	found = get_libmalloc_experiment_factors(apple_array, num_array_entries, &apple_array_val);
218*0f4c859eSApple OSS Distributions 	T_ASSERT_TRUE(found, "Found " LIBMALLOC_EXPERIMENT_FACTORS_KEY " in apple array");
219*0f4c859eSApple OSS Distributions 	T_ASSERT_EQ(apple_array_val, new_val, "Experiment value matches");
220*0f4c859eSApple OSS Distributions 	free(apple_array);
221*0f4c859eSApple OSS Distributions }
222*0f4c859eSApple OSS Distributions 
223*0f4c859eSApple OSS Distributions T_DECL(libmalloc_experiment_not_in_array,
224*0f4c859eSApple OSS Distributions     "libmalloc experiment flags do not show up in apple array if we're not doing an experiment",
225*0f4c859eSApple OSS Distributions     T_META_ASROOT(false))
226*0f4c859eSApple OSS Distributions {
227*0f4c859eSApple OSS Distributions 	size_t num_array_entries = 0;
228*0f4c859eSApple OSS Distributions 	char **apple_array;
229*0f4c859eSApple OSS Distributions 	bool found = false;
230*0f4c859eSApple OSS Distributions 
231*0f4c859eSApple OSS Distributions 	if (running_as_root()) {
232*0f4c859eSApple OSS Distributions 		drop_priv();
233*0f4c859eSApple OSS Distributions 	}
234*0f4c859eSApple OSS Distributions 	set_libmalloc_experiment(0);
235*0f4c859eSApple OSS Distributions 
236*0f4c859eSApple OSS Distributions 	apple_array = get_apple_array(&num_array_entries);
237*0f4c859eSApple OSS Distributions 	found = get_libmalloc_experiment_factors(apple_array, num_array_entries, NULL);
238*0f4c859eSApple OSS Distributions 	T_ASSERT_TRUE(!found, "Did not find " LIBMALLOC_EXPERIMENT_FACTORS_KEY " in apple array");
239*0f4c859eSApple OSS Distributions 	free(apple_array);
240*0f4c859eSApple OSS Distributions }
241*0f4c859eSApple OSS Distributions #endif /* ENTITLED */
242