Loading...
iokit/Kernel/RootDomainUserClient.cpp xnu-10063.141.1 xnu-12377.121.6
--- xnu/xnu-10063.141.1/iokit/Kernel/RootDomainUserClient.cpp
+++ xnu/xnu-12377.121.6/iokit/Kernel/RootDomainUserClient.cpp
@@ -34,6 +34,8 @@
 #include <IOKit/IOLib.h>
 #include <IOKit/IOKitKeys.h>
 #include <IOKit/IOBufferMemoryDescriptor.h>
+#include <IOKit/IOSubMemoryDescriptor.h>
+#include <AssertMacros.h>
 #include "RootDomainUserClient.h"
 #include <IOKit/pwr_mgt/IOPMLibDefs.h>
 #include <IOKit/pwr_mgt/IOPMPrivate.h>
@@ -224,9 +226,92 @@
 }
 
 IOReturn
+RootDomainUserClient::secureAttemptIdleSleepAbort(
+	uint32_t    *outReverted)
+{
+	int                     admin_priv = 0;
+	IOReturn                ret;
+
+	ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator);
+	admin_priv = (kIOReturnSuccess == ret);
+
+	if (admin_priv && fOwner) {
+		*outReverted = (uint32_t) fOwner->attemptIdleSleepAbort();
+	} else {
+		ret = kIOReturnNotPrivileged;
+	}
+	return ret;
+}
+
+IOReturn
+RootDomainUserClient::secureSetLockdownModeHibernation(
+	uint32_t status)
+{
+#if HIBERNATION
+	int                     admin_priv = 0;
+	IOReturn                ret;
+
+	ret = clientHasPrivilege(fOwningTask, kIOClientPrivilegeAdministrator);
+	admin_priv = (kIOReturnSuccess == ret);
+
+	if (admin_priv && fOwner) {
+		fOwner->setLockdownModeHibernation(status);
+	} else {
+		ret = kIOReturnNotPrivileged;
+	}
+	return kIOReturnSuccess;
+#else
+	return kIOReturnError;
+#endif
+}
+
+IOReturn
+RootDomainUserClient::secureGetAssertionLog(
+	IOPMAssertionLogData *outLog)
+{
+	if (!fOwner) {
+		return kIOReturnError;
+	}
+
+	return fOwner->getAssertionLog(outLog);
+}
+
+IOReturn
+RootDomainUserClient::secureSetAssertionLogNotificationThreshold(
+	uint64_t threshold)
+{
+	if (!fOwner) {
+		return kIOReturnError;
+	}
+
+	return fOwner->setAssertionLogNotificationThreshold(threshold);
+}
+
+IOReturn
+RootDomainUserClient::secureSetAssertionLogNotificationPort(
+	mach_port_t port)
+{
+	if (!fOwner) {
+		return kIOReturnError;
+	}
+
+	IOReturn ret = fOwner->setAssertionLogNotificationPort(port);
+
+	if (ret == kIOReturnSuccess) {
+		fAssertionLogNotificationPortRegistered = (port != MACH_PORT_NULL);
+	}
+
+	return ret;
+}
+
+IOReturn
 RootDomainUserClient::clientClose( void )
 {
 	terminate();
+
+	if (fAssertionLogNotificationPortRegistered) {
+		secureSetAssertionLogNotificationPort(MACH_PORT_NULL);
+	}
 
 	return kIOReturnSuccess;
 }
@@ -243,6 +328,17 @@
 }
 
 IOReturn
+RootDomainUserClient::registerNotificationPort(mach_port_t port, UInt32 type, UInt32 refCon)
+{
+	switch ((IOPMUserClientNotificationType)type) {
+	case IOPMUserClientNotificationType_AssertionLog:
+		return secureSetAssertionLogNotificationPort(port);
+	}
+
+	return kIOReturnSuccess;
+}
+
+IOReturn
 RootDomainUserClient::externalMethod(uint32_t selector, IOExternalMethodArgumentsOpaque * args )
 {
 	static const IOExternalMethodDispatch2022 dispatchArray[] = {
@@ -390,6 +486,42 @@
 			.allowAsync               = false,
 			.checkEntitlement         = NULL,
 		},
+		[kPMRequestIdleSleepRevert] = {
+			.function                 = &RootDomainUserClient::externalMethodDispatched,
+			.checkScalarInputCount    = 0,
+			.checkStructureInputSize  = 0,
+			.checkScalarOutputCount   = 1,
+			.checkStructureOutputSize = 0,
+			.allowAsync               = false,
+			.checkEntitlement         = NULL,
+		},
+		[kPMSetLDMHibernationDisable] = {
+			.function                 = &RootDomainUserClient::externalMethodDispatched,
+			.checkScalarInputCount    = 1,
+			.checkStructureInputSize  = 0,
+			.checkScalarOutputCount   = 0,
+			.checkStructureOutputSize = 0,
+			.allowAsync               = false,
+			.checkEntitlement         = NULL,
+		},
+		[kPMGetAssertionLog] = {
+			.function                 = &RootDomainUserClient::externalMethodDispatched,
+			.checkScalarInputCount    = 0,
+			.checkStructureInputSize  = 0,
+			.checkScalarOutputCount   = 0,
+			.checkStructureOutputSize = sizeof(IOPMAssertionLogData),
+			.allowAsync               = false,
+			.checkEntitlement         = NULL,
+		},
+		[kPMSetAssertionLogThreshold] = {
+			.function                 = &RootDomainUserClient::externalMethodDispatched,
+			.checkScalarInputCount    = 1,
+			.checkStructureInputSize  = 0,
+			.checkScalarOutputCount   = 0,
+			.checkStructureOutputSize = 0,
+			.allowAsync               = false,
+			.checkEntitlement         = NULL,
+		},
 	};
 
 	return dispatchExternalMethod(selector, args, dispatchArray, sizeof(dispatchArray) / sizeof(dispatchArray[0]), this, NULL);
@@ -397,8 +529,24 @@
 IOReturn
 RootDomainUserClient::externalMethodDispatched(OSObject * target, void * reference, IOExternalMethodArguments * arguments)
 {
-	IOReturn    ret = kIOReturnBadArgument;
-	RootDomainUserClient * me = (typeof(me))target;
+	IOReturn              ret = kIOReturnBadArgument;
+	RootDomainUserClient *me = (typeof(me))target;
+	IOMemoryDescriptor   *outMD = nullptr;
+	IOMemoryMap          *outMap = nullptr;
+
+	if (arguments->structureOutputSize > 0 || arguments->structureOutputDescriptorSize > 0) {
+		if (arguments->structureOutputDescriptor) {
+			outMD = arguments->structureOutputDescriptor;
+			outMD->retain();
+		} else {
+			outMD = IOMemoryDescriptor::withAddressRange((mach_vm_address_t)arguments->structureOutput, arguments->structureOutputSize, kIODirectionIn, kernel_task);
+		}
+
+		require_action(outMD != nullptr, out, ret = kIOReturnError);
+		outMap = outMD->map();
+		require_action(outMap != nullptr, out, ret = kIOReturnError);
+	}
+
 	switch (arguments->selector) {
 	case kPMSetAggressiveness:
 		ret = me->secureSetAggressiveness(
@@ -484,7 +632,6 @@
 		}
 		break;
 
-
 	case kPMSleepWakeDebugTrig:
 		ret = clientHasPrivilege(me->fOwningTask, kIOClientPrivilegeAdministrator);
 		if (ret == kIOReturnSuccess) {
@@ -500,10 +647,37 @@
 		}
 		break;
 
+	case kPMRequestIdleSleepRevert:
+		ret = me->secureAttemptIdleSleepAbort(
+			(uint32_t *) &arguments->scalarOutput[0]);
+		break;
+
+	case kPMSetLDMHibernationDisable:
+		ret = me->secureSetLockdownModeHibernation((uint32_t)arguments->scalarInput[0]);
+		break;
+
+	case kPMGetAssertionLog:
+		require_action(outMap != nullptr, out, ret = kIOReturnBadArgument);
+		ret = me->secureGetAssertionLog((IOPMAssertionLogData *)outMap->getAddress());
+		break;
+
+	case kPMSetAssertionLogThreshold:
+		ret = me->secureSetAssertionLogNotificationThreshold(arguments->scalarInput[0]);
+		break;
+
 	default:
 		// bad selector
-		return kIOReturnBadArgument;
-	}
+		ret = kIOReturnBadArgument;
+		break;
+	}
+
+out:
+	if (outMap) {
+		outMap->unmap();
+	}
+
+	OSSafeReleaseNULL(outMap);
+	OSSafeReleaseNULL(outMD);
 
 	return ret;
 }