IOHIDSecurePromptClient.cpp [plain text]
#define DEBUG_SECURE_PROMPT 0
#if DEBUG_SECURE_PROMPT
# define DEBUG_ASSERT_PRODUCTION_CODE 0
# define DEBUG_ASSERT_COMPONENT_NAME_STRING "IOHIDSecurePromptClient"
#endif
#include <AssertMacros.h>
#include <IOKit/IOLib.h>
#include <sys/proc.h>
#include <IOKit/IOCommandGate.h>
#include <IOKit/hidsystem/IOHIKeyboardMapper.h>
#include <IOKit/crypto/AppleFDEKeyStore.h>
#include <uuid/uuid.h>
#include "IOHIDSecurePromptClient.h"
static void __EraseData(OSData *target);
static void __EraseDataArray(OSArray *target);
static void __EraseMemory(void *mem, UInt32 size);
static void __InsertBytes(void *dest, UInt32 insertPoint, UInt32 destCount, void *source, UInt32 sourceCount, UInt32 size);
extern unsigned int hid_adb_2_usb_keymap[];
#undef super
#define super IOUserClient
OSDefineMetaClassAndStructors(IOHIDSecurePromptClient, IOUserClient)
typedef struct IOHIDSecurePromptClient_RawKeystrokeData {
UInt8 modifier[4];
UInt8 code[4];
} IOHIDSecurePromptClient_RawKeystrokeData;
#ifndef UTF32Char
typedef UInt32 UTF32Char;
#endif
typedef struct IOHIDSecurePromptClient_KeyqueueMessage {
mach_msg_header_t message;
mach_msg_body_t body;
UInt32 id;
} IOHIDSecurePromptClient_KeyqueueMessage;
typedef struct IOHIDSecurePromptClient_KeyqueueEntry {
UInt16 id;
UInt8 modifier;
UInt8 code;
} IOHIDSecurePromptClient_KeyqueueEntry;
typedef struct IOHIDSecurePromptClient_ExpansionData {
UInt8 gathering; UInt8 dead; UInt8 uuidState; UInt16 nextQueueID; UInt16 insertionPoint; UInt16 stringLength; UInt16 bufferLength; UInt32 layout; OSData *layouts; IONotifier *keyboardNotifier; mach_port_t port; UTF32Char *unicode; IOHIDSecurePromptClient_RawKeystrokeData
*rawKeystrokes; OSArray *messageQueue; uuid_t uuid; IOCommandGate *gate; kbdBitVector keyState; IOByteCount keyStateSize;
} IOHIDSecurePromptClient_ExpansionData;
enum {
kUUIDStateNeverSaved, kUUIDStateIsDirty, kUUIDStateIsClean, kUUIDStateIsGhost };
enum {
kControlModifier = 0x1,
kShiftModifier = 0x2,
kOptionModifier = 0x4,
kCommandModifier = 0x8
};
bool
IOHIDSecurePromptClient::initWithTask(task_t owningTask,
void* security_id,
UInt32 type,
OSDictionary * properties)
{
require(super::initWithTask(owningTask, security_id, type), init_error);
_reserved = (IOHIDSecurePromptClient_ExpansionData*)IOMalloc(sizeof(IOHIDSecurePromptClient_ExpansionData));
require(_reserved, init_error);
bzero(_reserved, sizeof(IOHIDSecurePromptClient_ExpansionData));
require_noerr(ensureBufferSize(32), init_error);
_reserved->messageQueue = OSArray::withCapacity(4);
require(_reserved->messageQueue, init_error);
_reserved->keyStateSize = 4*((NX_NUMKEYCODES+(EVK_BITS_PER_UNIT-1))/EVK_BITS_PER_UNIT);
_reserved->keyState = (kbdBitVector) IOMalloc(_reserved->keyStateSize);
bzero(_reserved->keyState, _reserved->keyStateSize);
require(_reserved->keyState, init_error);
uuid_generate(_reserved->uuid);
#if DEBUG_SECURE_PROMPT
#warning remove
uuid_string_t string;
uuid_unparse(_reserved->uuid, string);
IOLog("%s made UUID %s\n", __func__, string);
#endif
_reserved->uuidState = kUUIDStateNeverSaved;
return super::initWithTask(owningTask, security_id, type, properties);
init_error:
releaseReserved();
return false;
}
bool
IOHIDSecurePromptClient::start(IOService * provider)
{
if (!_reserved->gate) {
IOWorkLoop *loop = provider->getWorkLoop();
require(loop, start_error);
_reserved->gate = IOCommandGate::commandGate(this);
require(_reserved->gate, start_error);
require(kIOReturnSuccess == loop->addEventSource(_reserved->gate), start_error);
}
require(valid(), start_error);
return super::start(provider);
start_error:
return false;
}
void
IOHIDSecurePromptClient::releaseReserved()
{
if (_reserved) {
if (_reserved->gate) {
_reserved->gate->release();
_reserved->gate = NULL;
}
if (_reserved->layouts) {
_reserved->layouts->release();
_reserved->layouts = NULL;
}
ensureBufferSize(0);
if (_reserved->keyboardNotifier) {
_reserved->keyboardNotifier->remove();
_reserved->keyboardNotifier = NULL;
}
if (_reserved->keyState) {
IOFree( _reserved->keyState, _reserved->keyStateSize);
_reserved->keyState = NULL;
_reserved->keyStateSize = 0;
}
IOFree(_reserved, sizeof(IOHIDSecurePromptClient_ExpansionData));
_reserved = NULL;
}
}
void
IOHIDSecurePromptClient::free()
{
sync();
releaseReserved();
super::free();
}
bool
IOHIDSecurePromptClient::gathering()
{
require(valid(), uninitialized_data);
return _reserved->gathering;
uninitialized_data:
return false;
}
bool
IOHIDSecurePromptClient::dead()
{
require(_reserved, uninitialized_data);
return _reserved->dead;
uninitialized_data:
return true;
}
void
IOHIDSecurePromptClient::setNotifier(IONotifier *notifier)
{
require(valid(), exit_early);
if (_reserved->keyboardNotifier)
_reserved->keyboardNotifier->remove();
_reserved->keyboardNotifier = notifier;
if (notifier)
notifier->retain();
exit_early:
;
}
IOReturn
IOHIDSecurePromptClient::postKey(UInt32 key,
bool down)
{
uintptr_t p1 = key;
uintptr_t p2 = down;
require(valid(), uninitialized_data);
return _reserved->gate->runAction(OSMemberFunctionCast(IOCommandGate::Action,
this,
&IOHIDSecurePromptClient::postKeyGated),
(void*)p1, (void*)p2);
uninitialized_data:
return kIOReturnInternalError;
}
IOReturn
IOHIDSecurePromptClient::postKeyGated(void * p1, void * p2, void *, void *)
{
UInt32 key = (uintptr_t)p1;
bool down = (uintptr_t)p2;
bool keep = false;
bool wasDown = false;
UInt8 hidCode = key < 0x80 ? hid_adb_2_usb_keymap[key] : 0xff;
IOReturn result = kIOReturnInternalError;
if (dead()) {
return kIOReturnNotOpen;
}
if (!gathering()) {
return kIOReturnNotReady;
}
require(valid(), finished);
result = kIOReturnBadArgument;
require(key < 0xff, finished);
wasDown = EVK_IS_KEYDOWN(key, _reserved->keyState);
if (down) {
if (!wasDown) {
EVK_KEYDOWN(key, _reserved->keyState);
}
}
else {
if (wasDown) {
EVK_KEYUP(key, _reserved->keyState);
}
result = kIOReturnSuccess;
goto finished;
}
if (modifierDown(kControlModifier | kCommandModifier)) {
goto finished;
}
if ((hidCode >= 0x04) && (hidCode <= 0x27)) keep = true;
if ((hidCode >= 0x2c) && (hidCode <= 0x38)) keep = true;
if ((hidCode >= 0x54) && (hidCode <= 0x63)) keep = true;
if ((hidCode >= 0x85) && (hidCode <= 0x86)) keep = true;
if (keep && down && !wasDown) {
queueMessage(key);
result = kIOReturnSuccess;
}
else {
}
finished:
return result;
}
void
IOHIDSecurePromptClient::queueMessage(UInt8 code)
{
require(valid(), uninitialized_data);
{
UInt8 modifier = modifierState();
UInt16 id = _reserved->nextQueueID++;
IOHIDSecurePromptClient_KeyqueueEntry entry = {
id,
modifier,
code
};
IOHIDSecurePromptClient_KeyqueueMessage msg = {
{
MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,0),
sizeof(IOHIDSecurePromptClient_KeyqueueMessage),
_reserved->port,
MACH_PORT_NULL,
0,
keyMessage
},
{
0
},
id
};
OSData *entryData = OSData::withBytes(&entry, sizeof(entry));
require(entryData, out_of_memory);
_reserved->messageQueue->setObject(entryData);
entryData->release();
kern_return_t ret = mach_msg_send_from_kernel(&msg.message, msg.message.msgh_size);
switch ( ret ) {
case MACH_MSG_SUCCESS:
break;
case MACH_SEND_TIMED_OUT:
IOLog("%s: Unexpected response to mach_msg_send_from_kernel\n", __func__);
break;
default:
IOLog("%s: Very unexpected response to mach_msg_send_from_kernel: 0x%08x\n", __func__, ret);
break;
}
}
out_of_memory:
uninitialized_data:
;
}
IOReturn
IOHIDSecurePromptClient::clientClose()
{
OSIterator *itr = NULL;
require(_reserved, uninitialized_data);
sync();
_reserved->gathering = false;
_reserved->dead = true;
itr = getProviderIterator();
if (itr) {
bool done = false;
while (!done) {
OSObject *provider;
while (!done && (NULL != (provider = itr->getNextObject()))) {
IOService *parent = OSDynamicCast(IOService, provider);
detach(parent);
}
if (itr->isValid()) {
done = true;
}
else {
itr->reset();
}
}
itr->release();
}
uninitialized_data:
return super::clientClose();
}
IOReturn
IOHIDSecurePromptClient::registerNotificationPort(mach_port_t port,
UInt32 type,
io_user_reference_t refCon)
{
require(valid(), uninitialized_data);
if (type == 1) {
_reserved->port = port;
return kIOReturnSuccess;
}
uninitialized_data:
return super::registerNotificationPort(port, type, refCon);
}
IOExternalMethod *
IOHIDSecurePromptClient::getTargetAndMethodForIndex(IOService ** targetP,
UInt32 index)
{
static const IOExternalMethod methodTemplate[] = {
{ NULL, (IOMethod)&IOHIDSecurePromptClient::setGatheringMethod, kIOUCScalarIScalarO, 1, 0 },
{ NULL, (IOMethod)&IOHIDSecurePromptClient::confirmKeyMethod, kIOUCScalarIScalarO, 1, 1 },
{ NULL, (IOMethod)&IOHIDSecurePromptClient::getGatheringMethod, kIOUCScalarIScalarO, 1, 0 },
{ NULL, (IOMethod)&IOHIDSecurePromptClient::deleteKeysMethod, kIOUCScalarIScalarO, 2, 1 },
{ NULL, (IOMethod)&IOHIDSecurePromptClient::getIdentifierMethod, kIOUCScalarIScalarO, 0, 1 },
{ NULL, (IOMethod)&IOHIDSecurePromptClient::compareClientMethod, kIOUCScalarIScalarO, 1, 0 },
{ NULL, (IOMethod)&IOHIDSecurePromptClient::setUUIDMethod, kIOUCStructIStructO, sizeof(uuid_t), 0 },
{ NULL, (IOMethod)&IOHIDSecurePromptClient::getUUIDMethod, kIOUCStructIStructO, 0, sizeof(uuid_t) },
{ NULL, (IOMethod)&IOHIDSecurePromptClient::getInsertionPointMethod, kIOUCScalarIScalarO, 0, 1 },
{ NULL, (IOMethod)&IOHIDSecurePromptClient::setInsertionPointMethod, kIOUCScalarIScalarO, 1, 0 },
{ NULL, (IOMethod)&IOHIDSecurePromptClient::injectStringMethod, kIOUCStructIStructO, kIOUCVariableStructureSize, 0 },
{ NULL, NULL, 0, 0, 0 },
};
require(valid(), uninitialized_data);
require(index < (sizeof(methodTemplate) / sizeof(methodTemplate[0])), bad_argument);
*targetP = this;
return( (IOExternalMethod *)(methodTemplate + index) );
uninitialized_data:
bad_argument:
return NULL;
}
IOReturn
IOHIDSecurePromptClient::setGatheringMethod(void * p1, void * p2 __unused, void * p3 __unused, void * p4 __unused, void * p5 __unused, void * p6 __unused)
{
UInt32 state = (uintptr_t)p1;
return setGathering(state);
}
IOReturn
IOHIDSecurePromptClient::setGathering(UInt32 state)
{
uintptr_t tempState = state ? true : false;
require(valid(), uninitialized_data);
require(_reserved->uuidState != kUUIDStateIsGhost, uninitialized_data);
if (gathering() != tempState) {
_reserved->gathering = tempState;
OSIterator *itr = getProviderIterator();
if (itr) {
bool done = false;
while (!done) {
OSObject *provider;
while (!done && (NULL != (provider = itr->getNextObject()))) {
IOService *parent = OSDynamicCast(IOService, provider);
parent->message(gatheringMessage, this, (void*)tempState);
}
if (itr->isValid()) {
done = true;
}
else {
itr->reset();
}
}
itr->release();
}
}
if (_reserved->messageQueue) {
__EraseDataArray(_reserved->messageQueue);
_reserved->messageQueue->release();
}
_reserved->messageQueue = OSArray::withCapacity(4);
return kIOReturnSuccess;
uninitialized_data:
return kIOReturnNotOpen;
}
IOReturn
IOHIDSecurePromptClient::confirmKeyMethod(void * p1, void * p2, void * p3, void * p4, void * p5 __unused, void * p6 __unused)
{
require(valid(), uninitialized_data);
return _reserved->gate->runAction(OSMemberFunctionCast(IOCommandGate::Action,
this,
&IOHIDSecurePromptClient::confirmKeyGated),
p1, p2, p3, p4);
uninitialized_data:
return kIOReturnInternalError;
}
IOReturn
IOHIDSecurePromptClient::confirmKeyGated(void * p1, void * p2, void * , void * )
{
UInt32 id = (uintptr_t)p1;
return confirmKey(id, (UInt32*)p2);
}
IOReturn
IOHIDSecurePromptClient::confirmKey(UInt32 id,
UInt32 *count)
{
unsigned int index = 0;
IOReturn result = kIOReturnBadArgument;
OSCollectionIterator *iterator = NULL;
require(valid(), uninitialized_data);
require(_reserved->uuidState != kUUIDStateIsGhost, uninitialized_data);
result = kIOReturnInternalError;
require(count, invalid_argument);
result = kIOReturnBadMessageID;
iterator = OSCollectionIterator::withCollection(_reserved->messageQueue);
require(iterator, finished);
do {
OSObject * obj = iterator->getNextObject();
if (!obj) {
if (iterator->isValid()) {
goto finished;
}
else {
iterator->reset();
}
}
else {
OSData *entryData = OSDynamicCast(OSData, obj);
IOHIDSecurePromptClient_KeyqueueEntry *entry = NULL;
if (entryData == NULL) {
IOLog("%s: Found bad index in messageQueue: %d\n", __func__, index);
continue;
}
entry = (IOHIDSecurePromptClient_KeyqueueEntry*)entryData->getBytesNoCopy();
if (entry->id == id) {
result = appendConfirmedKeyCode(entry->modifier, entry->code);
__EraseData(entryData);
_reserved->messageQueue->removeObject(index);
*count = _reserved->stringLength;
goto finished;
}
}
}
while (true);
finished:
invalid_argument:
uninitialized_data:
if (iterator)
iterator->release();
return result;
}
IOReturn
IOHIDSecurePromptClient::appendConfirmedKeyCode(UInt8 modifier,
UInt8 code)
{
IOReturn result = kIOReturnInternalError;
UInt8 newCode = code ? code : 0xff;
IOHIDSecurePromptClient_RawKeystrokeData newKeystroke = {{ modifier }, { newCode }};
UTF32Char newUnicode = (modifier << 16) | newCode;
require(valid(), exit_early);
if (_reserved->uuidState == kUUIDStateIsClean)
_reserved->uuidState = kUUIDStateIsDirty;
{
result = kIOReturnNoMemory;
require_noerr(ensureBufferSize(_reserved->stringLength + 1), exit_early);
__InsertBytes(_reserved->unicode, _reserved->insertionPoint, _reserved->stringLength, &newUnicode, 1, sizeof(newUnicode));
__InsertBytes(_reserved->rawKeystrokes, _reserved->insertionPoint, _reserved->stringLength, &newKeystroke, 1, sizeof(newKeystroke));
__EraseMemory(&newKeystroke, sizeof(newKeystroke));
__EraseMemory(&newUnicode, sizeof(newUnicode));
_reserved->insertionPoint++;
_reserved->stringLength++;
}
result = kIOReturnSuccess;
exit_early:
return result;
}
IOReturn
IOHIDSecurePromptClient::deleteKeysMethod(void * p1, void * p2, void * p3, void * p4, void * p5 __unused, void * p6 __unused)
{
require(valid(), uninitialized_data);
return _reserved->gate->runAction(OSMemberFunctionCast(IOCommandGate::Action,
this,
&IOHIDSecurePromptClient::deleteKeysGated),
p1, p2, p3, p4);
uninitialized_data:
return kIOReturnInternalError;
}
IOReturn
IOHIDSecurePromptClient::deleteKeysGated(void * p1, void * p2, void * p3, void * p4 __unused)
{
UInt32 length;
IOReturn result;
require(p3, invalid_argument);
result = deleteKeys((intptr_t)p1, (uintptr_t)p2, &length);
*(UInt64*)p3 = length;
return result;
invalid_argument:
return kIOReturnBadArgument;
}
IOReturn
IOHIDSecurePromptClient::deleteKeys(SInt32 index,
UInt32 count,
UInt32 *newLength)
{
require(valid(), uninitialized_data);
require(_reserved->uuidState != kUUIDStateIsGhost, uninitialized_data);
{
SInt32 deleteBegin = index;
*newLength = _reserved->stringLength;
if ((count == 0) || (_reserved->stringLength == 0)) {
return kIOReturnSuccess;
}
if (deleteBegin < 0) {
deleteBegin = _reserved->stringLength - count;
if (deleteBegin < 0)
deleteBegin = 0;
}
require(_reserved->stringLength > (unsigned)deleteBegin, overrun);
if (((SInt64)count) > _reserved->stringLength - deleteBegin) {
count = _reserved->stringLength - deleteBegin;
}
memmove(_reserved->unicode + deleteBegin,
_reserved->unicode + (deleteBegin + count),
(_reserved->stringLength - deleteBegin - count) * sizeof(UTF32Char));
memmove(_reserved->rawKeystrokes + deleteBegin,
_reserved->rawKeystrokes + (deleteBegin + count),
(_reserved->stringLength - deleteBegin - count) * sizeof(IOHIDSecurePromptClient_RawKeystrokeData));
if (_reserved->uuidState == kUUIDStateIsClean)
_reserved->uuidState = kUUIDStateIsDirty;
_reserved->stringLength -= count;
*newLength = _reserved->stringLength;
if (_reserved->insertionPoint > index) {
_reserved->insertionPoint -= count;
if (_reserved->insertionPoint < index) {
_reserved->insertionPoint = index;
}
}
return kIOReturnSuccess;
}
uninitialized_data:
return kIOReturnInternalError;
overrun:
return kIOReturnOverrun;
}
bool
IOHIDSecurePromptClient::valid()
{
require(_reserved, invalid);
nrequire(_reserved->dead, invalid);
require(_reserved->unicode, invalid);
require(_reserved->rawKeystrokes, invalid);
require(_reserved->messageQueue, invalid);
require(_reserved->gate, invalid);
require(_reserved->keyState, invalid);
require(_reserved->insertionPoint <= _reserved->stringLength, invalid);
return true;
invalid:
return false;
}
#define CONTROL_DOWN(X) (EVK_IS_KEYDOWN(0x3b, X) || EVK_IS_KEYDOWN(0x3e, X)) // ADB Control keys
#define SHIFT_DOWN(X) (EVK_IS_KEYDOWN(0x38, X) || EVK_IS_KEYDOWN(0x3c, X)) // ADB Shift keys
#define OPTION_DOWN(X) (EVK_IS_KEYDOWN(0x3a, X) || EVK_IS_KEYDOWN(0x3d, X)) // ADB Alt keys
#define COMMAND_DOWN(X) (EVK_IS_KEYDOWN(0x37, X) || EVK_IS_KEYDOWN(0x36, X)) // ADB GUI keys
UInt8
IOHIDSecurePromptClient::modifierState()
{
UInt8 result = (CONTROL_DOWN(_reserved->keyState) ? kControlModifier : 0) |
(SHIFT_DOWN(_reserved->keyState) ? kShiftModifier : 0) |
(OPTION_DOWN(_reserved->keyState) ? kOptionModifier : 0) |
(COMMAND_DOWN(_reserved->keyState) ? kCommandModifier : 0);
return result;
}
bool
IOHIDSecurePromptClient::modifierDown(UInt8 modifierFlag)
{
bool result = (modifierState() & modifierFlag) ? true : false;
return result;
}
IOReturn
IOHIDSecurePromptClient::getIdentifierMethod(void * p1, void * p2 __unused, void * p3 __unused, void * p4 __unused, void * p5 __unused, void * p6 __unused)
{
require(valid() && p1, uninitialized_data);
*(UInt64*)p1 = identifier();
return kIOReturnSuccess;
uninitialized_data:
return kIOReturnInternalError;
}
uint64_t
IOHIDSecurePromptClient::identifier()
{
uint64_t result = 0xffffffff & (uint64_t)this;
return result;
}
IOReturn
IOHIDSecurePromptClient::compareClientMethod(void * p1, void *, void *, void *, void *, void *)
{
OSData *tempData = NULL;
IOReturn result = kIOReturnInternalError;
uint64_t targetID = (uintptr_t)p1;
OSIterator *siblings = NULL;
IORegistryEntry *parent = NULL;
IOHIDSecurePromptClient *target = NULL;
uuid_t targetUUID;
uuid_t selfUUID;
UInt8 *targetBuffer = NULL;
UInt8 *selfBuffer = NULL;
uint32_t targetBufferSize;
uint32_t selfBufferSize;
require(valid(), uninitialized_data);
require(AppleFDEKeyStore::instance, uninitialized_data);
parent = getParentEntry(gIOServicePlane);
require(parent, no_siblings);
siblings = parent->getChildIterator(gIOServicePlane);
require(siblings, no_siblings);
while(NULL != (target = nextForIterator(siblings))) {
if (target->identifier() == targetID)
break;
}
require(target, no_target);
require(target->valid(), no_target);
result = target->getUUIDMethod(targetUUID, NULL, NULL, NULL, NULL, NULL);
require(result == kIOReturnSuccess, no_target);
result = getUUIDMethod(selfUUID, NULL, NULL, NULL, NULL, NULL);
require(result == kIOReturnSuccess, no_target);
sync();
target->sync();
#if DEBUG_SECURE_PROMPT
#warning remove
uuid_string_t string;
uuid_unparse(selfUUID, string);
IOLog("%s of UUID %s to", __func__, string);
uuid_unparse(targetUUID, string);
IOLog(" UUID %s", string);
#endif
targetBuffer = (UInt8*)IOMalloc(AKS_MAX_PASSPHRASE_SIZE);
selfBuffer = (UInt8*)IOMalloc(AKS_MAX_PASSPHRASE_SIZE);
require(targetBuffer && selfBuffer, out_of_memory);
targetBufferSize = AKS_MAX_PASSPHRASE_SIZE;
result = AppleFDEKeyStore::instance->getPassphrase(targetUUID, targetBuffer, targetBufferSize, &targetBufferSize);
require(result == kIOReturnSuccess, keystore_error);
selfBufferSize = AKS_MAX_PASSPHRASE_SIZE;
result = AppleFDEKeyStore::instance->getPassphrase(selfUUID, selfBuffer, selfBufferSize, &selfBufferSize);
require(result == kIOReturnSuccess, keystore_error);
if ((targetBufferSize == selfBufferSize) && (0 == memcmp(targetBuffer, selfBuffer, targetBufferSize))) {
goto success;
}
result = kIOReturnNotPrivileged;
success:
keystore_error:
out_of_memory:
if (targetBuffer) {
__EraseMemory(targetBuffer, AKS_MAX_PASSPHRASE_SIZE);
IOFree(targetBuffer, AKS_MAX_PASSPHRASE_SIZE);
}
if (selfBuffer) {
__EraseMemory(selfBuffer, AKS_MAX_PASSPHRASE_SIZE);
IOFree(selfBuffer, AKS_MAX_PASSPHRASE_SIZE);
}
no_target:
if (siblings) {
siblings->release();
}
no_siblings:
if (tempData) {
__EraseData(tempData);
tempData->release();
}
uninitialized_data:
return result;
}
IOReturn
IOHIDSecurePromptClient::getUUIDMethod(void * p1, void * p2 __unused, void * p3 __unused, void * p4 __unused, void * p5 __unused, void * p6 __unused)
{
return _reserved->gate->runAction(OSMemberFunctionCast(IOCommandGate::Action,
this,
&IOHIDSecurePromptClient::getUUIDGated),
p1, p2, p3, p4);
}
IOReturn
IOHIDSecurePromptClient::getUUIDGated(void * p1, void * p2 __unused, void * p3 __unused, void * p4 __unused)
{
UInt8 *data = (UInt8*)p1;
require(valid(), uninitialized_data);
require(p1, uninitialized_data);
if (_reserved->uuidState == kUUIDStateNeverSaved)
_reserved->uuidState = kUUIDStateIsDirty;
bcopy(_reserved->uuid, data, sizeof(uuid_t));
return kIOReturnSuccess;
uninitialized_data:
return kIOReturnInternalError;
}
IOReturn
IOHIDSecurePromptClient::setUUIDMethod(void * p1, void * p2, void * p3, void * p4, void * p5 __unused, void * p6 __unused)
{
return _reserved->gate->runAction(OSMemberFunctionCast(IOCommandGate::Action,
this,
&IOHIDSecurePromptClient::setUUIDGated),
p1, p2, p3, p4);
}
IOReturn
IOHIDSecurePromptClient::setUUIDGated(void * p1, void * p2 __unused, void * p3 __unused,void * p4 __unused)
{
require(valid(), uninitialized_data);
require(p1, uninitialized_data);
return setUUID((UInt8*)p1);
uninitialized_data:
return kIOReturnInternalError;
}
IOReturn
IOHIDSecurePromptClient::setUUID(UInt8* bytes_in)
{
IOReturn result = kIOReturnNoMemory;
uint32_t bufferSize = AKS_MAX_PASSPHRASE_SIZE;
bcopy(bytes_in, _reserved->uuid, sizeof(uuid_t));
#if DEBUG_SECURE_PROMPT
#warning remove
uuid_string_t string;
uuid_unparse(_reserved->uuid, string);
IOLog("%s set UUID to %s\n", __func__, string);
#endif
if (_reserved->uuidState != kUUIDStateIsGhost) {
setGathering(0);
_reserved->uuidState = kUUIDStateIsGhost;
}
UInt8 *buffer = (UInt8*)IOMalloc(AKS_MAX_PASSPHRASE_SIZE);
require(buffer, out_of_memory);
bufferSize = AKS_MAX_PASSPHRASE_SIZE;
result = AppleFDEKeyStore::instance->getPassphrase(_reserved->uuid, buffer, bufferSize, &bufferSize);
require(result == kIOReturnSuccess, bad_uuid);
bad_uuid:
out_of_memory:
if (buffer) {
__EraseMemory(buffer, AKS_MAX_PASSPHRASE_SIZE);
IOFree(buffer, AKS_MAX_PASSPHRASE_SIZE);
}
return result;
}
IOReturn
IOHIDSecurePromptClient::getInsertionPointMethod(void * p1, void *, void *, void *, void *, void *)
{
require(valid() && p1, uninitialized_data);
*(uint64_t*)p1 = getInsertionPoint();
return kIOReturnSuccess;
uninitialized_data:
return kIOReturnInternalError;
}
uint64_t
IOHIDSecurePromptClient::getInsertionPoint()
{
return _reserved->insertionPoint;
}
IOReturn
IOHIDSecurePromptClient::setInsertionPointMethod(void * p1, void * p2, void * p3,
void * p4, void * p5 __unused, void * p6 __unused)
{
return _reserved->gate->runAction(OSMemberFunctionCast(IOCommandGate::Action,
this,
&IOHIDSecurePromptClient::setInsertionPointGated),
p1, p2, p3, p4);
}
IOReturn
IOHIDSecurePromptClient::setInsertionPointGated(void * p1, void * p2 __unused, void * p3 __unused,void * p4 __unused)
{
IOReturn result = kIOReturnBadArgument;
uintptr_t value = (uintptr_t)p1;
require(valid(), bad_argument);
require(value < 0x0fff, bad_argument);
if (value == 0) {
_reserved->insertionPoint = 0;
}
else {
if (value >= _reserved->stringLength) {
_reserved->insertionPoint = _reserved->stringLength;
}
else {
_reserved->insertionPoint = value;
}
}
result = kIOReturnSuccess;
bad_argument:
return result;
}
IOReturn
IOHIDSecurePromptClient::injectStringMethod(void * p1, void * p2, void * p3,
void * p4, void * p5 __unused, void * p6 __unused)
{
return _reserved->gate->runAction(OSMemberFunctionCast(IOCommandGate::Action,
this,
&IOHIDSecurePromptClient::injectStringGated),
p1, p2, p3, p4);
}
IOReturn
IOHIDSecurePromptClient::injectStringGated(void * p1, void * p2, void * p3 __unused,void * p4 __unused)
{
IOReturn result = kIOReturnBadArgument;
IOHIDSecurePromptClient_RawKeystrokeData * dummyRawData = NULL;
UTF32Char *string = (UTF32Char*)p1;
intptr_t length = (intptr_t)p2 / sizeof(UTF32Char);
vm_size_t dummyDataSize = length * sizeof(IOHIDSecurePromptClient_RawKeystrokeData);
require(valid(), bad_argument);
require(p1, bad_argument);
require((length > 0) && (length < 0x0fff), bad_argument);
dummyRawData = (IOHIDSecurePromptClient_RawKeystrokeData*)IOMalloc(dummyDataSize);
memset(dummyRawData, 0xff, dummyDataSize);
__InsertBytes(_reserved->rawKeystrokes, _reserved->insertionPoint, _reserved->stringLength, string, length, sizeof(UTF32Char));
__InsertBytes(_reserved->unicode, _reserved->insertionPoint, _reserved->stringLength, dummyRawData, length, sizeof(UTF32Char));
__EraseMemory(string, length * sizeof(UTF32Char));
_reserved->insertionPoint += length;
result = kIOReturnSuccess;
bad_argument:
if (dummyRawData)
IOFree(dummyRawData, dummyDataSize);
return result;
}
IOReturn
IOHIDSecurePromptClient::getGatheringMethod(void * p1, void * p2 __unused, void * p3 __unused, void * p4 __unused, void * p5 __unused, void * p6 __unused)
{
require(valid(), uninitialized_data);
require(p1, uninitialized_data);
*(UInt64*)p1 = gathering();
return kIOReturnSuccess;
uninitialized_data:
*(UInt64*)p1 = false;
return kIOReturnInternalError;
}
void
IOHIDSecurePromptClient::sync()
{
if (_reserved && _reserved->gate && !_reserved->dead)
_reserved->gate->runAction(OSMemberFunctionCast(IOCommandGate::Action,
this,
&IOHIDSecurePromptClient::syncGated),
0, 0, 0, 0);
}
IOReturn
IOHIDSecurePromptClient::syncGated(void * p1 __unused, void * p2 __unused, void * p3 __unused,void * p4 __unused)
{
if (_reserved && (_reserved->uuidState == kUUIDStateIsDirty) && valid()) {
IOReturn result;
AppleFDEKeyStore::instance->deletePassphrase(_reserved->uuid);
if (_reserved->stringLength > 0) {
result = AppleFDEKeyStore::instance->setPassphrase(_reserved->uuid,
_reserved->unicode,
_reserved->stringLength * sizeof(UTF32Char));
if (result != kIOReturnSuccess)
IOLog("%s failed to setPassphrase for code: %08x\n", __func__, result);
}
_reserved->uuidState = kUUIDStateIsClean;
#if DEBUG_SECURE_PROMPT
#warning remove
uuid_string_t string;
uuid_unparse(_reserved->uuid, string);
IOLog("%s on %s\n", __func__, string);
#endif
}
return kIOReturnSuccess;
}
IOHIDSecurePromptClient*
IOHIDSecurePromptClient::nextForIterator(OSIterator * iterator)
{
IOHIDSecurePromptClient *client = NULL;
do {
OSObject * obj = iterator->getNextObject();
if (!obj) {
if (iterator->isValid()) {
return NULL;
}
else {
iterator->reset();
}
}
else {
client = OSDynamicCast(IOHIDSecurePromptClient, obj);
}
}
while (!client);
return client;
}
void
__EraseData(OSData *target)
{
if (target) {
unsigned int size = target->getLength();
if (size) {
void *bytes = (void*)target->getBytesNoCopy();
__EraseMemory(bytes, size);
}
}
}
void
__EraseMemory(void *mem, UInt32 size)
{
if (mem) {
memset(mem, 0xFF, size);
memset(mem, 0x00, size);
}
}
void __EraseDataArray(OSArray *target)
{
OSCollectionIterator *iterator = NULL;
require(target, finished);
iterator = OSCollectionIterator::withCollection(target);
require(iterator, finished);
do {
OSObject * obj = iterator->getNextObject();
if (!obj) {
if (iterator->isValid()) {
goto finished;
}
else {
iterator->reset();
}
}
else {
OSData *dict = OSDynamicCast(OSData, obj);
__EraseData(dict);
}
}
while (true);
finished:
if (iterator)
iterator->release();
}
IOReturn
IOHIDSecurePromptClient::ensureBufferSize(UInt32 size)
{
IOReturn result = kIOReturnSuccess;
UInt8 *oldBuffer = NULL;
UInt32 oldBufferSize = 0;
UInt8 *newBuffer = NULL;
UInt8 *newKeystrokeOffset;
UInt32 newBufferSize = 0;
UInt32 newSize = size;
if (_reserved->bufferLength >= size)
goto finished;
if (!size) {
oldBuffer = (UInt8*)_reserved->unicode;
oldBufferSize = _reserved->bufferLength * (sizeof(UTF32Char) + sizeof(IOHIDSecurePromptClient_RawKeystrokeData));
goto finished;
}
newSize--;
newSize |= newSize >> 1;
newSize |= newSize >> 2;
newSize |= newSize >> 4;
newSize |= newSize >> 8;
newSize |= newSize >> 16;
newSize++;
result = kIOReturnNoMemory;
require(newSize < 1024, finished);
newBufferSize = newSize * (sizeof(UTF32Char) + sizeof(IOHIDSecurePromptClient_RawKeystrokeData));
newBuffer = (UInt8*)IOMalloc(newBufferSize);
require(newBuffer, finished);
newKeystrokeOffset = newBuffer + newSize * sizeof(UTF32Char);
memcpy(newBuffer, _reserved->unicode, _reserved->stringLength * sizeof(UTF32Char));
memcpy(newKeystrokeOffset, _reserved->rawKeystrokes, _reserved->stringLength * sizeof(IOHIDSecurePromptClient_RawKeystrokeData));
oldBuffer = (UInt8*)_reserved->unicode;
oldBufferSize = _reserved->bufferLength * (sizeof(UTF32Char) + sizeof(IOHIDSecurePromptClient_RawKeystrokeData));
_reserved->unicode = (UTF32Char*)newBuffer;
_reserved->rawKeystrokes = (IOHIDSecurePromptClient_RawKeystrokeData*)newKeystrokeOffset;
_reserved->bufferLength = newSize;
newBuffer = NULL;
result = kIOReturnSuccess;
finished:
if (newBuffer)
IOFree(newBuffer, newBufferSize);
if (oldBuffer) {
__EraseMemory(oldBuffer, oldBufferSize);
IOFree(oldBuffer, oldBufferSize);
}
return result;
}
void
__InsertBytes(void *dest, UInt32 insertPoint, UInt32 destCount, void *source, UInt32 sourceCount, UInt32 size)
{
UInt8 *destBytes = (UInt8*)dest;
UInt8 *sourceBytes = (UInt8*)source;
require(destBytes && sourceBytes && sourceCount && size, bad_parameter);
if (insertPoint > destCount) {
insertPoint = destCount;
}
if (insertPoint < destCount) {
memmove(destBytes + (insertPoint + sourceCount) * size, destBytes + insertPoint * size, sourceCount * size);
}
memcpy(destBytes + insertPoint * size, sourceBytes, sourceCount * size);
bad_parameter:
;
}