1 /* 2 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved. 3 * Copyright (c) 2007-2021 Apple Inc. All rights reserved. 4 * 5 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 6 * 7 * This file contains Original Code and/or Modifications of Original Code 8 * as defined in and that are subject to the Apple Public Source License 9 * Version 2.0 (the 'License'). You may not use this file except in 10 * compliance with the License. The rights granted to you under the License 11 * may not be used to create, or enable the creation or redistribution of, 12 * unlawful or unlicensed copies of an Apple operating system, or to 13 * circumvent, violate, or enable the circumvention or violation of, any 14 * terms of an Apple operating system software license agreement. 15 * 16 * Please obtain a copy of the License at 17 * http://www.opensource.apple.com/apsl/ and read it before using this file. 18 * 19 * The Original Code and all software distributed under the License are 20 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 21 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 22 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 23 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 24 * Please see the License for the specific language governing rights and 25 * limitations under the License. 26 * 27 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 28 */ 29 30 #define IOKIT_ENABLE_SHARED_PTR 31 32 #include <AssertMacros.h> 33 #include <IOKit/IOLib.h> 34 #include <IOKit/IONVRAM.h> 35 #include <IOKit/IOPlatformExpert.h> 36 #include <IOKit/IOUserClient.h> 37 #include <IOKit/IOKitKeys.h> 38 #include <IOKit/IOKitKeysPrivate.h> 39 #include <IOKit/IOBSD.h> 40 #include <kern/debug.h> 41 #include <os/system_event_log.h> 42 #include <pexpert/boot.h> 43 #include <sys/csr.h> 44 45 #define super IOService 46 47 OSDefineMetaClassAndStructors(IODTNVRAM, IOService); 48 49 class IONVRAMCHRPHandler; 50 class IONVRAMV3Handler; 51 52 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) 53 54 #define MAX_VAR_NAME_SIZE 63 55 56 #define kNVRAMBankSizeKey "nvram-bank-size" 57 #define kNVRAMBankCountKey "nvram-bank-count" 58 #define kNVRAMCurrentBankKey "nvram-current-bank" 59 60 #define kCurrentGenerationCountKey "Generation" 61 #define kCurrentNVRAMVersionKey "Version" 62 63 #define kNVRAMCommonUsedKey "CommonUsed" 64 #define kNVRAMSystemUsedKey "SystemUsed" 65 66 #define kIONVRAMPrivilege kIOClientPrivilegeAdministrator 67 68 #define MIN_SYNC_NOW_INTERVAL 15*60 /* Minimum 15 Minutes interval mandated */ 69 70 #if defined(DEBUG) || defined(DEVELOPMENT) 71 #define DEBUG_IFERROR(err, fmt, args...) \ 72 ({ \ 73 if ((err != kIOReturnSuccess) || gNVRAMLogging) \ 74 IOLog("%s:%s:%u - " fmt, __FILE_NAME__, __FUNCTION__, __LINE__, ##args); \ 75 }) 76 77 #define DEBUG_INFO(fmt, args...) \ 78 ({ \ 79 if (gNVRAMLogging) \ 80 IOLog("%s:%s:%u - " fmt, __FILE_NAME__, __FUNCTION__, __LINE__, ##args); \ 81 }) 82 83 #define DEBUG_ALWAYS(fmt, args...) \ 84 ({ \ 85 IOLog("%s:%s:%u - " fmt, __FILE_NAME__, __FUNCTION__, __LINE__, ##args); \ 86 }) 87 #else 88 #define DEBUG_IFERROR(err, fmt, args...) (void)NULL 89 #define DEBUG_INFO(fmt, args...) (void)NULL 90 #define DEBUG_ALWAYS(fmt, args...) (void)NULL 91 #endif 92 93 #define DEBUG_ERROR DEBUG_ALWAYS 94 95 #define SAFE_TO_LOCK() (preemption_enabled() && !panic_active()) 96 97 #define CONTROLLERLOCK() \ 98 ({ \ 99 if (SAFE_TO_LOCK()) \ 100 IOLockLock(_controllerLock); \ 101 }) 102 103 #define CONTROLLERUNLOCK() \ 104 ({ \ 105 if (SAFE_TO_LOCK()) \ 106 IOLockUnlock(_controllerLock); \ 107 }) 108 109 #define NVRAMREADLOCK() \ 110 ({ \ 111 if (SAFE_TO_LOCK()) \ 112 IORWLockRead(_variableLock); \ 113 }) 114 115 #define NVRAMWRITELOCK() \ 116 ({ \ 117 if (SAFE_TO_LOCK()) \ 118 IORWLockWrite(_variableLock); \ 119 }) 120 121 #define NVRAMUNLOCK() \ 122 ({ \ 123 if (SAFE_TO_LOCK()) \ 124 IORWLockUnlock(_variableLock); \ 125 }) 126 127 #define NVRAMLOCKASSERTHELD() \ 128 ({ \ 129 if (SAFE_TO_LOCK()) \ 130 IORWLockAssert(_variableLock, kIORWLockAssertHeld); \ 131 }) 132 133 #define NVRAMLOCKASSERTEXCLUSIVE() \ 134 ({ \ 135 if (SAFE_TO_LOCK()) \ 136 IORWLockAssert(_variableLock, kIORWLockAssertWrite); \ 137 }) 138 139 // MOD = Write, Delete 140 // RST = Reset, Obliterate 141 // RD = Read 142 // DEL = Delete 143 #define ENT_MOD_RST ((1 << kIONVRAMOperationWrite) | (1 << kIONVRAMOperationDelete) | (1 << kIONVRAMOperationObliterate) | (1 << kIONVRAMOperationReset)) 144 #define ENT_MOD_RD ((1 << kIONVRAMOperationRead) | (1 << kIONVRAMOperationWrite) | (1 << kIONVRAMOperationDelete)) 145 #define ENT_MOD ((1 << kIONVRAMOperationWrite) | (1 << kIONVRAMOperationDelete)) 146 #define ENT_RST ((1 << kIONVRAMOperationObliterate) | (1 << kIONVRAMOperationReset)) 147 #define ENT_RD ((1 << kIONVRAMOperationRead)) 148 #define ENT_DEL ((1 << kIONVRAMOperationDelete)) 149 150 enum NVRAMVersion { 151 kNVRAMVersionUnknown, 152 kNVRAMVersion1, // Legacy, banks, 0x800 common partition size 153 kNVRAMVersion2, // V1 but with (0x2000 - sizeof(struct apple_nvram_header) - sizeof(struct chrp_nvram_header)) common region 154 kNVRAMVersion3, // New EFI based format 155 kNVRAMVersionMax 156 }; 157 158 // Guid for Apple System Boot variables 159 // 40A0DDD2-77F8-4392-B4A3-1E7304206516 160 UUID_DEFINE(gAppleSystemVariableGuid, 0x40, 0xA0, 0xDD, 0xD2, 0x77, 0xF8, 0x43, 0x92, 0xB4, 0xA3, 0x1E, 0x73, 0x04, 0x20, 0x65, 0x16); 161 162 // Apple NVRAM Variable namespace (APPLE_VENDOR_OS_VARIABLE_GUID) 163 // 7C436110-AB2A-4BBB-A880-FE41995C9F82 164 UUID_DEFINE(gAppleNVRAMGuid, 0x7C, 0x43, 0x61, 0x10, 0xAB, 0x2A, 0x4B, 0xBB, 0xA8, 0x80, 0xFE, 0x41, 0x99, 0x5C, 0x9F, 0x82); 165 166 // Wifi NVRAM namespace 167 // 36C28AB5-6566-4C50-9EBD-CBB920F83843 168 UUID_DEFINE(gAppleWifiGuid, 0x36, 0xC2, 0x8A, 0xB5, 0x65, 0x66, 0x4C, 0x50, 0x9E, 0xBD, 0xCB, 0xB9, 0x20, 0xF8, 0x38, 0x43); 169 170 // Prefix for kernel-only variables 171 #define KERNEL_ONLY_VAR_NAME_PREFIX "krn." 172 173 static TUNABLE(bool, gNVRAMLogging, "nvram-log", false); 174 static bool gInternalBuild = false; 175 176 // IONVRAMSystemVariableListInternal: 177 // Used for internal builds only 178 // "force-lock-bits" used by fwam over ssh nvram to device so they are unable to use entitlements 179 // "stress-rack" used in SEG stress-rack restore prdocs 180 #define IONVRAMSystemVariableListInternal IONVRAMSystemVariableList, \ 181 "force-lock-bits", \ 182 "stress-rack" 183 184 // allowlist variables from macboot that need to be set/get from system region if present 185 static const char * const gNVRAMSystemList[] = { IONVRAMSystemVariableList, nullptr }; 186 static const char * const gNVRAMSystemListInternal[] = { IONVRAMSystemVariableListInternal, nullptr }; 187 188 typedef struct { 189 const char *name; 190 IONVRAMVariableType type; 191 } VariableTypeEntry; 192 193 static const 194 VariableTypeEntry gVariableTypes[] = { 195 {"auto-boot?", kOFVariableTypeBoolean}, 196 {"boot-args", kOFVariableTypeString}, 197 {"boot-command", kOFVariableTypeString}, 198 {"boot-device", kOFVariableTypeString}, 199 {"boot-file", kOFVariableTypeString}, 200 {"boot-screen", kOFVariableTypeString}, 201 {"boot-script", kOFVariableTypeString}, 202 {"console-screen", kOFVariableTypeString}, 203 {"default-client-ip", kOFVariableTypeString}, 204 {"default-gateway-ip", kOFVariableTypeString}, 205 {"default-mac-address?", kOFVariableTypeBoolean}, 206 {"default-router-ip", kOFVariableTypeString}, 207 {"default-server-ip", kOFVariableTypeString}, 208 {"default-subnet-mask", kOFVariableTypeString}, 209 {"diag-device", kOFVariableTypeString}, 210 {"diag-file", kOFVariableTypeString}, 211 {"diag-switch?", kOFVariableTypeBoolean}, 212 {"fcode-debug?", kOFVariableTypeBoolean}, 213 {"input-device", kOFVariableTypeString}, 214 {"input-device-1", kOFVariableTypeString}, 215 {"little-endian?", kOFVariableTypeBoolean}, 216 {"ldm", kOFVariableTypeBoolean}, 217 {"load-base", kOFVariableTypeNumber}, 218 {"mouse-device", kOFVariableTypeString}, 219 {"nvramrc", kOFVariableTypeString}, 220 {"oem-banner", kOFVariableTypeString}, 221 {"oem-banner?", kOFVariableTypeBoolean}, 222 {"oem-logo", kOFVariableTypeString}, 223 {"oem-logo?", kOFVariableTypeBoolean}, 224 {"output-device", kOFVariableTypeString}, 225 {"output-device-1", kOFVariableTypeString}, 226 {"pci-probe-list", kOFVariableTypeNumber}, 227 {"pci-probe-mask", kOFVariableTypeNumber}, 228 {"real-base", kOFVariableTypeNumber}, 229 {"real-mode?", kOFVariableTypeBoolean}, 230 {"real-size", kOFVariableTypeNumber}, 231 {"screen-#columns", kOFVariableTypeNumber}, 232 {"screen-#rows", kOFVariableTypeNumber}, 233 {"security-mode", kOFVariableTypeString}, 234 {"selftest-#megs", kOFVariableTypeNumber}, 235 {"use-generic?", kOFVariableTypeBoolean}, 236 {"use-nvramrc?", kOFVariableTypeBoolean}, 237 {"virt-base", kOFVariableTypeNumber}, 238 {"virt-size", kOFVariableTypeNumber}, 239 // Variables used for testing 240 {"test-bool", kOFVariableTypeBoolean}, 241 {"test-num", kOFVariableTypeNumber}, 242 {"test-str", kOFVariableTypeString}, 243 {"test-data", kOFVariableTypeData}, 244 #if !defined(__x86_64__) 245 {"acc-cm-override-charger-count", kOFVariableTypeNumber}, 246 {"acc-cm-override-count", kOFVariableTypeNumber}, 247 {"acc-mb-ld-lifetime", kOFVariableTypeNumber}, 248 {"com.apple.System.boot-nonce", kOFVariableTypeString}, 249 {"darkboot", kOFVariableTypeBoolean}, 250 {"enter-tdm-mode", kOFVariableTypeBoolean}, 251 #endif /* !defined(__x86_64__) */ 252 {nullptr, kOFVariableTypeData} // Default type to return 253 }; 254 255 union VariablePermission { 256 struct { 257 uint64_t UserWrite :1; 258 uint64_t RootRequired :1; 259 uint64_t KernelOnly :1; 260 uint64_t ResetNVRAMOnlyDelete :1; 261 uint64_t NeverAllowedToDelete :1; 262 uint64_t SystemReadHidden :1; 263 uint64_t FullAccess :1; 264 uint64_t InternalOnly :1; 265 uint64_t Reserved:57; 266 } Bits; 267 uint64_t Uint64; 268 }; 269 270 typedef struct { 271 const char *name; 272 VariablePermission p; 273 } VariablePermissionEntry; 274 275 static const 276 VariablePermissionEntry gVariablePermissions[] = { 277 {"aapl,pci", .p.Bits.RootRequired = 1}, 278 {"battery-health", .p.Bits.RootRequired = 1, 279 .p.Bits.NeverAllowedToDelete = 1}, 280 {"boot-image", .p.Bits.UserWrite = 1}, 281 {"com.apple.System.fp-state", .p.Bits.KernelOnly = 1}, 282 {"fm-account-masked", .p.Bits.RootRequired = 1, 283 .p.Bits.NeverAllowedToDelete = 1}, 284 {"fm-activation-locked", .p.Bits.RootRequired = 1, 285 .p.Bits.NeverAllowedToDelete = 1}, 286 {"fm-spkeys", .p.Bits.RootRequired = 1, 287 .p.Bits.NeverAllowedToDelete = 1}, 288 {"fm-spstatus", .p.Bits.RootRequired = 1, 289 .p.Bits.NeverAllowedToDelete = 1}, 290 {"policy-nonce-digests", .p.Bits.ResetNVRAMOnlyDelete = 1}, // Deleting this via user triggered obliterate leave J273a unable to boot 291 {"recoveryos-passcode-blob", .p.Bits.SystemReadHidden = 1}, 292 {"security-password", .p.Bits.RootRequired = 1}, 293 {"system-passcode-lock-blob", .p.Bits.SystemReadHidden = 1}, 294 295 #if !defined(__x86_64__) 296 {"acc-cm-override-charger-count", .p.Bits.KernelOnly = 1}, 297 {"acc-cm-override-count", .p.Bits.KernelOnly = 1}, 298 {"acc-mb-ld-lifetime", .p.Bits.KernelOnly = 1}, 299 {"backlight-level", .p.Bits.UserWrite = 1}, 300 {"backlight-nits", .p.Bits.UserWrite = 1}, 301 {"ldm", .p.Bits.KernelOnly = 1}, 302 {"com.apple.System.boot-nonce", .p.Bits.KernelOnly = 1}, 303 {"com.apple.System.sep.art", .p.Bits.KernelOnly = 1}, 304 {"darkboot", .p.Bits.UserWrite = 1}, 305 {"nonce-seeds", .p.Bits.KernelOnly = 1}, 306 #endif /* !defined(__x86_64__) */ 307 // Variables used for testing permissions 308 {"testSysReadHidden", .p.Bits.SystemReadHidden = 1}, 309 {"testKernelOnly", .p.Bits.KernelOnly = 1}, 310 {"testResetOnlyDel", .p.Bits.ResetNVRAMOnlyDelete = 1}, 311 {"testNeverDel", .p.Bits.NeverAllowedToDelete = 1}, 312 {"testUserWrite", .p.Bits.UserWrite = 1}, 313 {"testRootReq", .p.Bits.RootRequired = 1}, 314 {"reclaim-int", .p.Bits.InternalOnly = 1}, 315 {nullptr, {.Bits.FullAccess = 1}} // Default access 316 }; 317 318 typedef struct { 319 const uint8_t checkOp; 320 const uuid_t *varGuid; 321 const char *varName; 322 const char *varEntitlement; 323 } VariableEntitlementEntry; 324 325 // variable-guid pair entries that require entitlement check to do specified nvram operations 326 static const 327 VariableEntitlementEntry gVariableEntitlements[] = { 328 {ENT_MOD_RST, &gAppleNVRAMGuid, "ownership-warning", "com.apple.private.iokit.ddl-write"}, 329 {ENT_MOD, &gAppleSystemVariableGuid, "BluetoothInfo", "com.apple.private.iokit.nvram-bluetooth"}, 330 {ENT_MOD, &gAppleSystemVariableGuid, "BluetoothUHEDevices", "com.apple.private.iokit.nvram-bluetooth"}, 331 {ENT_MOD, &gAppleNVRAMGuid, "bluetoothExternalDongleFailed", "com.apple.private.iokit.nvram-bluetooth"}, 332 {ENT_MOD, &gAppleNVRAMGuid, "bluetoothInternalControllerInfo", "com.apple.private.iokit.nvram-bluetooth"}, 333 {ENT_RD, &gAppleSystemVariableGuid, "current-network", "com.apple.private.security.nvram.wifi-psks"}, 334 {ENT_RD, &gAppleWifiGuid, "current-network", "com.apple.private.security.nvram.wifi-psks"}, 335 {ENT_RD, &gAppleSystemVariableGuid, "preferred-networks", "com.apple.private.security.nvram.wifi-psks"}, 336 {ENT_RD, &gAppleWifiGuid, "preferred-networks", "com.apple.private.security.nvram.wifi-psks"}, 337 {ENT_RD, &gAppleSystemVariableGuid, "preferred-count", "com.apple.private.security.nvram.wifi-psks"}, 338 {ENT_RD, &gAppleWifiGuid, "preferred-count", "com.apple.private.security.nvram.wifi-psks"}, 339 // Variables used for testing entitlement 340 {ENT_MOD_RST, &gAppleNVRAMGuid, "testEntModRst", "com.apple.private.iokit.testEntModRst"}, 341 {ENT_MOD_RST, &gAppleSystemVariableGuid, "testEntModRstSys", "com.apple.private.iokit.testEntModRst"}, 342 {ENT_RST, &gAppleNVRAMGuid, "testEntRst", "com.apple.private.iokit.testEntRst"}, 343 {ENT_RST, &gAppleSystemVariableGuid, "testEntRstSys", "com.apple.private.iokit.testEntRst"}, 344 {ENT_RD, &gAppleNVRAMGuid, "testEntRd", "com.apple.private.iokit.testEntRd"}, 345 {ENT_RD, &gAppleSystemVariableGuid, "testEntRdSys", "com.apple.private.iokit.testEntRd"}, 346 {ENT_DEL, &gAppleNVRAMGuid, "testEntDel", "com.apple.private.iokit.testEntDel"}, 347 {ENT_DEL, &gAppleSystemVariableGuid, "testEntDelSys", "com.apple.private.iokit.testEntDel"}, 348 {0, &UUID_NULL, nullptr, nullptr} 349 }; 350 351 static NVRAMPartitionType 352 getPartitionTypeForGUID(const uuid_t guid) 353 { 354 if (uuid_compare(guid, gAppleSystemVariableGuid) == 0) { 355 return kIONVRAMPartitionSystem; 356 } else { 357 return kIONVRAMPartitionCommon; 358 } 359 } 360 361 static IONVRAMVariableType 362 getVariableType(const char *propName) 363 { 364 const VariableTypeEntry *entry; 365 366 entry = gVariableTypes; 367 while (entry->name != nullptr) { 368 if (strcmp(entry->name, propName) == 0) { 369 break; 370 } 371 entry++; 372 } 373 374 return entry->type; 375 } 376 377 static IONVRAMVariableType 378 getVariableType(const OSSymbol *propSymbol) 379 { 380 return getVariableType(propSymbol->getCStringNoCopy()); 381 } 382 383 static VariablePermission 384 getVariablePermission(const char *propName) 385 { 386 const VariablePermissionEntry *entry; 387 388 entry = gVariablePermissions; 389 while (entry->name != nullptr) { 390 if (strcmp(entry->name, propName) == 0) { 391 break; 392 } 393 entry++; 394 } 395 396 return entry->p; 397 } 398 399 static bool 400 variableInAllowList(const char *varName) 401 { 402 unsigned int i = 0; 403 const char * const *list = gInternalBuild ? gNVRAMSystemListInternal : gNVRAMSystemList; 404 405 while (list[i] != nullptr) { 406 if (strcmp(varName, list[i]) == 0) { 407 return true; 408 } 409 i++; 410 } 411 412 return false; 413 } 414 415 static bool 416 verifyWriteSizeLimit(const uuid_t varGuid, const char *variableName, size_t propDataSize) 417 { 418 if (variableInAllowList(variableName)) { 419 return propDataSize <= BOOT_LINE_LENGTH; 420 } 421 422 return true; 423 } 424 425 #if defined(DEBUG) || defined(DEVELOPMENT) 426 static const char * 427 getNVRAMOpString(IONVRAMOperation op) 428 { 429 switch (op) { 430 case kIONVRAMOperationRead: 431 return "Read"; 432 case kIONVRAMOperationWrite: 433 return "Write"; 434 case kIONVRAMOperationDelete: 435 return "Delete"; 436 case kIONVRAMOperationObliterate: 437 return "Obliterate"; 438 case kIONVRAMOperationReset: 439 return "Reset"; 440 case kIONVRAMOperationInit: 441 return "Init"; 442 default: 443 return "Unknown"; 444 } 445 } 446 #endif 447 448 /* 449 * Parse a variable name of the form "GUID:name". 450 * If the name cannot be parsed, substitute the Apple global variable GUID. 451 * Returns TRUE if a GUID was found in the name, FALSE otherwise. 452 * The guidResult and nameResult arguments may be nullptr if you just want 453 * to check the format of the string. 454 */ 455 static bool 456 parseVariableName(const char *key, uuid_t *guidResult, const char **nameResult) 457 { 458 uuid_string_t temp = {0}; 459 size_t keyLen = strlen(key); 460 bool ok = false; 461 const char *name = key; 462 uuid_t guid; 463 464 if (keyLen > sizeof(temp)) { 465 // check for at least UUID + ":" + more 466 memcpy(temp, key, sizeof(temp) - 1); 467 468 if ((uuid_parse(temp, guid) == 0) && 469 (key[sizeof(temp) - 1] == ':')) { 470 name = key + sizeof(temp); 471 ok = true; 472 } 473 } 474 475 if (guidResult) { 476 ok ? uuid_copy(*guidResult, guid) : uuid_copy(*guidResult, gAppleNVRAMGuid); 477 } 478 if (nameResult) { 479 *nameResult = name; 480 } 481 482 return ok; 483 } 484 485 static bool 486 parseVariableName(const OSSymbol *key, uuid_t *guidResult, const char **nameResult) 487 { 488 return parseVariableName(key->getCStringNoCopy(), guidResult, nameResult); 489 } 490 491 /** 492 * @brief Translates(if needed) varGuid and stores it in destGuid 493 * 494 * @param varGuid guid to translate 495 * @param variableName variable name attached to the guid 496 * @param destGuid translated guid is saved here 497 * @param systemActive boolean to indicate if it has system partition size > 0 498 */ 499 static void 500 translateGUID(const uuid_t varGuid, const char *variableName, uuid_t destGuid, bool systemActive) 501 { 502 if (varGuid == nullptr || variableName == nullptr || destGuid == nullptr) { 503 DEBUG_ERROR("nullptr passed as an argument\n"); 504 return; 505 } 506 507 bool systemGuid = uuid_compare(varGuid, gAppleSystemVariableGuid) == 0; 508 509 if (systemActive) { 510 if (variableInAllowList(variableName)) { 511 DEBUG_INFO("Using system GUID due to allow list\n"); 512 uuid_copy(destGuid, gAppleSystemVariableGuid); 513 } else if (systemGuid) { 514 DEBUG_INFO("System GUID used\n"); 515 uuid_copy(destGuid, gAppleSystemVariableGuid); 516 } else { 517 DEBUG_INFO("Use given guid\n"); 518 uuid_copy(destGuid, varGuid); 519 } 520 } else if (systemGuid) { 521 DEBUG_INFO("Overriding to Apple guid\n"); 522 uuid_copy(destGuid, gAppleNVRAMGuid); 523 } else { 524 DEBUG_INFO("Use given guid\n"); 525 uuid_copy(destGuid, varGuid); 526 } 527 } 528 529 /** 530 * @brief Checks if the variable-guid(translated) pair is present in gVariableEntitlements and if so, 531 * does it have the required entitlement for the NVRAM operation passed in 532 * 533 * @param varGuid guid for the variable to be checked, this gets translated by translateGUID 534 * @param varName variable name 535 * @param op NVRAM operation 536 * @param systemActive used to pass into translateGUID to get the correct guid to check against 537 * @param veChecked if variable entitlement is checked, this is set to true 538 * @return true if variable wasn't present in gVariableEntitlements, 539 * entitlement check wasn't required for operation passed in, 540 * or if entitlement check returned true 541 * @return false if varName/varGuid/veChecked was NULL or if entitlement check returned false 542 */ 543 static bool 544 verifyVarEntitlement(const uuid_t varGuid, const char *varName, IONVRAMOperation op, bool systemActive, bool *veChecked) 545 { 546 if (varGuid == nullptr || varName == nullptr || veChecked == nullptr) { 547 DEBUG_ERROR("nullptr passed as an argument\n"); 548 return false; 549 } 550 551 uuid_t translatedGuid; 552 const VariableEntitlementEntry *entry; 553 *veChecked = false; 554 555 translateGUID(varGuid, varName, translatedGuid, systemActive); 556 557 entry = gVariableEntitlements; 558 while ((entry != nullptr) && (entry->varName != nullptr)) { 559 if ((strcmp(entry->varName, varName) == 0) && (uuid_compare(translatedGuid, *(entry->varGuid)) == 0)) { 560 // check if task entitlement check is required for this operation 561 if (entry->checkOp & (1 << op)) { 562 *veChecked = true; 563 DEBUG_INFO("Checking entitlement %s for %s for operation %s\n", entry->varEntitlement, varName, getNVRAMOpString(op)); 564 return IOCurrentTaskHasEntitlement(entry->varEntitlement); 565 } 566 break; 567 } 568 entry++; 569 } 570 571 return true; 572 } 573 574 static bool 575 kernelOnlyVar(const uuid_t varGuid, const char *varName) 576 { 577 if (strncmp(varName, KERNEL_ONLY_VAR_NAME_PREFIX, sizeof(KERNEL_ONLY_VAR_NAME_PREFIX) - 1) == 0) { 578 return true; 579 } 580 581 return false; 582 } 583 584 static bool 585 verifyPermission(IONVRAMOperation op, const uuid_t varGuid, const char *varName, const bool systemActive) 586 { 587 VariablePermission perm; 588 bool kernel, varEntitled, writeEntitled = false, readEntitled = false, allowList, systemGuid = false, systemEntitled = false, systemInternalEntitled = false, systemAllow, systemReadHiddenAllow = false; 589 bool admin = false; 590 bool ok = false; 591 592 if (verifyVarEntitlement(varGuid, varName, op, systemActive, &varEntitled) == false) { 593 goto exit; 594 } 595 596 perm = getVariablePermission(varName); 597 598 kernel = current_task() == kernel_task; 599 600 if (perm.Bits.KernelOnly || kernelOnlyVar(varGuid, varName)) { 601 DEBUG_INFO("KernelOnly access for %s, kernel=%d\n", varName, kernel); 602 ok = kernel; 603 goto exit; 604 } 605 606 if (perm.Bits.InternalOnly && !gInternalBuild) { 607 DEBUG_INFO("InternalOnly access for %s, gInternalBuild=%d\n", varName, gInternalBuild); 608 goto exit; 609 } 610 611 allowList = variableInAllowList(varName); 612 systemGuid = uuid_compare(varGuid, gAppleSystemVariableGuid) == 0; 613 admin = IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege) == kIOReturnSuccess; 614 writeEntitled = IOCurrentTaskHasEntitlement(kIONVRAMWriteAccessKey); 615 readEntitled = IOCurrentTaskHasEntitlement(kIONVRAMReadAccessKey); 616 systemEntitled = IOCurrentTaskHasEntitlement(kIONVRAMSystemAllowKey); 617 systemInternalEntitled = IOCurrentTaskHasEntitlement(kIONVRAMSystemInternalAllowKey); 618 systemReadHiddenAllow = IOCurrentTaskHasEntitlement(kIONVRAMSystemHiddenAllowKey); 619 620 systemAllow = systemEntitled || (systemInternalEntitled && gInternalBuild) || kernel; 621 622 switch (op) { 623 case kIONVRAMOperationRead: 624 if (systemGuid && perm.Bits.SystemReadHidden) { 625 ok = systemReadHiddenAllow; 626 } else if (kernel || admin || readEntitled || perm.Bits.FullAccess || varEntitled) { 627 ok = true; 628 } 629 break; 630 631 case kIONVRAMOperationWrite: 632 if (kernel || perm.Bits.UserWrite || admin || writeEntitled || varEntitled) { 633 if (systemGuid) { 634 if (allowList) { 635 if (!systemAllow) { 636 DEBUG_ERROR("Allowed write to system region when NOT entitled for %s\n", varName); 637 } 638 } else if (varEntitled) { 639 DEBUG_INFO("Allowed write to system region using variable specific entitlement for %s\n", varName); 640 } else if (!systemAllow) { 641 DEBUG_ERROR("Not entitled for system region writes for %s\n", varName); 642 break; 643 } 644 } 645 ok = true; 646 } 647 break; 648 649 case kIONVRAMOperationDelete: 650 case kIONVRAMOperationObliterate: 651 case kIONVRAMOperationReset: 652 if (perm.Bits.NeverAllowedToDelete) { 653 DEBUG_INFO("Never allowed to delete %s\n", varName); 654 break; 655 } else if ((op == kIONVRAMOperationObliterate) && perm.Bits.ResetNVRAMOnlyDelete) { 656 DEBUG_INFO("Not allowed to obliterate %s\n", varName); 657 break; 658 } else if ((op == kIONVRAMOperationDelete) && perm.Bits.ResetNVRAMOnlyDelete) { 659 DEBUG_INFO("Only allowed to delete %s via NVRAM reset\n", varName); 660 break; 661 } 662 663 if (kernel || perm.Bits.UserWrite || admin || writeEntitled || varEntitled) { 664 if (systemGuid) { 665 if (allowList) { 666 if (!systemAllow) { 667 DEBUG_ERROR("Allowed delete to system region when NOT entitled for %s\n", varName); 668 } 669 } else if (varEntitled) { 670 DEBUG_INFO("Allowed delete to system region using variable specific entitlement for %s\n", varName); 671 } else if (!systemAllow) { 672 DEBUG_ERROR("Not entitled for system region deletes for %s\n", varName); 673 break; 674 } 675 } 676 ok = true; 677 } 678 break; 679 680 case kIONVRAMOperationInit: 681 break; 682 } 683 684 exit: 685 DEBUG_INFO("Permission for %s of %s %s: I=%d kern=%d, adm=%d, wE=%d, rE=%d, sG=%d, sEd=%d, sIEd=%d, sRHA=%d, UW=%d, vE=%d\n", getNVRAMOpString(op), varName, ok ? "granted" : "denied", 686 gInternalBuild, kernel, admin, writeEntitled, readEntitled, systemGuid, systemEntitled, systemInternalEntitled, systemReadHiddenAllow, perm.Bits.UserWrite, varEntitled); 687 688 return ok; 689 } 690 691 static bool 692 verifyPermission(IONVRAMOperation op, const OSSymbol *canonicalKey, const bool systemActive) 693 { 694 const char *varName; 695 uuid_t varGuid; 696 697 parseVariableName(canonicalKey->getCStringNoCopy(), &varGuid, &varName); 698 699 return verifyPermission(op, varGuid, varName, systemActive); 700 } 701 702 static bool 703 skipKey(const OSSymbol *aKey) 704 { 705 return aKey->isEqualTo(kIORegistryEntryAllowableSetPropertiesKey) || 706 aKey->isEqualTo(kIORegistryEntryDefaultLockingSetPropertiesKey) || 707 aKey->isEqualTo(kIOClassNameOverrideKey) || 708 aKey->isEqualTo(kIOBSDNameKey) || 709 aKey->isEqualTo(kIOBSDNamesKey) || 710 aKey->isEqualTo(kIOBSDMajorKey) || 711 aKey->isEqualTo(kIOBSDMinorKey) || 712 aKey->isEqualTo(kIOBSDUnitKey) || 713 aKey->isEqualTo(kIOUserServicePropertiesKey) || 714 aKey->isEqualTo(kIOExclaveAssignedKey) || 715 aKey->isEqualTo(kIOMatchCategoryKey) || 716 aKey->isEqualTo(kIOBusyInterest); 717 } 718 719 static OSSharedPtr<const OSSymbol> 720 keyWithGuidAndCString(const uuid_t guid, const char * cstring) 721 { 722 size_t length; 723 OSSharedPtr<const OSSymbol> symbolObj; 724 char *canonicalString; 725 726 length = sizeof(uuid_string_t) - 1 + sizeof(':') + strlen(cstring) + 1; 727 728 canonicalString = (char *) IOMallocData(length); 729 if (canonicalString == nullptr) { 730 return NULL; 731 } 732 733 uuid_unparse(guid, *((uuid_string_t*)canonicalString)); 734 canonicalString[sizeof(uuid_string_t) - 1] = ':'; 735 736 strlcpy(&canonicalString[sizeof(uuid_string_t)], cstring, length - sizeof(uuid_string_t)); 737 738 symbolObj = OSSymbol::withCString(canonicalString); 739 IOFreeData(canonicalString, length); 740 741 return symbolObj; 742 } 743 744 static void 745 dumpDict(const OSDictionary *dict) 746 { 747 const OSSymbol *key; 748 OSSharedPtr<OSCollectionIterator> iter; 749 unsigned int count = 0; 750 751 iter = OSCollectionIterator::withCollection(dict); 752 if (iter == nullptr) { 753 DEBUG_ERROR("failed to create iterator\n"); 754 goto exit; 755 } 756 757 DEBUG_INFO("Dumping dict...\n"); 758 while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) { 759 count++; 760 DEBUG_INFO("%u: %s\n", count, key->getCStringNoCopy()); 761 } 762 763 exit: 764 return; 765 } 766 767 // ************************** IODTNVRAMPlatformNotifier **************************** 768 // private IOService based class for passing notifications to IODTNVRAM 769 770 class IODTNVRAMPlatformNotifier : public IOService 771 { 772 OSDeclareDefaultStructors(IODTNVRAMPlatformNotifier) 773 private: 774 IODTNVRAM *_provider; 775 776 public: 777 bool start(IOService * provider) APPLE_KEXT_OVERRIDE; 778 779 virtual IOReturn callPlatformFunction( const OSSymbol * functionName, 780 bool waitForFunction, 781 void *param1, void *param2, 782 void *param3, void *param4 ) APPLE_KEXT_OVERRIDE; 783 }; 784 785 OSDefineMetaClassAndStructors(IODTNVRAMPlatformNotifier, IOService) 786 787 bool 788 IODTNVRAMPlatformNotifier::start(IOService * provider) 789 { 790 OSSharedPtr<OSSerializer> serializer; 791 OSSharedPtr<OSNumber> value = OSNumber::withNumber(1000, 32); 792 793 _provider = OSDynamicCast(IODTNVRAM, provider); 794 require(_provider != nullptr, error); 795 796 setProperty(gIOPlatformWakeActionKey, value.get()); 797 798 require(super::start(provider), error); 799 800 registerService(); 801 802 return true; 803 804 error: 805 stop(provider); 806 807 return false; 808 } 809 810 #include <IOKit/IOHibernatePrivate.h> 811 #include <IOKit/pwr_mgt/RootDomain.h> 812 static const OSSharedPtr<const OSSymbol> gIOHibernateStateKey = OSSymbol::withCString(kIOHibernateStateKey); 813 814 static uint32_t 815 hibernateState(void) 816 { 817 OSSharedPtr<OSData> data = OSDynamicPtrCast<OSData>(IOService::getPMRootDomain()->copyProperty(gIOHibernateStateKey.get()->getCStringNoCopy())); 818 uint32_t hibernateState = 0; 819 if ((data != NULL) && (data->getLength() == sizeof(hibernateState))) { 820 memcpy(&hibernateState, data->getBytesNoCopy(), sizeof(hibernateState)); 821 } 822 return hibernateState; 823 } 824 825 IOReturn 826 IODTNVRAMPlatformNotifier::callPlatformFunction( const OSSymbol * functionName, 827 bool waitForFunction, 828 void *param1, void *param2, 829 void *param3, void *param4 ) 830 { 831 if ((functionName == gIOPlatformWakeActionKey) && 832 (hibernateState() == kIOHibernateStateWakingFromHibernate)) { 833 DEBUG_INFO("waking from hibernate\n"); 834 _provider->reload(); 835 return kIOReturnSuccess; 836 } 837 838 return super::callPlatformFunction(functionName, waitForFunction, param1, param2, param3, param4); 839 } 840 841 842 // ************************** IODTNVRAMDiags **************************** 843 // private IOService based class for passing notifications to IODTNVRAM 844 #define kIODTNVRAMDiagsStatsKey "Stats" 845 #define kIODTNVRAMDiagsInitKey "Init" 846 #define kIODTNVRAMDiagsReadKey "Read" 847 #define kIODTNVRAMDiagsWriteKey "Write" 848 #define kIODTNVRAMDiagsDeleteKey "Delete" 849 #define kIODTNVRAMDiagsNameKey "Name" 850 #define kIODTNVRAMDiagsSizeKey "Size" 851 #define kIODTNVRAMDiagsPresentKey "Present" 852 853 // private IOService based class for publishing diagnostic info for IODTNVRAM 854 class IODTNVRAMDiags : public IOService 855 { 856 OSDeclareDefaultStructors(IODTNVRAMDiags) 857 private: 858 IODTNVRAM *_provider; 859 IORWLock *_variableLock; 860 OSSharedPtr<OSDictionary> _stats; 861 862 bool serializeStats(void *, OSSerialize * serializer); 863 864 public: 865 bool start(IOService * provider) APPLE_KEXT_OVERRIDE; 866 void logVariable(NVRAMPartitionType region, IONVRAMOperation op, const char *name, void *data); 867 }; 868 869 OSDefineMetaClassAndStructors(IODTNVRAMDiags, IOService) 870 871 bool 872 IODTNVRAMDiags::start(IOService * provider) 873 { 874 OSSharedPtr<OSSerializer> serializer; 875 876 _provider = OSDynamicCast(IODTNVRAM, provider); 877 require(_provider != nullptr, error); 878 879 require(super::start(provider), error); 880 881 _variableLock = IORWLockAlloc(); 882 require(_variableLock != nullptr, error); 883 884 _stats = OSDictionary::withCapacity(1); 885 require(_stats != nullptr, error); 886 887 serializer = OSSerializer::forTarget(this, OSMemberFunctionCast(OSSerializerCallback, this, &IODTNVRAMDiags::serializeStats)); 888 require(serializer != nullptr, error); 889 890 setProperty(kIODTNVRAMDiagsStatsKey, serializer.get()); 891 892 registerService(); 893 894 return true; 895 896 error: 897 stop(provider); 898 899 return false; 900 } 901 902 void 903 IODTNVRAMDiags::logVariable(NVRAMPartitionType region, IONVRAMOperation op, const char *name, void *data) 904 { 905 // "Stats" : OSDictionary 906 // - "XX:varName" : OSDictionary, XX is the region value prefix to distinguish which dictionary the variable is in 907 // - "Init" : OSBoolean True/present if variable present at initialization 908 // - "Read" : OSNumber count 909 // - "Write" : OSNumber count 910 // - "Delete" : OSNumber count 911 // - "Size" : OSNumber size, latest size from either init or write 912 // - "Present" : OSBoolean True/False if variable is present or not 913 char *entryKey; 914 size_t entryKeySize; 915 OSSharedPtr<OSDictionary> existingEntry; 916 OSSharedPtr<OSNumber> currentCount; 917 OSSharedPtr<OSNumber> varSize; 918 const char *opCountKey = nullptr; 919 920 entryKeySize = strlen("XX:") + strlen(name) + 1; 921 entryKey = IONewData(char, entryKeySize); 922 require(entryKey, exit); 923 924 snprintf(entryKey, entryKeySize, "%02X:%s", region, name); 925 926 NVRAMWRITELOCK(); 927 existingEntry.reset(OSDynamicCast(OSDictionary, _stats->getObject(entryKey)), OSRetain); 928 929 if (existingEntry == nullptr) { 930 existingEntry = OSDictionary::withCapacity(4); 931 } 932 933 switch (op) { 934 case kIONVRAMOperationRead: 935 opCountKey = kIODTNVRAMDiagsReadKey; 936 if (existingEntry->getObject(kIODTNVRAMDiagsPresentKey) == nullptr) { 937 existingEntry->setObject(kIODTNVRAMDiagsPresentKey, kOSBooleanFalse); 938 } 939 break; 940 case kIONVRAMOperationWrite: 941 opCountKey = kIODTNVRAMDiagsWriteKey; 942 varSize = OSNumber::withNumber((size_t)data, 64); 943 existingEntry->setObject(kIODTNVRAMDiagsSizeKey, varSize); 944 existingEntry->setObject(kIODTNVRAMDiagsPresentKey, kOSBooleanTrue); 945 break; 946 case kIONVRAMOperationDelete: 947 case kIONVRAMOperationObliterate: 948 case kIONVRAMOperationReset: 949 opCountKey = kIODTNVRAMDiagsDeleteKey; 950 existingEntry->setObject(kIODTNVRAMDiagsPresentKey, kOSBooleanFalse); 951 break; 952 case kIONVRAMOperationInit: 953 varSize = OSNumber::withNumber((size_t)data, 64); 954 existingEntry->setObject(kIODTNVRAMDiagsInitKey, varSize); 955 existingEntry->setObject(kIODTNVRAMDiagsSizeKey, varSize); 956 existingEntry->setObject(kIODTNVRAMDiagsPresentKey, kOSBooleanTrue); 957 break; 958 default: 959 goto unlock; 960 } 961 962 if (opCountKey) { 963 currentCount.reset(OSDynamicCast(OSNumber, existingEntry->getObject(opCountKey)), OSRetain); 964 965 if (currentCount == nullptr) { 966 currentCount = OSNumber::withNumber(1, 64); 967 } else { 968 currentCount->addValue(1); 969 } 970 971 existingEntry->setObject(opCountKey, currentCount); 972 } 973 974 _stats->setObject(entryKey, existingEntry); 975 976 unlock: 977 NVRAMUNLOCK(); 978 979 exit: 980 IODeleteData(entryKey, char, entryKeySize); 981 982 return; 983 } 984 985 bool 986 IODTNVRAMDiags::serializeStats(void *, OSSerialize * serializer) 987 { 988 bool ok; 989 990 NVRAMREADLOCK(); 991 ok = _stats->serialize(serializer); 992 NVRAMUNLOCK(); 993 994 return ok; 995 } 996 997 // ************************** IODTNVRAMVariables **************************** 998 999 // private IOService based class for publishing distinct dictionary properties on 1000 // for easy ioreg access since the serializeProperties call is overloaded and is used 1001 // as variable access 1002 class IODTNVRAMVariables : public IOService 1003 { 1004 OSDeclareDefaultStructors(IODTNVRAMVariables) 1005 private: 1006 IODTNVRAM *_provider; 1007 uuid_t _guid; 1008 bool _systemActive; 1009 1010 public: 1011 bool init(const uuid_t guid, const bool systemActive); 1012 virtual bool start(IOService * provider) APPLE_KEXT_OVERRIDE; 1013 1014 virtual bool serializeProperties(OSSerialize *s) const APPLE_KEXT_OVERRIDE; 1015 virtual OSPtr<OSObject> copyProperty(const OSSymbol *aKey) const APPLE_KEXT_OVERRIDE; 1016 virtual OSObject *getProperty(const OSSymbol *aKey) const APPLE_KEXT_OVERRIDE; 1017 virtual bool setProperty(const OSSymbol *aKey, OSObject *anObject) APPLE_KEXT_OVERRIDE; 1018 virtual IOReturn setProperties(OSObject *properties) APPLE_KEXT_OVERRIDE; 1019 virtual void removeProperty(const OSSymbol *aKey) APPLE_KEXT_OVERRIDE; 1020 }; 1021 1022 OSDefineMetaClassAndStructors(IODTNVRAMVariables, IOService) 1023 1024 bool 1025 IODTNVRAMVariables::init(const uuid_t guid, const bool systemActive) 1026 { 1027 require(super::init(), fail); 1028 1029 uuid_copy(_guid, guid); 1030 _systemActive = systemActive; 1031 1032 return true; 1033 1034 fail: 1035 return false; 1036 } 1037 1038 bool 1039 IODTNVRAMVariables::start(IOService * provider) 1040 { 1041 _provider = OSDynamicCast(IODTNVRAM, provider); 1042 if (_provider == nullptr) { 1043 goto error; 1044 } 1045 1046 if (!super::start(provider)) { 1047 goto error; 1048 } 1049 1050 registerService(); 1051 1052 return true; 1053 1054 error: 1055 stop(provider); 1056 1057 return false; 1058 } 1059 1060 bool 1061 IODTNVRAMVariables::serializeProperties(OSSerialize *s) const 1062 { 1063 const OSSymbol *key; 1064 OSSharedPtr<OSDictionary> dict; 1065 OSSharedPtr<OSCollectionIterator> iter; 1066 OSSharedPtr<OSDictionary> localVariables = _provider->_varDict; 1067 bool ok = false; 1068 1069 dict = OSDictionary::withCapacity(localVariables->getCount()); 1070 if (dict == nullptr) { 1071 DEBUG_ERROR("No dictionary\n"); 1072 goto exit; 1073 } 1074 1075 iter = OSCollectionIterator::withCollection(localVariables.get()); 1076 if (iter == nullptr) { 1077 DEBUG_ERROR("failed to create iterator\n"); 1078 goto exit; 1079 } 1080 1081 while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) { 1082 if (verifyPermission(kIONVRAMOperationRead, key, _systemActive)) { 1083 uuid_t guid; 1084 const char *name; 1085 1086 parseVariableName(key, &guid, &name); 1087 1088 if (uuid_compare(_guid, guid) == 0) { 1089 OSSharedPtr<const OSSymbol> sym = OSSymbol::withCString(name); 1090 dict->setObject(sym.get(), localVariables->getObject(key)); 1091 } 1092 } 1093 } 1094 1095 ok = dict->serialize(s); 1096 1097 exit: 1098 DEBUG_INFO("ok=%d\n", ok); 1099 return ok; 1100 } 1101 1102 OSPtr<OSObject> 1103 IODTNVRAMVariables::copyProperty(const OSSymbol *aKey) const 1104 { 1105 if (_provider && !skipKey(aKey)) { 1106 DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy()); 1107 1108 return _provider->copyPropertyWithGUIDAndName(_guid, aKey->getCStringNoCopy()); 1109 } else { 1110 return nullptr; 1111 } 1112 } 1113 1114 OSObject * 1115 IODTNVRAMVariables::getProperty(const OSSymbol *aKey) const 1116 { 1117 OSSharedPtr<OSObject> theObject = copyProperty(aKey); 1118 1119 return theObject.get(); 1120 } 1121 1122 bool 1123 IODTNVRAMVariables::setProperty(const OSSymbol *aKey, OSObject *anObject) 1124 { 1125 if (_provider) { 1126 return _provider->setPropertyWithGUIDAndName(_guid, aKey->getCStringNoCopy(), anObject) == kIOReturnSuccess; 1127 } else { 1128 return false; 1129 } 1130 } 1131 1132 IOReturn 1133 IODTNVRAMVariables::setProperties(OSObject *properties) 1134 { 1135 IOReturn ret = kIOReturnSuccess; 1136 OSObject *object; 1137 const OSSymbol *key; 1138 OSDictionary *dict; 1139 OSSharedPtr<OSCollectionIterator> iter; 1140 1141 dict = OSDynamicCast(OSDictionary, properties); 1142 if (dict == nullptr) { 1143 DEBUG_ERROR("Not a dictionary\n"); 1144 return kIOReturnBadArgument; 1145 } 1146 1147 iter = OSCollectionIterator::withCollection(dict); 1148 if (iter == nullptr) { 1149 DEBUG_ERROR("Couldn't create iterator\n"); 1150 return kIOReturnBadArgument; 1151 } 1152 1153 while (ret == kIOReturnSuccess) { 1154 key = OSDynamicCast(OSSymbol, iter->getNextObject()); 1155 if (key == nullptr) { 1156 break; 1157 } 1158 1159 object = dict->getObject(key); 1160 if (object == nullptr) { 1161 continue; 1162 } 1163 1164 ret = _provider->setPropertyWithGUIDAndName(_guid, key->getCStringNoCopy(), object); 1165 } 1166 1167 DEBUG_INFO("ret=%#08x\n", ret); 1168 1169 return ret; 1170 } 1171 1172 void 1173 IODTNVRAMVariables::removeProperty(const OSSymbol *aKey) 1174 { 1175 _provider->removePropertyWithGUIDAndName(_guid, aKey->getCStringNoCopy()); 1176 } 1177 1178 // ************************** Format Handlers *************************** 1179 class IODTNVRAMFormatHandler 1180 { 1181 protected: 1182 uint32_t _bankSize; 1183 uint32_t _bankCount; 1184 uint32_t _currentBank; 1185 1186 public: 1187 virtual 1188 ~IODTNVRAMFormatHandler(); 1189 virtual bool getNVRAMProperties(void); 1190 virtual IOReturn unserializeVariables(void) = 0; 1191 virtual IOReturn setVariable(const uuid_t varGuid, const char *variableName, OSObject *object) = 0; 1192 virtual bool setController(IONVRAMController *_nvramController) = 0; 1193 virtual IOReturn sync(void) = 0; 1194 virtual IOReturn flush(const uuid_t guid, IONVRAMOperation op) = 0; 1195 virtual void reload(void) = 0; 1196 virtual uint32_t getGeneration(void) const = 0; 1197 virtual uint32_t getVersion(void) const = 0; 1198 virtual uint32_t getSystemUsed(void) const = 0; 1199 virtual uint32_t getCommonUsed(void) const = 0; 1200 virtual bool getSystemPartitionActive(void) const = 0; 1201 }; 1202 1203 IODTNVRAMFormatHandler::~IODTNVRAMFormatHandler() 1204 { 1205 } 1206 1207 bool 1208 IODTNVRAMFormatHandler::getNVRAMProperties() 1209 { 1210 bool ok = false; 1211 OSSharedPtr<IORegistryEntry> entry; 1212 OSSharedPtr<OSObject> prop; 1213 OSData * data; 1214 1215 entry = IORegistryEntry::fromPath("/chosen", gIODTPlane); 1216 require_action(entry, exit, DEBUG_ERROR("Unable to find chosen node\n")); 1217 1218 prop = entry->copyProperty(kNVRAMBankSizeKey); 1219 require_action(prop, exit, DEBUG_ERROR("Unable to find %s property\n", kNVRAMBankSizeKey)); 1220 1221 data = OSDynamicCast(OSData, prop.get()); 1222 require(data, exit); 1223 1224 _bankSize = *((uint32_t *)data->getBytesNoCopy()); 1225 1226 prop = entry->copyProperty(kNVRAMBankCountKey); 1227 require_action(prop, exit, DEBUG_ERROR("Unable to find %s property\n", kNVRAMBankCountKey)); 1228 1229 data = OSDynamicCast(OSData, prop.get()); 1230 require(data, exit); 1231 1232 _bankCount = *((uint32_t *)data->getBytesNoCopy()); 1233 1234 prop = entry->copyProperty(kNVRAMCurrentBankKey); 1235 require_action(prop, exit, DEBUG_ERROR("Unable to find %s property\n", kNVRAMCurrentBankKey)); 1236 1237 data = OSDynamicCast(OSData, prop.get()); 1238 require(data, exit); 1239 1240 _currentBank = *((uint32_t *)data->getBytesNoCopy()); 1241 1242 ok = true; 1243 1244 DEBUG_ALWAYS("_bankSize=%#X, _bankCount=%#X, _currentBank=%#X\n", _bankSize, _bankCount, _currentBank); 1245 1246 exit: 1247 return ok; 1248 } 1249 1250 #include "IONVRAMCHRPHandler.cpp" 1251 1252 #include "IONVRAMV3Handler.cpp" 1253 1254 // **************************** IODTNVRAM ********************************* 1255 1256 bool 1257 IODTNVRAM::init(IORegistryEntry *old, const IORegistryPlane *plane) 1258 { 1259 OSSharedPtr<OSDictionary> dict; 1260 1261 DEBUG_INFO("...\n"); 1262 1263 require(super::init(old, plane), fail); 1264 1265 #if CONFIG_CSR && XNU_TARGET_OS_OSX 1266 gInternalBuild = (csr_check(CSR_ALLOW_APPLE_INTERNAL) == 0); 1267 #elif defined(DEBUG) || defined(DEVELOPMENT) 1268 gInternalBuild = true; 1269 #endif 1270 DEBUG_INFO("gInternalBuild = %d\n", gInternalBuild); 1271 1272 _variableLock = IORWLockAlloc(); 1273 require(_variableLock != nullptr, fail); 1274 1275 _controllerLock = IOLockAlloc(); 1276 require(_controllerLock != nullptr, fail); 1277 1278 // Clear the IORegistryEntry property table 1279 dict = OSDictionary::withCapacity(1); 1280 require(dict != nullptr, fail); 1281 1282 setPropertyTable(dict.get()); 1283 dict.reset(); 1284 1285 return true; 1286 1287 fail: 1288 return false; 1289 } 1290 1291 bool 1292 IODTNVRAM::start(IOService *provider) 1293 { 1294 OSSharedPtr<OSNumber> version; 1295 1296 DEBUG_INFO("...\n"); 1297 1298 require(super::start(provider), fail); 1299 1300 // Check if our overridden init function was called 1301 // If not, skip any additional initialization being done here. 1302 // This is not an error we just need to successfully exit this function to allow 1303 // AppleEFIRuntime to proceed and take over operation 1304 require_action(_controllerLock != nullptr, no_common, DEBUG_INFO("x86 init\n")); 1305 1306 _diags = new IODTNVRAMDiags; 1307 if (!_diags || !_diags->init()) { 1308 DEBUG_ERROR("Unable to create/init the diags service\n"); 1309 OSSafeReleaseNULL(_diags); 1310 goto fail; 1311 } 1312 1313 if (!_diags->attach(this)) { 1314 DEBUG_ERROR("Unable to attach the diags service!\n"); 1315 OSSafeReleaseNULL(_diags); 1316 goto fail; 1317 } 1318 1319 if (!_diags->start(this)) { 1320 DEBUG_ERROR("Unable to start the diags service!\n"); 1321 _diags->detach(this); 1322 OSSafeReleaseNULL(_diags); 1323 goto fail; 1324 } 1325 1326 _notifier = new IODTNVRAMPlatformNotifier; 1327 if (!_notifier || !_notifier->init()) { 1328 DEBUG_ERROR("Unable to create/init the notifier service\n"); 1329 OSSafeReleaseNULL(_notifier); 1330 goto fail; 1331 } 1332 1333 if (!_notifier->attach(this)) { 1334 DEBUG_ERROR("Unable to attach the notifier service!\n"); 1335 OSSafeReleaseNULL(_notifier); 1336 goto fail; 1337 } 1338 1339 if (!_notifier->start(this)) { 1340 DEBUG_ERROR("Unable to start the notifier service!\n"); 1341 _notifier->detach(this); 1342 OSSafeReleaseNULL(_notifier); 1343 goto fail; 1344 } 1345 1346 // This will load the proxied variable data which will call back into 1347 // IODTNVRAM for the variable sets which will also update the system/common services 1348 initImageFormat(); 1349 1350 version = OSNumber::withNumber(_format->getVersion(), 32); 1351 _diags->setProperty(kCurrentNVRAMVersionKey, version.get()); 1352 1353 if (_format->getSystemUsed()) { 1354 _systemService = new IODTNVRAMVariables; 1355 1356 if (!_systemService || !_systemService->init(gAppleSystemVariableGuid, _format->getSystemPartitionActive())) { 1357 DEBUG_ERROR("Unable to start the system service!\n"); 1358 OSSafeReleaseNULL(_systemService); 1359 goto no_system; 1360 } 1361 1362 _systemService->setName("options-system"); 1363 1364 if (!_systemService->attach(this)) { 1365 DEBUG_ERROR("Unable to attach the system service!\n"); 1366 OSSafeReleaseNULL(_systemService); 1367 goto no_system; 1368 } 1369 1370 if (!_systemService->start(this)) { 1371 DEBUG_ERROR("Unable to start the system service!\n"); 1372 _systemService->detach(this); 1373 OSSafeReleaseNULL(_systemService); 1374 goto no_system; 1375 } 1376 } 1377 1378 no_system: 1379 _commonService = new IODTNVRAMVariables; 1380 1381 if (!_commonService || !_commonService->init(gAppleNVRAMGuid, _format->getSystemPartitionActive())) { 1382 DEBUG_ERROR("Unable to start the common service!\n"); 1383 OSSafeReleaseNULL(_commonService); 1384 goto no_common; 1385 } 1386 1387 _commonService->setName("options-common"); 1388 1389 if (!_commonService->attach(this)) { 1390 DEBUG_ERROR("Unable to attach the common service!\n"); 1391 OSSafeReleaseNULL(_commonService); 1392 goto no_common; 1393 } 1394 1395 if (!_commonService->start(this)) { 1396 DEBUG_ERROR("Unable to start the common service!\n"); 1397 _commonService->detach(this); 1398 OSSafeReleaseNULL(_commonService); 1399 goto no_common; 1400 } 1401 1402 no_common: 1403 return true; 1404 1405 fail: 1406 stop(provider); 1407 return false; 1408 } 1409 1410 void 1411 IODTNVRAM::initImageFormat(void) 1412 { 1413 OSSharedPtr<IORegistryEntry> entry; 1414 OSSharedPtr<OSObject> prop; 1415 const char *proxyDataKey = "nvram-proxy-data"; 1416 const char *bankSizeKey = "nvram-bank-size"; 1417 OSData *data = nullptr; 1418 uint32_t size = 0; 1419 const uint8_t *image = nullptr; 1420 1421 entry = IORegistryEntry::fromPath("/chosen", gIODTPlane); 1422 1423 require(entry != nullptr, skip); 1424 1425 prop = entry->copyProperty(bankSizeKey); 1426 require(prop != nullptr, skip); 1427 1428 data = OSDynamicCast(OSData, prop.get()); 1429 require(data != nullptr, skip); 1430 1431 size = *((uint32_t*)data->getBytesNoCopy()); 1432 require_action(size != 0, skip, panic("NVRAM size is 0 bytes, possibly due to bad config with iBoot + xnu mismatch")); 1433 DEBUG_ALWAYS("NVRAM size is %u bytes\n", size); 1434 1435 prop = entry->copyProperty(proxyDataKey); 1436 require(prop != nullptr, skip); 1437 1438 data = OSDynamicCast(OSData, prop.get()); 1439 require_action(data != nullptr, skip, DEBUG_ERROR("No proxy data!\n")); 1440 1441 image = (const uint8_t *)data->getBytesNoCopy(); 1442 1443 skip: 1444 if (IONVRAMV3Handler::isValidImage(image, size)) { 1445 _format = IONVRAMV3Handler::init(this, image, size, _varDict); 1446 require_action(_format, skip, panic("IONVRAMV3Handler creation failed\n")); 1447 } else { 1448 _format = IONVRAMCHRPHandler::init(this, image, size, _varDict); 1449 require_action(_format, skip, panic("IONVRAMCHRPHandler creation failed\n")); 1450 } 1451 1452 _format->unserializeVariables(); 1453 1454 dumpDict(_varDict.get()); 1455 1456 #if defined(RELEASE) 1457 if (entry != nullptr) { 1458 entry->removeProperty(proxyDataKey); 1459 } 1460 #endif 1461 1462 _lastDeviceSync = 0; 1463 _freshInterval = true; 1464 } 1465 1466 void 1467 IODTNVRAM::registerNVRAMController(IONVRAMController *controller) 1468 { 1469 DEBUG_INFO("setting controller\n"); 1470 1471 NVRAMWRITELOCK(); 1472 CONTROLLERLOCK(); 1473 1474 _format->setController(controller); 1475 1476 CONTROLLERUNLOCK(); 1477 NVRAMUNLOCK(); 1478 1479 return; 1480 } 1481 1482 bool 1483 IODTNVRAM::safeToSync(void) 1484 { 1485 AbsoluteTime delta; 1486 UInt64 delta_ns; 1487 SInt32 delta_secs; 1488 1489 // delta interval went by 1490 clock_get_uptime(&delta); 1491 1492 // Figure it in seconds. 1493 absolutetime_to_nanoseconds(delta, &delta_ns); 1494 delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC); 1495 1496 if ((delta_secs > (_lastDeviceSync + MIN_SYNC_NOW_INTERVAL)) || _freshInterval) { 1497 _lastDeviceSync = delta_secs; 1498 _freshInterval = false; 1499 return true; 1500 } 1501 1502 return false; 1503 } 1504 1505 IOReturn 1506 IODTNVRAM::syncInternal(bool rateLimit) 1507 { 1508 IOReturn ret = kIOReturnSuccess; 1509 1510 DEBUG_INFO("rateLimit=%d\n", rateLimit); 1511 1512 if (!SAFE_TO_LOCK()) { 1513 DEBUG_INFO("cannot lock\n"); 1514 goto exit; 1515 } 1516 1517 // Rate limit requests to sync. Drivers that need this rate limiting will 1518 // shadow the data and only write to flash when they get a sync call 1519 if (rateLimit) { 1520 if (safeToSync() == false) { 1521 DEBUG_INFO("safeToSync()=false\n"); 1522 goto exit; 1523 } 1524 } 1525 1526 DEBUG_INFO("Calling sync()\n"); 1527 record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "sync", "triggered"); 1528 1529 NVRAMREADLOCK(); 1530 CONTROLLERLOCK(); 1531 1532 ret = _format->sync(); 1533 1534 CONTROLLERUNLOCK(); 1535 NVRAMUNLOCK(); 1536 1537 record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "sync", "completed with ret=%08x", ret); 1538 1539 if (_diags) { 1540 OSSharedPtr<OSNumber> generation = OSNumber::withNumber(_format->getGeneration(), 32); 1541 _diags->setProperty(kCurrentGenerationCountKey, generation.get()); 1542 } 1543 1544 exit: 1545 return ret; 1546 } 1547 1548 IOReturn 1549 IODTNVRAM::sync(void) 1550 { 1551 return syncInternal(false); 1552 } 1553 1554 void 1555 IODTNVRAM::reload(void) 1556 { 1557 _format->reload(); 1558 } 1559 1560 OSPtr<OSDictionary> 1561 IODTNVRAM::dictionaryWithProperties(void) const 1562 { 1563 const OSSymbol *canonicalKey; 1564 OSSharedPtr<OSDictionary> localVarDict, returnDict; 1565 OSSharedPtr<OSCollectionIterator> iter; 1566 unsigned int totalCapacity = 0; 1567 uuid_t varGuid; 1568 const char * varName; 1569 1570 NVRAMREADLOCK(); 1571 if (_varDict) { 1572 localVarDict = OSDictionary::withDictionary(_varDict.get()); 1573 } 1574 NVRAMUNLOCK(); 1575 1576 if (localVarDict != nullptr) { 1577 totalCapacity = localVarDict->getCapacity(); 1578 } 1579 1580 returnDict = OSDictionary::withCapacity(totalCapacity); 1581 1582 if (returnDict == nullptr) { 1583 DEBUG_ERROR("No dictionary\n"); 1584 goto exit; 1585 } 1586 1587 // Copy system entries first if present then copy unique other entries 1588 iter = OSCollectionIterator::withCollection(localVarDict.get()); 1589 if (iter == nullptr) { 1590 DEBUG_ERROR("failed to create iterator\n"); 1591 goto exit; 1592 } 1593 1594 while ((canonicalKey = OSDynamicCast(OSSymbol, iter->getNextObject()))) { 1595 parseVariableName(canonicalKey, &varGuid, &varName); 1596 1597 if ((uuid_compare(varGuid, gAppleSystemVariableGuid) == 0) && 1598 verifyPermission(kIONVRAMOperationRead, varGuid, varName, _format->getSystemPartitionActive())) { 1599 OSSharedPtr<const OSSymbol> returnKey = OSSymbol::withCString(varName); 1600 returnDict->setObject(returnKey.get(), localVarDict->getObject(canonicalKey)); 1601 } 1602 } 1603 1604 iter.reset(); 1605 1606 iter = OSCollectionIterator::withCollection(localVarDict.get()); 1607 if (iter == nullptr) { 1608 DEBUG_ERROR("failed to create iterator\n"); 1609 goto exit; 1610 } 1611 1612 while ((canonicalKey = OSDynamicCast(OSSymbol, iter->getNextObject()))) { 1613 parseVariableName(canonicalKey, &varGuid, &varName); 1614 1615 if (uuid_compare(varGuid, gAppleNVRAMGuid) == 0) { 1616 if (returnDict->getObject(varName) != nullptr) { 1617 // Skip non uniques 1618 continue; 1619 } 1620 1621 if (verifyPermission(kIONVRAMOperationRead, varGuid, varName, _format->getSystemPartitionActive())) { 1622 OSSharedPtr<const OSSymbol> returnKey = OSSymbol::withCString(varName); 1623 returnDict->setObject(returnKey.get(), localVarDict->getObject(canonicalKey)); 1624 } 1625 } 1626 } 1627 exit: 1628 return returnDict; 1629 } 1630 1631 bool 1632 IODTNVRAM::serializeProperties(OSSerialize *s) const 1633 { 1634 bool ok = false; 1635 OSSharedPtr<OSDictionary> dict; 1636 1637 dict = dictionaryWithProperties(); 1638 if (dict) { 1639 ok = dict->serialize(s); 1640 } 1641 1642 DEBUG_INFO("ok=%d\n", ok); 1643 return ok; 1644 } 1645 1646 IOReturn 1647 IODTNVRAM::flushGUID(const uuid_t guid, IONVRAMOperation op) 1648 { 1649 IOReturn ret = kIOReturnSuccess; 1650 1651 if (_format->getSystemPartitionActive() && (uuid_compare(guid, gAppleSystemVariableGuid) == 0)) { 1652 ret = _format->flush(guid, op); 1653 1654 DEBUG_INFO("system variables flushed, ret=%08x\n", ret); 1655 } else if (uuid_compare(guid, gAppleNVRAMGuid) == 0) { 1656 ret = _format->flush(guid, op); 1657 1658 DEBUG_INFO("common variables flushed, ret=%08x\n", ret); 1659 } 1660 1661 return ret; 1662 } 1663 1664 bool 1665 IODTNVRAM::handleSpecialVariables(const char *name, const uuid_t guid, const OSObject *obj, IOReturn *error) 1666 { 1667 IOReturn ret = kIOReturnSuccess; 1668 bool special = false; 1669 1670 NVRAMLOCKASSERTEXCLUSIVE(); 1671 1672 // ResetNVRam flushes both regions in one call 1673 // Obliterate can flush either separately 1674 if (strcmp(name, "ObliterateNVRam") == 0) { 1675 special = true; 1676 ret = flushGUID(guid, kIONVRAMOperationObliterate); 1677 } else if (strcmp(name, "ResetNVRam") == 0) { 1678 special = true; 1679 ret = flushGUID(gAppleSystemVariableGuid, kIONVRAMOperationReset); 1680 1681 if (ret != kIOReturnSuccess) { 1682 goto exit; 1683 } 1684 1685 ret = flushGUID(gAppleNVRAMGuid, kIONVRAMOperationReset); 1686 } 1687 1688 exit: 1689 if (error) { 1690 *error = ret; 1691 } 1692 1693 return special; 1694 } 1695 1696 OSSharedPtr<OSObject> 1697 IODTNVRAM::copyPropertyWithGUIDAndName(const uuid_t guid, const char *name) const 1698 { 1699 OSSharedPtr<const OSSymbol> canonicalKey; 1700 OSSharedPtr<OSObject> theObject; 1701 uuid_t newGuid; 1702 1703 if (_varDict == nullptr) { 1704 DEBUG_INFO("No dictionary\n"); 1705 goto exit; 1706 } 1707 1708 if (!verifyPermission(kIONVRAMOperationRead, guid, name, _format->getSystemPartitionActive())) { 1709 DEBUG_INFO("Not privileged\n"); 1710 goto exit; 1711 } 1712 1713 translateGUID(guid, name, newGuid, _format->getSystemPartitionActive()); 1714 1715 canonicalKey = keyWithGuidAndCString(newGuid, name); 1716 1717 NVRAMREADLOCK(); 1718 theObject.reset(_varDict->getObject(canonicalKey.get()), OSRetain); 1719 NVRAMUNLOCK(); 1720 1721 if (_diags) { 1722 _diags->logVariable(getPartitionTypeForGUID(newGuid), kIONVRAMOperationRead, name, NULL); 1723 } 1724 1725 if (theObject != nullptr) { 1726 DEBUG_INFO("%s has object\n", canonicalKey.get()->getCStringNoCopy()); 1727 } else { 1728 DEBUG_INFO("%s no entry\n", canonicalKey.get()->getCStringNoCopy()); 1729 } 1730 1731 exit: 1732 return theObject; 1733 } 1734 1735 OSSharedPtr<OSObject> 1736 IODTNVRAM::copyProperty(const OSSymbol *aKey) const 1737 { 1738 const char *variableName; 1739 uuid_t varGuid; 1740 1741 if (skipKey(aKey)) { 1742 return nullptr; 1743 } 1744 DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy()); 1745 1746 parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName); 1747 1748 return copyPropertyWithGUIDAndName(varGuid, variableName); 1749 } 1750 1751 OSSharedPtr<OSObject> 1752 IODTNVRAM::copyProperty(const char *aKey) const 1753 { 1754 OSSharedPtr<const OSSymbol> keySymbol; 1755 OSSharedPtr<OSObject> theObject; 1756 1757 keySymbol = OSSymbol::withCString(aKey); 1758 if (keySymbol != nullptr) { 1759 theObject = copyProperty(keySymbol.get()); 1760 } 1761 1762 return theObject; 1763 } 1764 1765 OSObject * 1766 IODTNVRAM::getProperty(const OSSymbol *aKey) const 1767 { 1768 // The shared pointer gets released at the end of the function, 1769 // and returns a view into theObject. 1770 OSSharedPtr<OSObject> theObject = copyProperty(aKey); 1771 1772 return theObject.get(); 1773 } 1774 1775 OSObject * 1776 IODTNVRAM::getProperty(const char *aKey) const 1777 { 1778 // The shared pointer gets released at the end of the function, 1779 // and returns a view into theObject. 1780 OSSharedPtr<OSObject> theObject = copyProperty(aKey); 1781 1782 return theObject.get(); 1783 } 1784 1785 IOReturn 1786 IODTNVRAM::setPropertyWithGUIDAndName(const uuid_t guid, const char *name, OSObject *anObject) 1787 { 1788 IOReturn ret = kIOReturnSuccess; 1789 bool remove = false; 1790 OSString *tmpString = nullptr; 1791 OSSharedPtr<OSObject> propObject; 1792 OSSharedPtr<OSObject> sharedObject(anObject, OSRetain); 1793 bool deletePropertyKey, syncNowPropertyKey, forceSyncNowPropertyKey, deletePropertyKeyWRet; 1794 bool ok; 1795 size_t propDataSize = 0; 1796 uuid_t newGuid; 1797 1798 deletePropertyKey = strncmp(name, kIONVRAMDeletePropertyKey, sizeof(kIONVRAMDeletePropertyKey)) == 0; 1799 deletePropertyKeyWRet = strncmp(name, kIONVRAMDeletePropertyKeyWRet, sizeof(kIONVRAMDeletePropertyKeyWRet)) == 0; 1800 syncNowPropertyKey = strncmp(name, kIONVRAMSyncNowPropertyKey, sizeof(kIONVRAMSyncNowPropertyKey)) == 0; 1801 forceSyncNowPropertyKey = strncmp(name, kIONVRAMForceSyncNowPropertyKey, sizeof(kIONVRAMForceSyncNowPropertyKey)) == 0; 1802 1803 if (deletePropertyKey || deletePropertyKeyWRet) { 1804 tmpString = OSDynamicCast(OSString, anObject); 1805 if (tmpString != nullptr) { 1806 const char *variableName; 1807 uuid_t valueVarGuid; 1808 bool guidProvided; 1809 IOReturn removeRet; 1810 1811 guidProvided = parseVariableName(tmpString->getCStringNoCopy(), &valueVarGuid, &variableName); 1812 1813 // nvram tool will provide a "nvram -d var" or "nvram -d guid:var" as 1814 // kIONVRAMDeletePropertyKey=var or kIONVRAMDeletePropertyKey=guid:var 1815 // that will come into this function as (gAppleNVRAMGuid, varname, nullptr) 1816 // if we provide the "-z" flag to the nvram tool this function will come in as 1817 // (gAppleSystemVariableGuid, varname, nullptr). We are reparsing the value string, 1818 // if there is a GUID provided with the value then use that GUID otherwise use the 1819 // guid that was provided via the node selection or default. 1820 if (guidProvided == false) { 1821 DEBUG_INFO("Removing with API provided GUID\n"); 1822 removeRet = removePropertyWithGUIDAndName(guid, variableName); 1823 } else { 1824 DEBUG_INFO("Removing with value provided GUID\n"); 1825 removeRet = removePropertyWithGUIDAndName(valueVarGuid, variableName); 1826 } 1827 if (deletePropertyKeyWRet) { 1828 ret = removeRet; 1829 } 1830 DEBUG_INFO("%s found, removeRet=%#08x\n", deletePropertyKeyWRet ? "deletePropertyKeyWRet" : "deletePropertyKey", removeRet); 1831 } else { 1832 DEBUG_INFO("%s value needs to be an OSString\n", deletePropertyKeyWRet ? "deletePropertyKeyWRet" : "deletePropertyKey"); 1833 ret = kIOReturnError; 1834 } 1835 goto exit; 1836 } else if (syncNowPropertyKey || forceSyncNowPropertyKey) { 1837 tmpString = OSDynamicCast(OSString, anObject); 1838 DEBUG_INFO("NVRAM sync key %s found\n", name); 1839 if (tmpString != nullptr) { 1840 // We still want to throttle NVRAM commit rate for SyncNow. ForceSyncNow is provided as a really big hammer. 1841 ret = syncInternal(syncNowPropertyKey); 1842 } else { 1843 DEBUG_INFO("%s value needs to be an OSString\n", name); 1844 ret = kIOReturnError; 1845 } 1846 goto exit; 1847 } 1848 1849 if (!verifyPermission(kIONVRAMOperationWrite, guid, name, _format->getSystemPartitionActive())) { 1850 DEBUG_INFO("Not privileged\n"); 1851 ret = kIOReturnNotPrivileged; 1852 goto exit; 1853 } 1854 1855 // Make sure the object is of the correct type. 1856 switch (getVariableType(name)) { 1857 case kOFVariableTypeBoolean: 1858 propObject = OSDynamicPtrCast<OSBoolean>(sharedObject); 1859 if (propObject) { 1860 record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "write", "%s as bool to %d", name, ((OSBoolean *)propObject.get())->getValue()); 1861 } 1862 break; 1863 1864 case kOFVariableTypeNumber: 1865 propObject = OSDynamicPtrCast<OSNumber>(sharedObject); 1866 if (propObject) { 1867 record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "write", "%s as number to %#llx", name, ((OSNumber *)propObject.get())->unsigned64BitValue()); 1868 } 1869 break; 1870 1871 case kOFVariableTypeString: 1872 propObject = OSDynamicPtrCast<OSString>(sharedObject); 1873 if (propObject != nullptr) { 1874 record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "write", "%s as string to %s", name, ((OSString *)propObject.get())->getCStringNoCopy()); 1875 1876 propDataSize = (OSDynamicPtrCast<OSString>(propObject))->getLength(); 1877 1878 if ((strncmp(name, kIONVRAMBootArgsKey, sizeof(kIONVRAMBootArgsKey)) == 0) && (propDataSize >= BOOT_LINE_LENGTH)) { 1879 DEBUG_ERROR("boot-args size too large for BOOT_LINE_LENGTH, propDataSize=%zu\n", propDataSize); 1880 ret = kIOReturnNoSpace; 1881 goto exit; 1882 } 1883 } 1884 break; 1885 1886 case kOFVariableTypeData: 1887 propObject = OSDynamicPtrCast<OSData>(sharedObject); 1888 if (propObject == nullptr) { 1889 tmpString = OSDynamicCast(OSString, sharedObject.get()); 1890 if (tmpString != nullptr) { 1891 propObject = OSData::withBytes(tmpString->getCStringNoCopy(), 1892 tmpString->getLength()); 1893 } 1894 } 1895 1896 if (propObject != nullptr) { 1897 propDataSize = (OSDynamicPtrCast<OSData>(propObject))->getLength(); 1898 record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "write", "%s as data with size %#x", name, ((OSData *)propObject.get())->getLength()); 1899 } 1900 1901 #if defined(XNU_TARGET_OS_OSX) 1902 if ((propObject != nullptr) && ((OSDynamicPtrCast<OSData>(propObject))->getLength() == 0)) { 1903 remove = true; 1904 } 1905 #endif /* defined(XNU_TARGET_OS_OSX) */ 1906 break; 1907 default: 1908 break; 1909 } 1910 1911 if (propObject == nullptr) { 1912 DEBUG_ERROR("No property object\n"); 1913 ret = kIOReturnBadArgument; 1914 goto exit; 1915 } 1916 1917 if (!verifyWriteSizeLimit(guid, name, propDataSize)) { 1918 DEBUG_ERROR("Property data size of %zu too long for %s\n", propDataSize, name); 1919 ret = kIOReturnNoSpace; 1920 goto exit; 1921 } 1922 1923 NVRAMWRITELOCK(); 1924 ok = handleSpecialVariables(name, guid, propObject.get(), &ret); 1925 NVRAMUNLOCK(); 1926 1927 if (ok) { 1928 goto exit; 1929 } 1930 1931 if (remove == false) { 1932 DEBUG_INFO("Adding object\n"); 1933 1934 translateGUID(guid, name, newGuid, _format->getSystemPartitionActive()); 1935 1936 NVRAMWRITELOCK(); 1937 1938 ret = _format->setVariable(newGuid, name, propObject.get()); 1939 1940 NVRAMUNLOCK(); 1941 } else { 1942 DEBUG_INFO("Removing object\n"); 1943 ret = removePropertyWithGUIDAndName(guid, name); 1944 } 1945 1946 if (tmpString) { 1947 propObject.reset(); 1948 } 1949 1950 exit: 1951 DEBUG_INFO("ret=%#08x\n", ret); 1952 1953 return ret; 1954 } 1955 1956 IOReturn 1957 IODTNVRAM::setPropertyInternal(const OSSymbol *aKey, OSObject *anObject) 1958 { 1959 const char *variableName; 1960 uuid_t varGuid; 1961 1962 DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy()); 1963 1964 parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName); 1965 1966 return setPropertyWithGUIDAndName(varGuid, variableName, anObject); 1967 } 1968 1969 bool 1970 IODTNVRAM::setProperty(const OSSymbol *aKey, OSObject *anObject) 1971 { 1972 return setPropertyInternal(aKey, anObject) == kIOReturnSuccess; 1973 } 1974 1975 void 1976 IODTNVRAM::removeProperty(const OSSymbol *aKey) 1977 { 1978 IOReturn ret; 1979 1980 ret = removePropertyInternal(aKey); 1981 1982 if (ret != kIOReturnSuccess) { 1983 DEBUG_INFO("removePropertyInternal failed, ret=%#08x\n", ret); 1984 } 1985 } 1986 1987 IOReturn 1988 IODTNVRAM::removePropertyWithGUIDAndName(const uuid_t guid, const char *name) 1989 { 1990 IOReturn ret; 1991 uuid_t newGuid; 1992 1993 DEBUG_INFO("name=%s\n", name); 1994 1995 if (_varDict == nullptr) { 1996 DEBUG_INFO("No dictionary\n"); 1997 ret = kIOReturnNotFound; 1998 goto exit; 1999 } 2000 2001 if (!verifyPermission(kIONVRAMOperationDelete, guid, name, _format->getSystemPartitionActive())) { 2002 DEBUG_INFO("Not privileged\n"); 2003 ret = kIOReturnNotPrivileged; 2004 goto exit; 2005 } 2006 2007 translateGUID(guid, name, newGuid, _format->getSystemPartitionActive()); 2008 2009 NVRAMWRITELOCK(); 2010 2011 ret = _format->setVariable(newGuid, name, nullptr); 2012 2013 if (ret != kIOReturnSuccess) { 2014 DEBUG_INFO("%s not found\n", name); 2015 ret = kIOReturnNotFound; 2016 } 2017 2018 NVRAMUNLOCK(); 2019 2020 record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "delete", "%s", name); 2021 2022 exit: 2023 return ret; 2024 } 2025 2026 IOReturn 2027 IODTNVRAM::removePropertyInternal(const OSSymbol *aKey) 2028 { 2029 IOReturn ret; 2030 const char *variableName; 2031 uuid_t varGuid; 2032 2033 DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy()); 2034 2035 parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName); 2036 2037 ret = removePropertyWithGUIDAndName(varGuid, variableName); 2038 2039 return ret; 2040 } 2041 2042 IOReturn 2043 IODTNVRAM::setProperties(OSObject *properties) 2044 { 2045 IOReturn ret = kIOReturnSuccess; 2046 OSObject *object; 2047 const OSSymbol *key; 2048 OSDictionary *dict; 2049 OSSharedPtr<OSCollectionIterator> iter; 2050 2051 dict = OSDynamicCast(OSDictionary, properties); 2052 if (dict == nullptr) { 2053 DEBUG_ERROR("Not a dictionary\n"); 2054 return kIOReturnBadArgument; 2055 } 2056 2057 iter = OSCollectionIterator::withCollection(dict); 2058 if (iter == nullptr) { 2059 DEBUG_ERROR("Couldn't create iterator\n"); 2060 return kIOReturnBadArgument; 2061 } 2062 2063 while (ret == kIOReturnSuccess) { 2064 key = OSDynamicCast(OSSymbol, iter->getNextObject()); 2065 if (key == nullptr) { 2066 break; 2067 } 2068 2069 object = dict->getObject(key); 2070 if (object == nullptr) { 2071 continue; 2072 } 2073 2074 ret = setPropertyInternal(key, object); 2075 } 2076 2077 DEBUG_INFO("ret=%#08x\n", ret); 2078 2079 return ret; 2080 } 2081 2082 // ********************** Deprecated ******************** 2083 2084 IOReturn 2085 IODTNVRAM::readXPRAM(IOByteCount offset, uint8_t *buffer, 2086 IOByteCount length) 2087 { 2088 return kIOReturnUnsupported; 2089 } 2090 2091 IOReturn 2092 IODTNVRAM::writeXPRAM(IOByteCount offset, uint8_t *buffer, 2093 IOByteCount length) 2094 { 2095 return kIOReturnUnsupported; 2096 } 2097 2098 IOReturn 2099 IODTNVRAM::readNVRAMProperty(IORegistryEntry *entry, 2100 const OSSymbol **name, 2101 OSData **value) 2102 { 2103 return kIOReturnUnsupported; 2104 } 2105 2106 IOReturn 2107 IODTNVRAM::writeNVRAMProperty(IORegistryEntry *entry, 2108 const OSSymbol *name, 2109 OSData *value) 2110 { 2111 return kIOReturnUnsupported; 2112 } 2113 2114 OSDictionary * 2115 IODTNVRAM::getNVRAMPartitions(void) 2116 { 2117 return NULL; 2118 } 2119 2120 IOReturn 2121 IODTNVRAM::readNVRAMPartition(const OSSymbol *partitionID, 2122 IOByteCount offset, uint8_t *buffer, 2123 IOByteCount length) 2124 { 2125 return kIOReturnUnsupported; 2126 } 2127 2128 IOReturn 2129 IODTNVRAM::writeNVRAMPartition(const OSSymbol *partitionID, 2130 IOByteCount offset, uint8_t *buffer, 2131 IOByteCount length) 2132 { 2133 return kIOReturnUnsupported; 2134 } 2135 2136 IOByteCount 2137 IODTNVRAM::savePanicInfo(uint8_t *buffer, IOByteCount length) 2138 { 2139 return 0; 2140 } 2141