xref: /xnu-11215.61.5/tests/nvram_tests/nvram_nonentitled.c (revision 4f1223e81cd707a65cc109d0b8ad6653699da3c4)
1 #include <darwintest.h>
2 #include "nvram_helper.h"
3 
4 T_GLOBAL_META(T_META_NAMESPACE("xnu.nvram"),
5     T_META_RADAR_COMPONENT_NAME("xnu"),
6     T_META_RADAR_COMPONENT_VERSION("nvram"));
7 
8 static io_registry_entry_t optionsRef = IO_OBJECT_NULL;
9 
10 // xcrun -sdk iphoneos.internal make -C tests nvram_nonentitled && sudo ./tests/build/sym/nvram_nonentitled
11 
12 // Test basic read, write, delete for a random variable
13 T_DECL(TestBasicCmds, "Test basic nvram commands")
14 {
15 	const char *varToTest = "varToTest1";
16 
17 	optionsRef = CreateOptionsRef();
18 
19 	TestVarOp(OP_SET, varToTest, DefaultSetVal, KERN_SUCCESS, optionsRef);
20 	TestVarOp(OP_GET, varToTest, DefaultSetVal, KERN_SUCCESS, optionsRef);
21 	TestVarOp(OP_DEL, varToTest, NULL, KERN_SUCCESS, optionsRef);
22 
23 	ReleaseOptionsRef(optionsRef);
24 }
25 
26 // Test basic read, write, delete for a random variable with random guid
27 T_DECL(TestRandomGuid, "Test random guid")
28 {
29 	const char *varToTest = "11112222-77F8-4392-B4A3-1E7304206516:varToTest3";
30 
31 	optionsRef = CreateOptionsRef();
32 
33 	TestVarOp(OP_SET, varToTest, DefaultSetVal, KERN_SUCCESS, optionsRef);
34 	TestVarOp(OP_GET, varToTest, DefaultSetVal, KERN_SUCCESS, optionsRef);
35 	TestVarOp(OP_DEL, varToTest, NULL, KERN_SUCCESS, optionsRef);
36 
37 	ReleaseOptionsRef(optionsRef);
38 }
39 
40 // Test NVRAM delete with return key works
41 T_DECL(TestDelWRet, "Test NVRAM delete with return key")
42 {
43 	char * varToTest = "testDelWRet";
44 
45 	optionsRef = CreateOptionsRef();
46 
47 	TestVarOp(OP_SET, varToTest, DefaultSetVal, KERN_SUCCESS, optionsRef);
48 	TestVarOp(OP_DEL_RET, varToTest, NULL, KERN_SUCCESS, optionsRef);
49 	TestVarOp(OP_GET, varToTest, NULL, KERN_FAILURE, optionsRef);
50 
51 	ReleaseOptionsRef(optionsRef);
52 }
53 
54 // Test NVRAM Sync
55 T_DECL(TestNVRAMSync, "Test NVRAM Sync")
56 {
57 	optionsRef = CreateOptionsRef();
58 
59 	// NVRAM sync using kIONVRAMSyncNowPropertyKey have a 15min rate limit.
60 	// However, we do not return an error for that not being able to sync due to the rate limit
61 	TestVarOp(OP_SYN, kIONVRAMSyncNowPropertyKey, NULL, KERN_SUCCESS, optionsRef);
62 	// kIONVRAMForceSyncNowPropertyKey bypasses the rate limit
63 	TestVarOp(OP_SYN, kIONVRAMForceSyncNowPropertyKey, NULL, KERN_SUCCESS, optionsRef);
64 
65 	ReleaseOptionsRef(optionsRef);
66 }
67 
68 // Test iokit matching for property
69 T_DECL(TestIOKitMatch, "Test IOKit matching for property")
70 {
71 	const char *varToTest = "iokitTestVar";
72 	const char *pathToTest = CFSTR("IODeviceTree:/options");
73 	const char *propToTest = CFSTR("iokitTestVar");
74 	CFMutableDictionaryRef matchingDict = NULL;
75 
76 	optionsRef = CreateOptionsRef();
77 	TestVarOp(OP_SET, varToTest, DefaultSetVal, KERN_SUCCESS, optionsRef);
78 
79 	matchingDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
80 	if (!matchingDict) {
81 		T_FAIL("Failed to allocate matching dictionary");
82 		goto exit;
83 	}
84 	// match to both path and property
85 	CFDictionaryAddValue(matchingDict, CFSTR(kIOPathMatchKey), pathToTest);
86 	CFDictionaryAddValue(matchingDict, CFSTR(kIOPropertyExistsMatchKey), propToTest);
87 
88 	io_service_t service  = IOServiceGetMatchingService(kIOMasterPortDefault, matchingDict);
89 	if (!service) {
90 		T_FAIL("Failed to get matching service");
91 		goto exit;
92 	}
93 	T_ASSERT_NE(service, IO_OBJECT_NULL, "Got service match for property %s", varToTest);
94 
95 exit:
96 	TestVarOp(OP_DEL, varToTest, NULL, KERN_SUCCESS, optionsRef);
97 	ReleaseOptionsRef(optionsRef);
98 }
99 
100 #if !(__x86_64__)
101 #if (TARGET_OS_OSX)
102 // Test that writing of system variables without system entitlement should fail
103 T_DECL(TestSystem, "Test system guids")
104 {
105 	const char *varToTest = SystemNVRAMGuidString ":" "varToTest2";
106 
107 	optionsRef = CreateOptionsRef();
108 
109 	TestVarOp(OP_SET, varToTest, DefaultSetVal, kIOReturnNotPrivileged, optionsRef);
110 
111 	ReleaseOptionsRef(optionsRef);
112 }
113 #endif /* (TARGET_OS_OSX) */
114 
115 // Test that writing of kernel variables without w/o kernel task should fail
116 T_DECL(TestKernelPrefix, "Test kernel prefix")
117 {
118 	char * varToTest = KernelOnlyVariablePrefix "kernelVar";
119 
120 	optionsRef = CreateOptionsRef();
121 
122 	TestVarOp(OP_SET, varToTest, DefaultSetVal, kIOReturnNotPrivileged, optionsRef);
123 
124 	TestVarOp(OP_GET, varToTest, DefaultSetVal, KERN_FAILURE, optionsRef);
125 
126 	ReleaseOptionsRef(optionsRef);
127 }
128 
129 // Test that variables with KernelOnly bit set cannot be modified from user space
130 T_DECL(TestKernelOnly, "Test variable with TestKernelOnly bit set")
131 {
132 	char * varToTest = "testKernelOnly";
133 
134 	optionsRef = CreateOptionsRef();
135 
136 	TestVarOp(OP_SET, varToTest, DefaultSetVal, kIOReturnNotPrivileged, optionsRef);
137 
138 	ReleaseOptionsRef(optionsRef);
139 }
140 
141 // Test that variables with NeverAllowedToDelete bit set cannot be deleted even with ResetNVram()
142 // To reset nvram, call the test with -r argument:
143 // sudo ./tests/build/sym/nvram_nonentitled -n xnu.nvram.TestImmutable -- -r
144 T_DECL(TestImmutable, "Test immutable variable")
145 {
146 	opterr = 0;
147 	optind = 0;
148 	const char * varToTest = "testNeverDel";
149 
150 	optionsRef = CreateOptionsRef();
151 
152 	TestVarOp(OP_SET, varToTest, DefaultSetVal, KERN_SUCCESS, optionsRef);
153 	TestVarOp(OP_DEL, varToTest, NULL, KERN_FAILURE, optionsRef);
154 
155 	if (getopt(argc, argv, "r") == 'r') {
156 		TestVarOp(OP_RES, NULL, NULL, KERN_SUCCESS, optionsRef);
157 	}
158 	TestVarOp(OP_GET, varToTest, DefaultSetVal, KERN_SUCCESS, optionsRef);
159 
160 	ReleaseOptionsRef(optionsRef);
161 }
162 
163 // Test that variables with ResetNVRAMOnlyDelete bit set can be deleted only by ResetNVram
164 // To reset nvram, call the test with -r argument:
165 // sudo ./tests/build/sym/nvram_nonentitled -n xnu.nvram.TestResetOnlyDel -- -r
166 T_DECL(TestResetOnlyDel, "Test variable with ResetNVRAMOnlyDelete bit set")
167 {
168 	opterr = 0;
169 	optind = 0;
170 	const char * varToTest = "testResetOnlyDel";
171 
172 	optionsRef = CreateOptionsRef();
173 
174 	TestVarOp(OP_SET, varToTest, DefaultSetVal, KERN_SUCCESS, optionsRef);
175 	TestVarOp(OP_DEL, varToTest, NULL, KERN_FAILURE, optionsRef);
176 
177 	if (getopt(argc, argv, "r") == 'r') {
178 		TestVarOp(OP_RES, NULL, NULL, KERN_SUCCESS, optionsRef);
179 		TestVarOp(OP_GET, varToTest, NULL, KERN_FAILURE, optionsRef);
180 	}
181 
182 	ReleaseOptionsRef(optionsRef);
183 }
184 
185 // Test that read of entitled variables without entitlement should fail
186 T_DECL(TestEntRd, "Test read entitled variables")
187 {
188 	char * varToTest = "testEntRd";
189 
190 	optionsRef = CreateOptionsRef();
191 
192 	TestVarOp(OP_SET, varToTest, DefaultSetVal, KERN_SUCCESS, optionsRef);
193 	TestVarOp(OP_GET, varToTest, NULL, KERN_FAILURE, optionsRef);
194 	TestVarOp(OP_DEL, varToTest, NULL, KERN_SUCCESS, optionsRef);
195 
196 	ReleaseOptionsRef(optionsRef);
197 }
198 
199 // Test that writing of entitled variables without entitlement should fail
200 T_DECL(TestEntModRst, "Test write entitled variables")
201 {
202 	char * varToTest = "testEntModRst";
203 
204 	optionsRef = CreateOptionsRef();
205 
206 	TestVarOp(OP_SET, varToTest, DefaultSetVal, kIOReturnNotPrivileged, optionsRef);
207 
208 	ReleaseOptionsRef(optionsRef);
209 }
210 
211 // Test that deleting of entitled variables without entitlement should fail
212 // To reset nvram, call the test with -r argument:
213 // sudo ./tests/build/sym/nvram_nonentitled -n xnu.nvram.TestEntDel -- -r
214 T_DECL(TestEntDel, "Test delete entitled variables")
215 {
216 	opterr = 0;
217 	optind = 0;
218 	char * varToTest = "testEntDel";
219 
220 	optionsRef = CreateOptionsRef();
221 
222 	TestVarOp(OP_SET, varToTest, DefaultSetVal, KERN_SUCCESS, optionsRef);
223 	TestVarOp(OP_DEL, varToTest, NULL, KERN_FAILURE, optionsRef);
224 
225 	if (getopt(argc, argv, "r") == 'r') {
226 		TestVarOp(OP_RES, NULL, NULL, KERN_SUCCESS, optionsRef);
227 		TestVarOp(OP_GET, varToTest, NULL, KERN_FAILURE, optionsRef);
228 	}
229 
230 	ReleaseOptionsRef(optionsRef);
231 }
232 
233 // Test resetting of nvram without entitlement should not erase TestEntRst
234 // To reset nvram, call the test with -r argument:
235 // sudo ./tests/build/sym/nvram_nonentitled -n xnu.nvram.TestEntRst -- -r
236 T_DECL(TestEntRst, "Test reset entitled variables")
237 {
238 	opterr = 0;
239 	optind = 0;
240 	char * varToTest = "testEntRst";
241 
242 	optionsRef = CreateOptionsRef();
243 
244 	TestVarOp(OP_SET, varToTest, DefaultSetVal, KERN_SUCCESS, optionsRef);
245 
246 	if (getopt(argc, argv, "r") == 'r') {
247 		TestVarOp(OP_RES, NULL, NULL, KERN_SUCCESS, optionsRef);
248 		TestVarOp(OP_GET, varToTest, DefaultSetVal, KERN_SUCCESS, optionsRef);
249 	} else {
250 		TestVarOp(OP_DEL, varToTest, NULL, KERN_SUCCESS, optionsRef);
251 		T_PASS("NVram reset not invoked");
252 	}
253 
254 	ReleaseOptionsRef(optionsRef);
255 }
256 
257 // Test nvram types
258 T_DECL(TestTypes, "Test nvram types")
259 {
260 	char * boolVar = "test-bool";
261 	char * numVar  = "test-num";
262 	char * strVar  = "test-str";
263 	char * dataVar = "test-data";
264 
265 	optionsRef = CreateOptionsRef();
266 
267 	TestVarOp(OP_SET, boolVar, "true", KERN_SUCCESS, optionsRef);
268 	TestVarOp(OP_SET, numVar, "123", KERN_SUCCESS, optionsRef);
269 	TestVarOp(OP_SET, strVar, "teststring", KERN_SUCCESS, optionsRef);
270 	TestVarOp(OP_SET, dataVar, "testdata", KERN_SUCCESS, optionsRef);
271 
272 	T_ASSERT_EQ(GetVarType(boolVar, optionsRef), CFBooleanGetTypeID(), "Verified %s type as boolean.\n", boolVar);
273 	T_ASSERT_EQ(GetVarType(numVar, optionsRef), CFNumberGetTypeID(), "Verified %s type as number.\n", numVar);
274 	T_ASSERT_EQ(GetVarType(strVar, optionsRef), CFStringGetTypeID(), "Verified %s type as string.\n", strVar);
275 	T_ASSERT_EQ(GetVarType(dataVar, optionsRef), CFDataGetTypeID(), "Verified %s type as data.\n", dataVar);
276 
277 	TestVarOp(OP_DEL, boolVar, NULL, KERN_SUCCESS, optionsRef);
278 	TestVarOp(OP_DEL, numVar, NULL, KERN_SUCCESS, optionsRef);
279 	TestVarOp(OP_DEL, strVar, NULL, KERN_SUCCESS, optionsRef);
280 	TestVarOp(OP_DEL, dataVar, NULL, KERN_SUCCESS, optionsRef);
281 
282 	ReleaseOptionsRef(optionsRef);
283 }
284 
285 // Test NVRAM Reset
286 // To reset nvram, call the test with -r argument:
287 // sudo ./tests/build/sym/nvram_nonentitled -n xnu.nvram.TestNVRAMReset -- -r
288 T_DECL(TestNVRAMReset, "Test NVRAM Reset")
289 {
290 	opterr = 0;
291 	optind = 0;
292 	const char * varToTest = "testVar1";
293 	const char * varToTestWRand = RandomNVRAMGuidString ":" "testVar2";
294 
295 
296 	optionsRef = CreateOptionsRef();
297 
298 	if (getopt(argc, argv, "r") == 'r') {
299 		TestVarOp(OP_SET, varToTest, DefaultSetVal, KERN_SUCCESS, optionsRef);
300 		TestVarOp(OP_SET, varToTestWRand, DefaultSetVal, KERN_SUCCESS, optionsRef);
301 
302 		TestVarOp(OP_RES, NULL, NULL, KERN_SUCCESS, optionsRef);
303 
304 		TestVarOp(OP_GET, varToTest, NULL, KERN_FAILURE, optionsRef);
305 		TestVarOp(OP_GET, varToTestWRand, NULL, KERN_FAILURE, optionsRef);
306 	} else {
307 		T_PASS("NVram reset not invoked");
308 	}
309 
310 	ReleaseOptionsRef(optionsRef);
311 }
312 
313 // Test NVRAM Obliterate
314 // To obliterate nvram, call the test with -r argument:
315 // sudo ./tests/build/sym/nvram_nonentitled -n xnu.nvram.TestNVRAMOblit -- -r
316 T_DECL(TestNVRAMOblit, "Test NVRAM Obliterate")
317 {
318 	opterr = 0;
319 	optind = 0;
320 	const char * varToTest = "testVar1";
321 	const char * varToTestWRand = RandomNVRAMGuidString ":" "testVar2";
322 	const char * oblitNonSys = CommonNVRAMGuidString ":" "ObliterateNVRam";
323 
324 	optionsRef = CreateOptionsRef();
325 
326 	if (getopt(argc, argv, "r") == 'r') {
327 		TestVarOp(OP_SET, varToTest, DefaultSetVal, KERN_SUCCESS, optionsRef);
328 		TestVarOp(OP_SET, varToTestWRand, DefaultSetVal, KERN_SUCCESS, optionsRef);
329 
330 		TestVarOp(OP_OBL, oblitNonSys, NULL, KERN_SUCCESS, optionsRef);
331 
332 		TestVarOp(OP_GET, varToTest, NULL, KERN_FAILURE, optionsRef);
333 		TestVarOp(OP_GET, varToTestWRand, NULL, KERN_FAILURE, optionsRef);
334 	} else {
335 		T_PASS("NVram obliterate not invoked");
336 	}
337 
338 	ReleaseOptionsRef(optionsRef);
339 }
340 #endif /* !(__x86_64__) */
341