X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/3e170ce000f1506b7b5d2c5c7faec85ceabb573d..d26ffc64f583ab2d29df48f13518685602bc8832:/iokit/Kernel/IONVRAM.cpp diff --git a/iokit/Kernel/IONVRAM.cpp b/iokit/Kernel/IONVRAM.cpp index 17cd841bc..94d6b75dd 100644 --- a/iokit/Kernel/IONVRAM.cpp +++ b/iokit/Kernel/IONVRAM.cpp @@ -94,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; @@ -118,7 +118,9 @@ void IODTNVRAM::registerNVRAMController(IONVRAMController *nvram) _nvramController->read(0, _nvramImage, kIODTNVRAMImageSize); initNVRAMImage(); } else { - syncOFVariables(); + IOLockLock(_ofLock); + (void) syncVariables(); + IOLockUnlock(_ofLock); } } @@ -139,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) { @@ -297,7 +301,10 @@ bool IODTNVRAM::serializeProperties(OSSerialize *s) const && (current_task() == kernel_task || mac_iokit_check_nvram_get(kauth_cred_get(), key->getCStringNoCopy()) == 0) #endif ) { } - else dict->removeObject(key); + else { + dict->removeObject(key); + iter->reset(); + } } } @@ -378,14 +385,13 @@ 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; @@ -405,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) { @@ -425,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) { - syncOFVariables(); + 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; } @@ -470,11 +495,12 @@ void IODTNVRAM::removeProperty(const OSSymbol *aKey) if (result) { _ofDict->removeObject(aKey); } - IOLockUnlock(_ofLock); if (result) { - syncOFVariables(); + (void) syncVariables(); } + + IOLockUnlock(_ofLock); } IOReturn IODTNVRAM::setProperties(OSObject *properties) @@ -579,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); @@ -592,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); @@ -606,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); @@ -619,8 +645,8 @@ 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); @@ -733,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))) { @@ -753,6 +778,11 @@ IOReturn IODTNVRAM::initOFVariables(void) } IOReturn IODTNVRAM::syncOFVariables(void) +{ + return kIOReturnUnsupported; +} + +IOReturn IODTNVRAM::syncVariables(void) { bool ok; UInt32 length, maxLength; @@ -760,29 +790,30 @@ IOReturn IODTNVRAM::syncOFVariables(void) const OSSymbol *tmpSymbol; OSObject *tmpObject; OSCollectionIterator *iter; - + + 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) { @@ -791,21 +822,20 @@ IOReturn IODTNVRAM::syncOFVariables(void) } } iter->release(); - IOLockUnlock(_ofLock); - + if (ok) { bcopy(buffer, _ofImage, _ofPartitionSize); } - + IODelete(buffer, UInt8, _ofPartitionSize); - + if (!ok) return kIOReturnBadArgument; - + if (_nvramController != 0) { - _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize); + return _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize); } - - return kIOReturnSuccess; + + return kIOReturnNotReady; } struct OFVariable { @@ -821,6 +851,7 @@ enum { kOWVariableOffsetString = 17 }; +static const OFVariable gOFVariables[] = { {"little-endian?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 0}, {"real-mode?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 1}, @@ -869,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) { @@ -888,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) { @@ -903,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) { @@ -996,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; @@ -1040,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 : @@ -1360,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; @@ -1384,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) { @@ -1414,7 +1457,7 @@ IOReturn IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry, nvPath = 0; nvName = 0; } - + startPtr = wherePtr; } } @@ -1460,22 +1503,39 @@ 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); } - IOLockUnlock(_ofLock); if (data) data->release(); - if (ok) syncOFVariables(); + 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; }