/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuProcessSectionView.NT.cpp Date: 2022-08-09 Author: Reece ***/ #include #include "AuProcessSectionView.NT.hpp" #include "Process.hpp" #include #include "AuProcessSectionFileMapView.NT.hpp" #include #include namespace Aurora::Process { AuUInt ProcessSectionView::GetStart() { return AuNumericLimits::min(); } AuUInt ProcessSectionView::GetEnd() { return AuNumericLimits::max(); } AuSPtr ProcessSectionView::Allocate(AuUInt uLength) { PageTable table {}; table.NX = true; table.readable = true; table.writable = true; return this->AllocateEx2(uLength, 0, table); } AuSPtr ProcessSectionView::MapFileByPath(const AuString &str, AuUInt64 uOffset, AuUInt uLength, AuFS::EFileOpenMode mode, AuFS::EFileAdvisoryLockLevel sectionLock) { auto pHandle = AuIO::IOHandleShared(); if (!pHandle) { SysPushErrorMemory(); return nullptr; } AuIO::IIOHandle::HandleCreate createhandle(str); createhandle.eAdvisoryLevel = AuFS::EFileAdvisoryLockLevel::eNoSafety; createhandle.eMode = mode; createhandle.bFailIfNonEmptyFile = false; createhandle.bDirectIOMode = false; createhandle.bAsyncHandle = false; if (!pHandle->InitFromPath(createhandle)) { return nullptr; } return this->MapFileByObject(pHandle, uOffset, uLength, mode, sectionLock); } AuSPtr ProcessSectionView::MapFileByObject(const AuSPtr &pIOHandle, AuUInt64 uOffset, AuUInt uLength, AuFS::EFileOpenMode mode, AuFS::EFileAdvisoryLockLevel processLockLevel) { HANDLE hFileMap; ULONG desiredAccess {}, pageAttributes {}; if (!pIOHandle) { SysPushErrorArg(); return {}; } if (!uLength) { SysPushErrorArg("invalid uLength"); return {}; } if (processLockLevel != AuFS::EFileAdvisoryLockLevel::eNoSafety) { DWORD dwFlags {}; OVERLAPPED overlapped {}; if (processLockLevel == AuFS::EFileAdvisoryLockLevel::eBlockReadWrite) { dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; } dwFlags |= LOCKFILE_FAIL_IMMEDIATELY; overlapped.Offset = AuBitsToLower(uOffset); overlapped.OffsetHigh = AuBitsToHigher(uOffset); if (!::LockFileEx((HANDLE)pIOHandle->GetOSHandle(), dwFlags, 0, AuBitsToLower(uLength), AuBitsToHigher(uLength), &overlapped)) { SysPushErrorIO("No Lock"); return {}; } } switch (mode) { case AuFS::EFileOpenMode::eRead: { desiredAccess = SECTION_MAP_READ; pageAttributes = PAGE_READONLY; break; } case AuFS::EFileOpenMode::eWrite: case AuFS::EFileOpenMode::eReadWrite: { desiredAccess = SECTION_MAP_READ | SECTION_MAP_WRITE; pageAttributes = PAGE_READWRITE; break; } default: SysPushErrorGeneric(); return {}; }; hFileMap = ::CreateFileMappingA((HANDLE)pIOHandle->GetOSHandle(), nullptr, pageAttributes, #if defined(AURORA_IS_64BIT) AuBitsToHigher(uLength), AuBitsToLower(uLength), #else 0, uLength, #endif nullptr); if ((hFileMap == INVALID_HANDLE_VALUE) || (!hFileMap)) { SysPushErrorIO("Couldn't create file map. Is the requeted access mode too high for the given object?"); return {}; } auto map = ::MapViewOfFile(hFileMap, desiredAccess, AuBitsToHigher(uOffset), AuBitsToLower(uOffset), uLength); if (!map) { SysPushErrorIO("Couldn't create map of section"); AuWin32CloseHandle(hFileMap); return {}; } auto pNewObject = AuMakeShared(AuUInt(map), hFileMap); if (!pNewObject) { SysPushErrorMem(); AuWin32CloseHandle(hFileMap); ::UnmapViewOfFile(map); return {}; } pNewObject->pProcessGlobalHint = this; pNewObject->uLength = uLength; return pNewObject; } AuSPtr ProcessSectionView::MapIPCMemory(const AuString &handleString, AuUInt64 uOffset, AuUInt uLength, AuFS::EFileOpenMode mode) { AuIPC::IPCHandle handle; HANDLE hFileMap; ULONG desiredAccess {}, pageAttributes {}; if (!uLength) { SysPushErrorArg("invalid uLength"); return {}; } if (!handle.FromString(handleString)) { SysPushErrorParseError("{}", handleString); return {}; } auto token = handle.GetToken(AuIPC::EIPCHandleType::eIPCMemory, 0); if (!token) { SysPushErrorParseError(); return {}; } auto actualLength = token->token.word; auto path = token->token.ToNTPath(); if (actualLength < uOffset + uLength) { SysPushErrorIO("Out of range"); return {}; } switch (mode) { case AuFS::EFileOpenMode::eRead: { desiredAccess = SECTION_MAP_READ; pageAttributes = PAGE_READONLY; break; } case AuFS::EFileOpenMode::eWrite: case AuFS::EFileOpenMode::eReadWrite: { desiredAccess = SECTION_MAP_READ | SECTION_MAP_WRITE; pageAttributes = PAGE_READWRITE; break; } default: SysPushErrorGeneric(); return {}; }; hFileMap = ::OpenFileMappingA(desiredAccess, FALSE, path.c_str()); if ((hFileMap == INVALID_HANDLE_VALUE) || (!hFileMap)) { SysPushErrorIO("Couldn't create IPC map (handle: {})", handleString); return {}; } auto map = ::MapViewOfFile(hFileMap, desiredAccess, AuBitsToHigher(uOffset), AuBitsToLower(uOffset), uLength); if (!map) { SysPushErrorIO("Couldn't create map of IPC section (handle: {})", handleString); AuWin32CloseHandle(hFileMap); return {}; } auto pNewObject = AuMakeShared(AuUInt(map), hFileMap); if (!pNewObject) { SysPushErrorMem(); AuWin32CloseHandle(hFileMap); ::UnmapViewOfFile(map); return {}; } pNewObject->pProcessGlobalHint = this; pNewObject->uLength = uLength; return pNewObject; } AuSPtr ProcessSectionView::AllocateEx(AuUInt uLength, AuUInt uOffset) { SysAssert(this->bPanicOnEx, "Windows 7/8 called a Windows 10 RS4 memory management routine. " "Applications requiring explicit and pre-reserved memory maps cannot run on unmodified unsupported versions of Windows." "We lied about reserving a region of bytes with a ProcessSectionView. Unable to gurantee uOffset."); return this->Allocate(uLength); } AuSPtr ProcessSectionView::AllocateEx2(AuUInt uLength, AuUInt uOffset, PageTable permissions) { SysAssert(this->bPanicOnEx, "Windows 7/8 called a Windows 10 RS4 memory management routine. " "Applications requiring explicit and pre-reserved memory maps cannot run on unmodified unsupported versions of Windows." "We lied about reserving a region of bytes with a ProcessSectionView. Unable to gurantee uOffset."); HANDLE hFileMap; if (!uLength) { SysPushErrorArg("invalid uLength"); return {}; } DWORD uPageFlags {}; if (permissions.writable && permissions.NX) { uPageFlags = PAGE_READWRITE; } else if (permissions.readable && permissions.NX) { uPageFlags = PAGE_READONLY; } else if (permissions.writable) { uPageFlags = PAGE_EXECUTE_READWRITE; } else if (permissions.readable) { uPageFlags = PAGE_EXECUTE_READ; } hFileMap = ::CreateFileMappingA(INVALID_HANDLE_VALUE, nullptr, uPageFlags, #if defined(AURORA_IS_64BIT) AuBitsToHigher(uLength), AuBitsToLower(uLength), #else 0, uLength, #endif nullptr); if ((hFileMap == INVALID_HANDLE_VALUE) || (!hFileMap)) { SysPushErrorIO("Couldn't create file map"); return {}; } DWORD sectionPermission {}; if (permissions.readable) { sectionPermission = SECTION_MAP_READ; } if (permissions.writable) { sectionPermission |= SECTION_MAP_WRITE; } if (!permissions.NX) { sectionPermission |= SECTION_MAP_EXECUTE; } auto map = ::MapViewOfFile(hFileMap, sectionPermission, 0, 0, uLength); if (!map) { SysPushErrorIO("Couldn't create allocation of section"); AuWin32CloseHandle(hFileMap); return {}; } auto pNewObject = AuMakeShared(AuUInt(map), hFileMap); if (!pNewObject) { SysPushErrorMem(); AuWin32CloseHandle(hFileMap); return {}; } pNewObject->pProcessGlobalHint = this; pNewObject->uLength = uLength; return pNewObject; } AuSPtr ProcessSectionView::MapFileByPathEx(AuUInt viewOffset, const AuString &str, AuUInt64 uOffset, AuUInt uLength, Aurora::IO::FS::EFileOpenMode mode, Aurora::IO::FS::EFileAdvisoryLockLevel processLockLevel) { SysAssert(this->bPanicOnEx, "Windows 7/8 called a Windows 10 RS4 memory management routine. " "Applications requiring explicit and pre-reserved memory maps cannot run on unmodified unsupported versions of Windows." "We lied about reserving a region of bytes with a ProcessSectionView. Unable to gurantee uOffset."); return this->MapFileByPath(str, uOffset, uLength, mode, processLockLevel); } AuSPtr ProcessSectionView::MapFileByObjectEx(AuUInt viewOffset, const AuSPtr &pIOHandle, AuUInt64 uOffset, AuUInt uLength, Aurora::IO::FS::EFileOpenMode mode, Aurora::IO::FS::EFileAdvisoryLockLevel processLockLevel) { SysAssert(this->bPanicOnEx, "Windows 7/8 called a Windows 10 RS4 memory management routine. " "Applications requiring explicit and pre-reserved memory maps cannot run on unmodified unsupported versions of Windows." "We lied about reserving a region of bytes with a ProcessSectionView. Unable to gurantee uOffset."); return this->MapFileByObject(pIOHandle, uOffset, uLength, mode, processLockLevel); } AuSPtr ProcessSectionView::MapIPCMemoryEx(AuUInt viewOffset, const AuString &handle, AuUInt64 uOffset, AuUInt uLength, Aurora::IO::FS::EFileOpenMode mode) { SysAssert(this->bPanicOnEx, "Windows 7/8 called a Windows 10 RS4 memory management routine. " "Applications requiring explicit and pre-reserved memory maps cannot run on unmodified unsupported versions of Windows." "We lied about reserving a region of bytes with a ProcessSectionView. Unable to gurantee uOffset."); return this->MapIPCMemory(handle, uOffset, uLength, mode); } AuList> ProcessSectionView::GetAllocations() { AU_LOCK_GUARD(this->spinlock); return this->allocations; } void ProcessSectionView::DoVanillaDriverlessExtesionWin7Test() { #if defined(AURORA_PLATFORM_WIN32) #define WIN_7_WARN "WARNING: ADDRESS SPACE CANNOT BE RESERVED ON OLDER NT KERNELS. \r\n" \ "AuProcess::ReserveAddressSpace(AuUInt uOffset) is about to lie about reserving the address space, yield the entire address space, and leave a note to terminate the application if an explicit fixed-offset request is made." SysPushErrorUnimplemented("Win7_ReserveAddressSpace_RS4_REQ"); AuUInt uEnvSize {}; ::getenv_s(&uEnvSize, nullptr, 0, "AURORA_FORCE_RANDOM_ADDRESS_WITHOUT_VIRTALLOC2"); if (uEnvSize) { // bah // enjoy return not respecting what was provided as the expected offset. // this is not a workaround for missing functionality in the operating systems userland and kernel abstraction. // this will just prevent us from panicing preemptively. this->bPanicOnEx = true; } else { AuLogWarn(WIN_7_WARN); this->bPanicOnEx = false; } #else AuLogWarn("I don't know this platform - AuProcess"); this->bPanicOnEx = true; #endif } AUKN_SYM AuSPtr GetGlobalProcessSpace() { static ProcessSectionView gSingleton; gSingleton.DoVanillaDriverlessExtesionWin7Test(); return AuUnsafeRaiiToShared(&gSingleton); } }