diff --git a/kernel/objects.cpp b/kernel/objects.cpp index a701ed3..6f5016e 100644 --- a/kernel/objects.cpp +++ b/kernel/objects.cpp @@ -79,63 +79,22 @@ struct HandleTable { bool CloseHandle(EsHandle handle); void ModifyFlags(EsHandle handle, uint32_t newFlags); - // Resolve the handle if it is valid and return the type in type. + // Resolve the handle if it is valid. // The initial value of type is used as a mask of expected object types for the handle. - void ResolveHandle(struct KObject *object, EsHandle handle); +#define RESOLVE_HANDLE_FAILED (0) +#define RESOLVE_HANDLE_NO_CLOSE (1) +#define RESOLVE_HANDLE_NORMAL (2) + uint8_t ResolveHandle(Handle *outHandle, EsHandle inHandle, KernelObjectType typeMask); void Destroy(); }; -struct KObject { - void Initialise(HandleTable *handleTable, EsHandle _handle, KernelObjectType _type); - - KObject() { EsMemoryZero(this, sizeof(*this)); } - KObject(Process *process, EsHandle _handle, KernelObjectType _type); - KObject(HandleTable *handleTable, EsHandle _handle, KernelObjectType _type); - - ~KObject() { - if (!checked && valid) { - KernelPanic("KObject - Object not checked!\n"); - } - - if (parentObject && close) { - CloseHandleToObject(parentObject, parentType, parentFlags); - } - } - - void *object, *parentObject; - uint32_t flags, parentFlags; - KernelObjectType type, parentType; - bool valid, checked, close, softFailure; -}; - void InitialiseObjectManager(); #endif #ifdef IMPLEMENTATION -KObject::KObject(Process *process, EsHandle _handle, KernelObjectType _type) { - EsMemoryZero(this, sizeof(*this)); - Initialise(&process->handleTable, _handle, _type); -} - -KObject::KObject(HandleTable *handleTable, EsHandle _handle, KernelObjectType _type) { - EsMemoryZero(this, sizeof(*this)); - Initialise(handleTable, _handle, _type); -} - -void KObject::Initialise(HandleTable *handleTable, EsHandle _handle, KernelObjectType _type) { - type = _type; - - handleTable->ResolveHandle(this, _handle); - parentObject = object, parentType = type, parentFlags = flags; - - if (!valid) { - KernelLog(LOG_ERROR, "Object Manager", "invalid handle", "KObject::Initialise - Invalid handle %d for type mask %x.\n", _handle, _type); - } -} - // A lock used to change the handle count on several objects. // TODO Make changing handle count lockless wherever possible? KMutex objectHandleCountChange; @@ -462,43 +421,48 @@ void HandleTable::ModifyFlags(EsHandle handle, uint32_t newFlags) { _handle->flags = newFlags; } -void HandleTable::ResolveHandle(KObject *object, EsHandle handle) { - KernelObjectType requestedType = object->type; - object->type = COULD_NOT_RESOLVE_HANDLE; - +uint8_t HandleTable::ResolveHandle(Handle *outHandle, EsHandle inHandle, KernelObjectType typeMask) { // Special handles. - if (handle == ES_CURRENT_THREAD && (requestedType & KERNEL_OBJECT_THREAD)) { - object->type = KERNEL_OBJECT_THREAD, object->valid = true, object->object = GetCurrentThread(); - return; - } else if (handle == ES_CURRENT_PROCESS && (requestedType & KERNEL_OBJECT_PROCESS)) { - object->type = KERNEL_OBJECT_PROCESS, object->valid = true, object->object = GetCurrentThread()->process; - return; - } else if (handle == ES_INVALID_HANDLE && (requestedType & KERNEL_OBJECT_NONE)) { - object->type = KERNEL_OBJECT_NONE, object->valid = true; - return; + if (inHandle == ES_CURRENT_THREAD && (typeMask & KERNEL_OBJECT_THREAD)) { + outHandle->type = KERNEL_OBJECT_THREAD; + outHandle->object = GetCurrentThread(); + outHandle->flags = 0; + return RESOLVE_HANDLE_NO_CLOSE; + } else if (inHandle == ES_CURRENT_PROCESS && (typeMask & KERNEL_OBJECT_PROCESS)) { + outHandle->type = KERNEL_OBJECT_PROCESS; + outHandle->object = GetCurrentThread()->process; + outHandle->flags = 0; + return RESOLVE_HANDLE_NO_CLOSE; + } else if (inHandle == ES_INVALID_HANDLE && (typeMask & KERNEL_OBJECT_NONE)) { + outHandle->type = KERNEL_OBJECT_NONE; + outHandle->object = nullptr; + outHandle->flags = 0; + return RESOLVE_HANDLE_NO_CLOSE; } // Check that the handle is within the correct bounds. - if ((!handle) || handle >= HANDLE_TABLE_L1_ENTRIES * HANDLE_TABLE_L2_ENTRIES) { - return; + if ((!inHandle) || inHandle >= HANDLE_TABLE_L1_ENTRIES * HANDLE_TABLE_L2_ENTRIES) { + return RESOLVE_HANDLE_FAILED; } KMutexAcquire(&lock); EsDefer(KMutexRelease(&lock)); - HandleTableL2 *l2 = l1r.t[handle / HANDLE_TABLE_L2_ENTRIES]; - if (!l2) return; + HandleTableL2 *l2 = l1r.t[inHandle / HANDLE_TABLE_L2_ENTRIES]; + if (!l2) return RESOLVE_HANDLE_FAILED; - Handle *_handle = l2->t + (handle % HANDLE_TABLE_L2_ENTRIES); + Handle *_handle = l2->t + (inHandle % HANDLE_TABLE_L2_ENTRIES); - if ((_handle->type & requestedType) && (_handle->object)) { + if ((_handle->type & typeMask) && (_handle->object)) { // Open a handle to the object so that it can't be destroyed while the system call is still using it. // The handle is closed in the KObject's destructor. if (OpenHandleToObject(_handle->object, _handle->type, _handle->flags)) { - object->type = _handle->type, object->object = _handle->object, object->flags = _handle->flags; - object->valid = object->close = true; + *outHandle = *_handle; + return RESOLVE_HANDLE_NORMAL; } } + + return RESOLVE_HANDLE_FAILED; } // TODO Switch the order of flags and type, so that the default value of flags can be 0. diff --git a/kernel/syscall.cpp b/kernel/syscall.cpp index d6ec1a8..9567080 100644 --- a/kernel/syscall.cpp +++ b/kernel/syscall.cpp @@ -115,7 +115,6 @@ bool MessageQueue::GetMessage(_EsMessageWithObject *_message) { return true; } -#define CHECK_OBJECT(x) if (!x.valid) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_HANDLE, !x.softFailure); else x.checked = true #define SYSCALL_BUFFER_LIMIT (64 * 1024 * 1024) // To prevent overflow and DOS attacks. #define SYSCALL_BUFFER(address, length, index, write) \ MMRegion *_region ## index = MMFindAndPinRegion(currentVMM, (address), (length)); \ @@ -123,18 +122,18 @@ bool MessageQueue::GetMessage(_EsMessageWithObject *_message) { EsDefer(if (_region ## index) MMUnpinRegion(currentVMM, _region ## index)); \ if (write && (_region ## index->flags & MM_REGION_READ_ONLY) && (~_region ## index->flags & MM_REGION_COPY_ON_WRITE)) \ SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true); -#define SYSCALL_HANDLE(handle, type, __object, variableType) \ - KObject ES_C_PREPROCESSOR_JOIN(_object, __LINE__)(currentProcess, handle, type); \ - CHECK_OBJECT(ES_C_PREPROCESSOR_JOIN(_object, __LINE__)); \ - variableType *const __object = (variableType *) (ES_C_PREPROCESSOR_JOIN(_object, __LINE__)).object #define SYSCALL_HANDLE_2(handle, _type, out) \ - KObject ES_C_PREPROCESSOR_JOIN(_object, __LINE__)(currentProcess, handle, _type); \ - CHECK_OBJECT(ES_C_PREPROCESSOR_JOIN(_object, __LINE__)); \ - const Handle out = { \ - .object = (ES_C_PREPROCESSOR_JOIN(_object, __LINE__)).object, \ - .flags = (ES_C_PREPROCESSOR_JOIN(_object, __LINE__)).flags, \ - .type = (ES_C_PREPROCESSOR_JOIN(_object, __LINE__)).type, \ - } + Handle _ ## out; \ + uint8_t status_ ## out = currentProcess->handleTable.ResolveHandle(&_ ## out, handle, _type); \ + if (status_ ## out == RESOLVE_HANDLE_FAILED) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_HANDLE, true); \ + EsDefer(if (status_ ## out == RESOLVE_HANDLE_NORMAL) CloseHandleToObject(_ ## out.object, _ ## out.type, _ ## out.flags)); \ + const Handle out = _ ## out +#define SYSCALL_HANDLE(handle, _type, out, variableType) \ + Handle _ ## out; \ + uint8_t status_ ## out = currentProcess->handleTable.ResolveHandle(&_ ## out, handle, _type); \ + if (status_ ## out == RESOLVE_HANDLE_FAILED) SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_HANDLE, true); \ + EsDefer(if (status_ ## out == RESOLVE_HANDLE_NORMAL) CloseHandleToObject(_ ## out.object, _ ## out.type, _ ## out.flags)); \ + variableType *const out = (variableType *) _ ## out.object #define SYSCALL_READ(destination, source, length) \ if (!MMArchIsBufferInUserRange(source, length) || !MMArchSafeCopy((uintptr_t) (destination), source, length)) \ SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_BUFFER, true); @@ -866,15 +865,22 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_WAIT) { } EsHandle handles[ES_MAX_WAIT_COUNT]; + KEvent *events[ES_MAX_WAIT_COUNT]; + Handle _objects[ES_MAX_WAIT_COUNT]; + uint8_t status[ES_MAX_WAIT_COUNT]; + bool handleErrors = false; + uintptr_t waitReturnValue; + SYSCALL_READ(handles, argument0, argument1 * sizeof(EsHandle)); - KEvent *events[ES_MAX_WAIT_COUNT]; - KObject _objects[ES_MAX_WAIT_COUNT] = {}; - for (uintptr_t i = 0; i < argument1; i++) { - _objects[i].Initialise(¤tProcess->handleTable, handles[i], - KERNEL_OBJECT_PROCESS | KERNEL_OBJECT_THREAD | KERNEL_OBJECT_EVENT | KERNEL_OBJECT_EVENT_SINK); - CHECK_OBJECT(_objects[i]); + KernelObjectType typeMask = KERNEL_OBJECT_PROCESS | KERNEL_OBJECT_THREAD | KERNEL_OBJECT_EVENT | KERNEL_OBJECT_EVENT_SINK; + status[i] = currentProcess->handleTable.ResolveHandle(&_objects[i], handles[i], typeMask); + + if (status[i] == RESOLVE_HANDLE_FAILED) { + handleErrors = true; + continue; + } void *object = _objects[i].object; @@ -901,28 +907,39 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_WAIT) { } } - size_t waitObjectCount = argument1; - KTimer timer = {}; + if (!handleErrors) { + size_t waitObjectCount = argument1; + KTimer timer = {}; - if (argument2 != (uintptr_t) ES_WAIT_NO_TIMEOUT) { - KTimerSet(&timer, argument2); - events[waitObjectCount++] = &timer.event; + if (argument2 != (uintptr_t) ES_WAIT_NO_TIMEOUT) { + KTimerSet(&timer, argument2); + events[waitObjectCount++] = &timer.event; + } + + currentThread->terminatableState = THREAD_USER_BLOCK_REQUEST; + waitReturnValue = scheduler.WaitEvents(events, waitObjectCount); + currentThread->terminatableState = THREAD_IN_SYSCALL; + + if (waitReturnValue == argument1) { + waitReturnValue = ES_ERROR_TIMEOUT_REACHED; + } + + if (argument2 != (uintptr_t) ES_WAIT_NO_TIMEOUT) { + KTimerRemove(&timer); + } } - uintptr_t waitReturnValue; - currentThread->terminatableState = THREAD_USER_BLOCK_REQUEST; - waitReturnValue = scheduler.WaitEvents(events, waitObjectCount); - currentThread->terminatableState = THREAD_IN_SYSCALL; - - if (waitReturnValue == argument1) { - waitReturnValue = ES_ERROR_TIMEOUT_REACHED; + for (uintptr_t i = 0; i < argument1; i++) { + if (status[i] == RESOLVE_HANDLE_NORMAL) { + CloseHandleToObject(_objects[i].object, _objects[i].type, _objects[i].flags); + } } - if (argument2 != (uintptr_t) ES_WAIT_NO_TIMEOUT) { - KTimerRemove(&timer); + if (handleErrors) { + SYSCALL_RETURN(ES_FATAL_ERROR_INVALID_HANDLE, true); + } else { + SYSCALL_RETURN(waitReturnValue, false); } - - SYSCALL_RETURN(waitReturnValue, false); } SYSCALL_IMPLEMENT(ES_SYSCALL_WINDOW_SET_CURSOR) {