diff --git a/src/core/kernel/exports/EmuKrnlNt.cpp b/src/core/kernel/exports/EmuKrnlNt.cpp index 9a04a8995..efbebd61a 100644 --- a/src/core/kernel/exports/EmuKrnlNt.cpp +++ b/src/core/kernel/exports/EmuKrnlNt.cpp @@ -142,10 +142,10 @@ XBSYSAPI EXPORTNUM(187) xbox::ntstatus_xt NTAPI xbox::NtClose NTSTATUS ret = xbox::status_success; - if (IsEmuHandle(Handle)) + if (EmuHandle::IsEmuHandle(Handle)) { // delete 'special' handles - EmuHandle *iEmuHandle = HandleToEmuHandle(Handle); + auto iEmuHandle = (EmuHandle*)Handle; ret = iEmuHandle->NtClose(); LOG_UNIMPLEMENTED(); // TODO : Base this on the Ob* functions @@ -682,8 +682,8 @@ XBSYSAPI EXPORTNUM(197) xbox::ntstatus_xt NTAPI xbox::NtDuplicateObject NTSTATUS ret = xbox::status_success; - if (IsEmuHandle(SourceHandle)) { - EmuHandle* iEmuHandle = HandleToEmuHandle(SourceHandle); + if (EmuHandle::IsEmuHandle(SourceHandle)) { + auto iEmuHandle = (EmuHandle*)SourceHandle; ret = iEmuHandle->NtDuplicateObject(TargetHandle, Options); /* PVOID Object; @@ -739,7 +739,7 @@ XBSYSAPI EXPORTNUM(198) xbox::ntstatus_xt NTAPI xbox::NtFlushBuffersFile LOG_FUNC_END; NTSTATUS ret = xbox::status_success; - if (IsEmuHandle(FileHandle)) + if (EmuHandle::IsEmuHandle(FileHandle)) LOG_UNIMPLEMENTED(); else ret = NtDll::NtFlushBuffersFile(FileHandle, (NtDll::IO_STATUS_BLOCK*)IoStatusBlock); @@ -1371,13 +1371,16 @@ XBSYSAPI EXPORTNUM(215) xbox::ntstatus_xt NTAPI xbox::NtQuerySymbolicLinkObject LOG_FUNC_ARG_OUT(ReturnedLength) LOG_FUNC_END; - NTSTATUS ret = 0; + NTSTATUS ret = STATUS_INVALID_HANDLE; EmuNtSymbolicLinkObject* symbolicLinkObject = NULL; - // Check that we actually got an EmuHandle : - ret = STATUS_INVALID_HANDLE; + // We expect LinkHandle to always be an EmuHandle + if (!EmuHandle::IsEmuHandle(LinkHandle)) { + LOG_UNIMPLEMENTED(); + return ret; + } - EmuHandle* iEmuHandle = HandleToEmuHandle(LinkHandle); + auto iEmuHandle = (EmuHandle*)LinkHandle; // Retrieve the NtSymbolicLinkObject and populate the output arguments : ret = xbox::status_success; symbolicLinkObject = (EmuNtSymbolicLinkObject*)iEmuHandle->NtObject; diff --git a/src/core/kernel/support/EmuFile.cpp b/src/core/kernel/support/EmuFile.cpp index c5c6113e0..4aa93c7bc 100644 --- a/src/core/kernel/support/EmuFile.cpp +++ b/src/core/kernel/support/EmuFile.cpp @@ -255,9 +255,39 @@ EmuHandle::EmuHandle(EmuNtObject* ntObject) NtObject = ntObject; } +std::unordered_set EmuHandle::EmuHandleLookup = {}; +std::shared_mutex EmuHandle::EmuHandleLookupLock = {}; + +EmuHandle* EmuHandle::CreateEmuHandle(EmuNtObject* ntObject) { + auto emuHandle = new EmuHandle(ntObject); + + // Register EmuHandle + { + std::unique_lock scopedLock(EmuHandleLookupLock); + EmuHandleLookup.insert(emuHandle); + } + + return emuHandle; +} + NTSTATUS EmuHandle::NtClose() { - return NtObject->NtClose(); + auto status = NtObject->NtClose(); + + // Unregister the handle + if (status == STATUS_SUCCESS) { + std::unique_lock scopedLock(EmuHandleLookupLock); + EmuHandleLookup.erase(this); + } + + return status; +} + +bool EmuHandle::IsEmuHandle(HANDLE Handle) +{ + std::shared_lock scopedLock(EmuHandleLookupLock); + auto iter = EmuHandleLookup.find((EmuHandle*) Handle); + return !(iter == EmuHandleLookup.end()); } NTSTATUS EmuHandle::NtDuplicateObject(PHANDLE TargetHandle, DWORD Options) @@ -274,7 +304,7 @@ EmuNtObject::EmuNtObject() HANDLE EmuNtObject::NewHandle() { RefCount++; - return EmuHandleToHandle(new EmuHandle(this)); + return EmuHandle::CreateEmuHandle(this); } NTSTATUS EmuNtObject::NtClose() @@ -292,21 +322,6 @@ EmuNtObject* EmuNtObject::NtDuplicateObject(DWORD Options) return this; } -bool IsEmuHandle(HANDLE Handle) -{ - return ((uint32_t)Handle > 0x80000000) && ((uint32_t)Handle < 0xFFFFFFFE); -} - -EmuHandle* HandleToEmuHandle(HANDLE Handle) -{ - return (EmuHandle*)((uint32_t)Handle & 0x7FFFFFFF); -} - -HANDLE EmuHandleToHandle(EmuHandle* emuHandle) -{ - return (HANDLE)((uint32_t)emuHandle | 0x80000000); -} - std::wstring string_to_wstring(std::string const & src) { std::wstring result = std::wstring(src.length(), L' '); diff --git a/src/core/kernel/support/EmuFile.h b/src/core/kernel/support/EmuFile.h index 8690f6970..0c4d5a834 100644 --- a/src/core/kernel/support/EmuFile.h +++ b/src/core/kernel/support/EmuFile.h @@ -30,6 +30,8 @@ #include #include #include +#include +#include // ****************************************************************** // * prevent name collisions @@ -160,10 +162,21 @@ NTSTATUS CxbxConvertFilePath(std::string RelativeXboxPath, OUT std::wstring &Rel class EmuHandle { public: - EmuHandle(EmuNtObject* ntObject); NTSTATUS NtClose(); NTSTATUS NtDuplicateObject(PHANDLE TargetHandle, DWORD Options); EmuNtObject* NtObject; + + static EmuHandle* CreateEmuHandle(EmuNtObject* ntObject); + static bool IsEmuHandle(HANDLE Handle); +private: + EmuHandle(EmuNtObject* ntObject); + // Keep track of every EmuHandle wrapper + // If we remember what EmuHandle objects we hand out, we can tell the difference between an EmuHandle and garbage + // We used to rely on the high bit to differentiatean EmuHandles + // But titles may attempt to operate on invalid handles with the high bit set + // Test case: Amped sets a handle value to 0xFDFDFDFD (coincidentally a VS debugger guard value) + static std::unordered_set EmuHandleLookup; + static std::shared_mutex EmuHandleLookupLock; }; // ****************************************************************** @@ -204,13 +217,6 @@ struct XboxDevice { HANDLE HostRootHandle; }; -// ****************************************************************** -// * is Handle a 'special' emulated handle? -// ****************************************************************** -bool IsEmuHandle(HANDLE Handle); -EmuHandle* HandleToEmuHandle(HANDLE Handle); -HANDLE EmuHandleToHandle(EmuHandle* emuHandle); - CHAR* NtStatusToString(IN NTSTATUS Status); int CxbxRegisterDeviceHostPath(std::string XboxFullPath, std::string HostDevicePath, bool IsFile = false);