X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/fe8ab488e9161c46dd9885d58fc52996dc0249ff..d26ffc64f583ab2d29df48f13518685602bc8832:/iokit/Kernel/IONVRAM.cpp diff --git a/iokit/Kernel/IONVRAM.cpp b/iokit/Kernel/IONVRAM.cpp index 5af96b290..94d6b75dd 100644 --- a/iokit/Kernel/IONVRAM.cpp +++ b/iokit/Kernel/IONVRAM.cpp @@ -32,9 +32,17 @@ #include #include #include +#include #include #include +#if CONFIG_MACF +extern "C" { +#include +#include +}; +#endif /* MAC */ + #define super IOService #define kIONVRAMPrivilege kIOClientPrivilegeAdministrator @@ -67,7 +75,7 @@ bool IODTNVRAM::init(IORegistryEntry *old, const IORegistryPlane *plane) // race condition possible between // IODTNVRAM and IONVRAMController (restore loses boot-args) initProxyData(); - + return true; } @@ -86,7 +94,7 @@ void IODTNVRAM::initProxyData(void) data = OSDynamicCast(OSData, prop); if (data != 0) { bytes = data->getBytesNoCopy(); - if (bytes != 0) { + if ((bytes != 0) && (data->getLength() <= kIODTNVRAMImageSize)) { bcopy(bytes, _nvramImage, data->getLength()); initNVRAMImage(); _isProxied = true; @@ -109,6 +117,10 @@ void IODTNVRAM::registerNVRAMController(IONVRAMController *nvram) if (!_isProxied) { _nvramController->read(0, _nvramImage, kIODTNVRAMImageSize); initNVRAMImage(); + } else { + IOLockLock(_ofLock); + (void) syncVariables(); + IOLockUnlock(_ofLock); } } @@ -129,9 +141,11 @@ void IODTNVRAM::initNVRAMImage(void) // Look through the partitions to find the OF, MacOS partitions. while (currentOffset < kIODTNVRAMImageSize) { currentLength = ((UInt16 *)(_nvramImage + currentOffset))[1] * 16; - + + if (currentLength < 16) break; partitionOffset = currentOffset + 16; partitionLength = currentLength - 16; + if ((partitionOffset + partitionLength) > kIODTNVRAMImageSize) break; if (strncmp((const char *)_nvramImage + currentOffset + 4, kIODTNVRAMOFPartitionName, 12) == 0) { @@ -217,9 +231,10 @@ void IODTNVRAM::initNVRAMImage(void) // Set the partition checksum. _nvramImage[freePartitionOffset + 1] = calculatePartitionChecksum(_nvramImage + freePartitionOffset); - - // Set the nvram image as dirty. - _nvramImageDirty = true; + + if (_nvramController != 0) { + _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize); + } } } else { _piImage = _nvramImage + _piPartitionOffset; @@ -231,20 +246,21 @@ void IODTNVRAM::initNVRAMImage(void) initOFVariables(); } -void IODTNVRAM::sync(void) +void IODTNVRAM::syncInternal(bool rateLimit) { - if (!_nvramImageDirty && !_ofImageDirty) return; - - // Don't try to sync OF Variables if the system has already paniced. - if (!_systemPaniced) syncOFVariables(); - // Don't try to perform controller operations if none has been registered. if (_nvramController == 0) return; + + // Rate limit requests to sync. Drivers that need this rate limiting will + // shadow the data and only write to flash when they get a sync call + if (rateLimit && !safeToSync()) return; - _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize); _nvramController->sync(); - - _nvramImageDirty = false; +} + +void IODTNVRAM::sync(void) +{ + syncInternal(false); } bool IODTNVRAM::serializeProperties(OSSerialize *s) const @@ -280,8 +296,15 @@ bool IODTNVRAM::serializeProperties(OSSerialize *s) const variablePerm = getOFVariablePerm(key); if ((hasPrivilege || (variablePerm != kOFVariablePermRootOnly)) && - ( ! (variablePerm == kOFVariablePermKernelOnly && current_task() != kernel_task) )) {} - else dict->removeObject(key); + ( ! (variablePerm == kOFVariablePermKernelOnly && current_task() != kernel_task) ) +#if CONFIG_MACF + && (current_task() == kernel_task || mac_iokit_check_nvram_get(kauth_cred_get(), key->getCStringNoCopy()) == 0) +#endif + ) { } + else { + dict->removeObject(key); + iter->reset(); + } } } @@ -309,6 +332,12 @@ OSObject *IODTNVRAM::copyProperty(const OSSymbol *aKey) const } if (variablePerm == kOFVariablePermKernelOnly && current_task() != kernel_task) return 0; +#if CONFIG_MACF + if (current_task() != kernel_task && + mac_iokit_check_nvram_get(kauth_cred_get(), aKey->getCStringNoCopy()) != 0) + return 0; +#endif + IOLockLock(_ofLock); theObject = _ofDict->getObject(aKey); if (theObject) theObject->retain(); @@ -356,20 +385,25 @@ bool IODTNVRAM::setProperty(const OSSymbol *aKey, OSObject *anObject) bool result; UInt32 propType, propPerm; OSString *tmpString; - OSObject *propObject = 0; - + OSObject *propObject = 0, *oldObject; + if (_ofDict == 0) return false; - + // Verify permissions. propPerm = getOFVariablePerm(aKey); - result = IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege); - if (result != kIOReturnSuccess) { + if (IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege) != kIOReturnSuccess) { if (propPerm != kOFVariablePermUserWrite) return false; } if (propPerm == kOFVariablePermKernelOnly && current_task() != kernel_task) return 0; // Don't allow change of 'aapl,panic-info'. if (aKey->isEqualTo(kIODTNVRAMPanicInfoKey)) return false; + +#if CONFIG_MACF + if (current_task() != kernel_task && + mac_iokit_check_nvram_set(kauth_cred_get(), aKey->getCStringNoCopy(), anObject) != 0) + return false; +#endif // Make sure the object is of the correct type. propType = getOFVariableType(aKey); @@ -377,15 +411,15 @@ bool IODTNVRAM::setProperty(const OSSymbol *aKey, OSObject *anObject) case kOFVariableTypeBoolean : propObject = OSDynamicCast(OSBoolean, anObject); break; - + case kOFVariableTypeNumber : propObject = OSDynamicCast(OSNumber, anObject); break; - + case kOFVariableTypeString : propObject = OSDynamicCast(OSString, anObject); break; - + case kOFVariableTypeData : propObject = OSDynamicCast(OSData, anObject); if (propObject == 0) { @@ -397,17 +431,36 @@ bool IODTNVRAM::setProperty(const OSSymbol *aKey, OSObject *anObject) } break; } - + if (propObject == 0) return false; IOLockLock(_ofLock); + + oldObject = _ofDict->getObject(aKey); + if (oldObject) { + oldObject->retain(); + } result = _ofDict->setObject(aKey, propObject); - IOLockUnlock(_ofLock); - + if (result) { - _ofImageDirty = true; + if (syncVariables() != kIOReturnSuccess) { + if (oldObject) { + _ofDict->setObject(aKey, oldObject); + } + else { + _ofDict->removeObject(aKey); + } + (void) syncVariables(); + result = false; + } } - + + if (oldObject) { + oldObject->release(); + } + + IOLockUnlock(_ofLock); + return result; } @@ -429,14 +482,24 @@ void IODTNVRAM::removeProperty(const OSSymbol *aKey) // Don't allow change of 'aapl,panic-info'. if (aKey->isEqualTo(kIODTNVRAMPanicInfoKey)) return; +#if CONFIG_MACF + if (current_task() != kernel_task && + mac_iokit_check_nvram_delete(kauth_cred_get(), aKey->getCStringNoCopy()) != 0) + return; +#endif + // If the object exists, remove it from the dictionary. IOLockLock(_ofLock); result = _ofDict->getObject(aKey) != 0; if (result) { _ofDict->removeObject(aKey); - _ofImageDirty = true; } + + if (result) { + (void) syncVariables(); + } + IOLockUnlock(_ofLock); } @@ -472,14 +535,15 @@ IOReturn IODTNVRAM::setProperties(OSObject *properties) } else { result = false; } - } else if(key->isEqualTo(kIONVRAMSyncNowPropertyKey)) { + } else if(key->isEqualTo(kIONVRAMSyncNowPropertyKey) || key->isEqualTo(kIONVRAMForceSyncNowPropertyKey)) { tmpStr = OSDynamicCast(OSString, object); if (tmpStr != 0) { - result = true; // We are not going to gaurantee sync, this is best effort + result = true; - if(safeToSync()) - sync(); + // We still want to throttle NVRAM commit rate for SyncNow. ForceSyncNow is provided as a really big hammer. + + syncInternal(key->isEqualTo(kIONVRAMSyncNowPropertyKey)); } else { result = false; @@ -541,7 +605,7 @@ IOReturn IODTNVRAM::readNVRAMPartition(const OSSymbol *partitionID, IOByteCount length) { OSNumber *partitionOffsetNumber, *partitionLengthNumber; - UInt32 partitionOffset, partitionLength; + UInt32 partitionOffset, partitionLength, end; partitionOffsetNumber = (OSNumber *)_nvramPartitionOffsets->getObject(partitionID); @@ -554,8 +618,8 @@ IOReturn IODTNVRAM::readNVRAMPartition(const OSSymbol *partitionID, partitionOffset = partitionOffsetNumber->unsigned32BitValue(); partitionLength = partitionLengthNumber->unsigned32BitValue(); - if ((buffer == 0) || (length == 0) || - (offset + length > partitionLength)) + if (os_add_overflow(offset, length, &end)) return kIOReturnBadArgument; + if ((buffer == 0) || (length == 0) || (end > partitionLength)) return kIOReturnBadArgument; bcopy(_nvramImage + partitionOffset + offset, buffer, length); @@ -568,7 +632,7 @@ IOReturn IODTNVRAM::writeNVRAMPartition(const OSSymbol *partitionID, IOByteCount length) { OSNumber *partitionOffsetNumber, *partitionLengthNumber; - UInt32 partitionOffset, partitionLength; + UInt32 partitionOffset, partitionLength, end; partitionOffsetNumber = (OSNumber *)_nvramPartitionOffsets->getObject(partitionID); @@ -581,13 +645,15 @@ IOReturn IODTNVRAM::writeNVRAMPartition(const OSSymbol *partitionID, partitionOffset = partitionOffsetNumber->unsigned32BitValue(); partitionLength = partitionLengthNumber->unsigned32BitValue(); - if ((buffer == 0) || (length == 0) || - (offset + length > partitionLength)) + if (os_add_overflow(offset, length, &end)) return kIOReturnBadArgument; + if ((buffer == 0) || (length == 0) || (end > partitionLength)) return kIOReturnBadArgument; bcopy(buffer, _nvramImage + partitionOffset + offset, length); - _nvramImageDirty = true; + if (_nvramController != 0) { + _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize); + } return kIOReturnSuccess; } @@ -605,7 +671,9 @@ IOByteCount IODTNVRAM::savePanicInfo(UInt8 *buffer, IOByteCount length) // Save the Panic Info length. *(UInt32 *)_piImage = length; - _nvramImageDirty = true; + if (_nvramController != 0) { + _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize); + } /* * This prevents OF variables from being committed if the system has panicked */ @@ -691,7 +759,6 @@ IOReturn IODTNVRAM::initOFVariables(void) } } - // Create the 'aapl,panic-info' property if needed. if (_piImage != 0) { propDataLength = *(UInt32 *)_piImage; if ((propDataLength != 0) && (propDataLength <= (_piPartitionSize - 4))) { @@ -701,7 +768,9 @@ IOReturn IODTNVRAM::initOFVariables(void) // Clear the length from _piImage and mark dirty. *(UInt32 *)_piImage = 0; - _nvramImageDirty = true; + if (_nvramController != 0) { + _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize); + } } } @@ -709,6 +778,11 @@ IOReturn IODTNVRAM::initOFVariables(void) } IOReturn IODTNVRAM::syncOFVariables(void) +{ + return kIOReturnUnsupported; +} + +IOReturn IODTNVRAM::syncVariables(void) { bool ok; UInt32 length, maxLength; @@ -716,31 +790,30 @@ IOReturn IODTNVRAM::syncOFVariables(void) const OSSymbol *tmpSymbol; OSObject *tmpObject; OSCollectionIterator *iter; - - if ((_ofImage == 0) || (_ofDict == 0)) return kIOReturnNotReady; - - if (!_ofImageDirty) return kIOReturnSuccess; - + + IOLockAssert(_ofLock, kIOLockAssertOwned); + + if ((_ofImage == 0) || (_ofDict == 0) || _systemPaniced) return kIOReturnNotReady; + buffer = tmpBuffer = IONew(UInt8, _ofPartitionSize); if (buffer == 0) return kIOReturnNoMemory; bzero(buffer, _ofPartitionSize); - + ok = true; maxLength = _ofPartitionSize; - IOLockLock(_ofLock); iter = OSCollectionIterator::withCollection(_ofDict); if (iter == 0) ok = false; - + while (ok) { tmpSymbol = OSDynamicCast(OSSymbol, iter->getNextObject()); if (tmpSymbol == 0) break; - + // Don't save 'aapl,panic-info'. if (tmpSymbol->isEqualTo(kIODTNVRAMPanicInfoKey)) continue; - + tmpObject = _ofDict->getObject(tmpSymbol); - + length = maxLength; ok = convertObjectToProp(tmpBuffer, &length, tmpSymbol, tmpObject); if (ok) { @@ -749,20 +822,20 @@ IOReturn IODTNVRAM::syncOFVariables(void) } } iter->release(); - IOLockUnlock(_ofLock); - + if (ok) { bcopy(buffer, _ofImage, _ofPartitionSize); } - + IODelete(buffer, UInt8, _ofPartitionSize); - + if (!ok) return kIOReturnBadArgument; - - _ofImageDirty = false; - _nvramImageDirty = true; - - return kIOReturnSuccess; + + if (_nvramController != 0) { + return _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize); + } + + return kIOReturnNotReady; } struct OFVariable { @@ -778,6 +851,7 @@ enum { kOWVariableOffsetString = 17 }; +static const OFVariable gOFVariables[] = { {"little-endian?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 0}, {"real-mode?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 1}, @@ -826,12 +900,22 @@ OFVariable gOFVariables[] = { {"security-password", kOFVariableTypeData, kOFVariablePermRootOnly, -1}, {"boot-image", kOFVariableTypeData, kOFVariablePermUserWrite, -1}, {"com.apple.System.fp-state", kOFVariableTypeData, kOFVariablePermKernelOnly, -1}, +#if CONFIG_EMBEDDED + {"backlight-level", kOFVariableTypeData, kOFVariablePermUserWrite, -1}, + {"com.apple.System.sep.art", kOFVariableTypeData, kOFVariablePermKernelOnly, -1}, + {"com.apple.System.boot-nonce", kOFVariableTypeString, kOFVariablePermKernelOnly, -1}, + {"darkboot", kOFVariableTypeBoolean, kOFVariablePermUserWrite, -1}, + {"acc-mb-ld-lifetime", kOFVariableTypeNumber, kOFVariablePermKernelOnly, -1}, + {"acc-cm-override-charger-count", kOFVariableTypeNumber, kOFVariablePermKernelOnly, -1}, + {"acc-cm-override-count", kOFVariableTypeNumber, kOFVariablePermKernelOnly, -1}, + {"enter-tdm-mode", kOFVariableTypeBoolean, kOFVariablePermUserWrite, -1}, +#endif {0, kOFVariableTypeData, kOFVariablePermUserRead, -1} }; UInt32 IODTNVRAM::getOFVariableType(const OSSymbol *propSymbol) const { - OFVariable *ofVar; + const OFVariable *ofVar; ofVar = gOFVariables; while (1) { @@ -845,7 +929,7 @@ UInt32 IODTNVRAM::getOFVariableType(const OSSymbol *propSymbol) const UInt32 IODTNVRAM::getOFVariablePerm(const OSSymbol *propSymbol) const { - OFVariable *ofVar; + const OFVariable *ofVar; ofVar = gOFVariables; while (1) { @@ -860,7 +944,7 @@ UInt32 IODTNVRAM::getOFVariablePerm(const OSSymbol *propSymbol) const bool IODTNVRAM::getOWVariableInfo(UInt32 variableNumber, const OSSymbol **propSymbol, UInt32 *propType, UInt32 *propOffset) { - OFVariable *ofVar; + const OFVariable *ofVar; ofVar = gOFVariables; while (1) { @@ -953,7 +1037,7 @@ bool IODTNVRAM::convertObjectToProp(UInt8 *buffer, UInt32 *length, const OSSymbol *propSymbol, OSObject *propObject) { const UInt8 *propName; - UInt32 propNameLength, propDataLength; + UInt32 propNameLength, propDataLength, remaining; UInt32 propType, tmpValue; OSBoolean *tmpBoolean = 0; OSNumber *tmpNumber = 0; @@ -997,29 +1081,30 @@ bool IODTNVRAM::convertObjectToProp(UInt8 *buffer, UInt32 *length, // Copy the property name equal sign. buffer += snprintf((char *)buffer, *length, "%s=", propName); - + remaining = *length - propNameLength - 1; + switch (propType) { case kOFVariableTypeBoolean : if (tmpBoolean->getValue()) { - strlcpy((char *)buffer, "true", *length - propNameLength); + strlcpy((char *)buffer, "true", remaining); } else { - strlcpy((char *)buffer, "false", *length - propNameLength); + strlcpy((char *)buffer, "false", remaining); } break; case kOFVariableTypeNumber : tmpValue = tmpNumber->unsigned32BitValue(); if (tmpValue == 0xFFFFFFFF) { - strlcpy((char *)buffer, "-1", *length - propNameLength); + strlcpy((char *)buffer, "-1", remaining); } else if (tmpValue < 1000) { - snprintf((char *)buffer, *length - propNameLength, "%d", (uint32_t)tmpValue); + snprintf((char *)buffer, remaining, "%d", (uint32_t)tmpValue); } else { - snprintf((char *)buffer, *length - propNameLength, "0x%x", (uint32_t)tmpValue); + snprintf((char *)buffer, remaining, "0x%x", (uint32_t)tmpValue); } break; case kOFVariableTypeString : - strlcpy((char *)buffer, tmpString->getCStringNoCopy(), *length - propNameLength); + strlcpy((char *)buffer, tmpString->getCStringNoCopy(), remaining); break; case kOFVariableTypeData : @@ -1317,7 +1402,7 @@ IOReturn IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry, const OSSymbol *propName, OSData *value) { - OSData *oldData; + OSData *oldData, *escapedData; OSData *data = 0; const UInt8 *startPtr; const UInt8 *propStart; @@ -1341,9 +1426,10 @@ IOReturn IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry, oldData = OSDynamicCast(OSData, _ofDict->getObject(_registryPropertiesKey)); if (oldData) { + startPtr = (const UInt8 *) oldData->getBytesNoCopy(); endPtr = startPtr + oldData->getLength(); - + propStart = startPtr; wherePtr = startPtr; while (wherePtr < endPtr) { @@ -1371,7 +1457,7 @@ IOReturn IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry, nvPath = 0; nvName = 0; } - + startPtr = wherePtr; } } @@ -1417,22 +1503,40 @@ IOReturn IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry, // append prop name ok &= data->appendBytes(propName->getCStringNoCopy(), propName->getLength() + 1); - + // append escaped data - oldData = escapeDataToData(value); - ok &= (oldData != 0); - if (ok) ok &= data->appendBytes(oldData); + escapedData = escapeDataToData(value); + ok &= (escapedData != 0); + if (ok) ok &= data->appendBytes(escapedData); } while (false); + oldData->retain(); if (ok) { ok = _ofDict->setObject(_registryPropertiesKey, data); - if (ok) _ofImageDirty = true; } - IOLockUnlock(_ofLock); if (data) data->release(); + if (ok) { + if (syncVariables() != kIOReturnSuccess) { + if (oldData) { + _ofDict->setObject(_registryPropertiesKey, oldData); + } + else { + _ofDict->removeObject(_registryPropertiesKey); + } + (void) syncVariables(); + ok = false; + } + } + + if (oldData) { + oldData->release(); + } + + IOLockUnlock(_ofLock); + return ok ? kIOReturnSuccess : kIOReturnNoMemory; }