AuroraRuntime/Source/Process/AuProcessSectionView.NT.cpp

507 lines
18 KiB
C++

/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuProcessSectionView.NT.cpp
Date: 2022-08-09
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "AuProcessSectionView.NT.hpp"
#include "Process.hpp"
#include <Source/IO/FS/FileStream.NT.hpp>
#include "AuProcessSectionFileMapView.NT.hpp"
#include <Source/IO/IPC/AuIPCHandle.hpp>
#include <Windows.h>
namespace Aurora::Process
{
AuUInt ProcessSectionView::GetStart()
{
return AuNumericLimits<AuUInt>::min();
}
AuUInt ProcessSectionView::GetEnd()
{
return AuNumericLimits<AuUInt>::max();
}
AuSPtr<IProcessSectionMapView> ProcessSectionView::Allocate(AuUInt uLength)
{
PageTable table {};
table.NX = true;
table.readable = true;
table.writable = true;
return this->AllocateEx2(uLength, 0, table);
}
AuSPtr<IProcessSectionMapView> 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<IProcessSectionMapView> ProcessSectionView::MapFileByObject(const AuSPtr<IO::IIOHandle> &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 {};
HANDLE hEventHandle { INVALID_HANDLE_VALUE };
OVERLAPPED overlapped {};
if (processLockLevel == AuFS::EFileAdvisoryLockLevel::eBlockReadWrite)
{
dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
}
dwFlags |= LOCKFILE_FAIL_IMMEDIATELY;
overlapped.Offset = AuBitsToLower(uOffset);
overlapped.OffsetHigh = AuBitsToHigher(uOffset);
#if 0
bool bIsAsync = pIOHandle->IsAsync();
if (bIsAsync)
{
hEventHandle = ::CreateEventA(nullptr, false, false, nullptr);
if (!hEventHandle)
{
SysPushErrorGeneric();
return {};
}
overlapped.hEvent = hEventHandle;
}
#endif
auto hHandle = (HANDLE)pIOHandle->GetOSHandle();
if (!::LockFileEx(hHandle,
dwFlags,
0,
AuBitsToLower(uLength),
AuBitsToHigher(uLength),
&overlapped))
{
#if 0
if (GetLastError() == ERROR_IO_PENDING)
{
::WaitForSingleObject(hEventHandle, 0);
DWORD idc {};
if (!::GetOverlappedResult(hHandle,
&overlapped,
&idc,
true))
{
SysPushErrorIO("No Lock");
AuWin32CloseHandle(hEventHandle);
return {};
}
}
else
#endif
{
SysPushErrorIO("No Lock");
AuWin32CloseHandle(hEventHandle);
return {};
}
}
else
{
AuWin32CloseHandle(hEventHandle);
}
}
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 {};
};
if (!pCreateFileMappingA)
{
return {};
}
hFileMap = pCreateFileMappingA((HANDLE)pIOHandle->GetOSHandle(),
nullptr,
pageAttributes,
#if defined(AURORA_IS_64BIT)
AuBitsToHigher(uLength + uOffset),
AuBitsToLower(uLength + uOffset),
#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 = pMapViewOfFile(hFileMap,
desiredAccess,
AuBitsToHigher(uOffset),
AuBitsToLower(uOffset),
uLength);
if (!map)
{
SysPushErrorIO("Couldn't create map of section");
AuWin32CloseHandle(hFileMap);
return {};
}
auto pNewObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map), hFileMap);
if (!pNewObject)
{
SysPushErrorMem();
AuWin32CloseHandle(hFileMap);
::UnmapViewOfFile(map);
return {};
}
pNewObject->pProcessGlobalHint = this;
pNewObject->uLength = uLength;
return pNewObject;
}
AuSPtr<IProcessSectionMapView> 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 = pOpenFileMappingA(desiredAccess,
FALSE,
path.c_str());
if ((hFileMap == INVALID_HANDLE_VALUE) ||
(!hFileMap))
{
SysPushErrorIO("Couldn't create IPC map (handle: {})", handleString);
return {};
}
auto map = pMapViewOfFile(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<ProcessSectionFileMapView>(AuUInt(map), hFileMap);
if (!pNewObject)
{
SysPushErrorMem();
AuWin32CloseHandle(hFileMap);
::UnmapViewOfFile(map);
return {};
}
pNewObject->pProcessGlobalHint = this;
pNewObject->uLength = uLength;
return pNewObject;
}
AuSPtr<IProcessSectionMapView> 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<IProcessSectionMapView> 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;
}
if (!pCreateFileMappingA)
{
return {};
}
hFileMap = pCreateFileMappingA(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 = pMapViewOfFile(hFileMap,
sectionPermission,
0,
0,
uLength);
if (!map)
{
SysPushErrorIO("Couldn't create allocation of section");
AuWin32CloseHandle(hFileMap);
return {};
}
auto pNewObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map), hFileMap);
if (!pNewObject)
{
SysPushErrorMem();
AuWin32CloseHandle(hFileMap);
return {};
}
pNewObject->pProcessGlobalHint = this;
pNewObject->uLength = uLength;
return pNewObject;
}
AuSPtr<IProcessSectionMapView> 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<IProcessSectionMapView> ProcessSectionView::MapFileByObjectEx(AuUInt viewOffset,
const AuSPtr<IO::IIOHandle> &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<IProcessSectionMapView> 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<AuPair<AuUInt, AuUInt>> 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<IProcessSectionView> GetGlobalProcessSpace()
{
static ProcessSectionView gSingleton;
gSingleton.DoVanillaDriverlessExtesionWin7Test();
return AuUnsafeRaiiToShared(&gSingleton);
}
}