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