AuroraRuntime/Source/Process/ProcessSectionView.NT.cpp
J Reece Wilson 2e5742dd2f [*] Harden Process Section APIs
[*] Refactor IProcessSectionView::MapIPCMemory length type to machine word
2022-08-15 00:41:43 +01:00

285 lines
9.3 KiB
C++

/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: ProcessSectionView.NT.hpp
Date: 2022-08-09
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "ProcessSectionView.NT.hpp"
#include "Process.hpp"
#include <Source/IO/FS/FileStream.NT.hpp>
#include "ProcessSectionFileMapView.NT.hpp"
#include <Source/IO/IPC/IPCHandle.hpp>
#include <Windows.h>
namespace Aurora::Process
{
AuSPtr<IProcessSectionMapView> ProcessSectionView::Allocate(AuUInt length)
{
HANDLE hFileMap;
if (!length)
{
SysPushErrorArg("invalid length");
return {};
}
hFileMap = ::CreateFileMappingA(INVALID_HANDLE_VALUE,
nullptr,
PAGE_READWRITE,
#if defined(AURORA_IS_64BIT)
AuBitsToHigher(length),
AuBitsToLower(length),
#else
0,
length,
#endif
nullptr);
if ((hFileMap == INVALID_HANDLE_VALUE) ||
(!hFileMap))
{
SysPushErrorIO("Couldn't create file map");
return {};
}
auto map = ::MapViewOfFile(hFileMap,
SECTION_MAP_READ | SECTION_MAP_WRITE,
0,
0,
length);
if (!map)
{
SysPushErrorIO("Couldn't create allocation of section");
AuWin32CloseHandle(hFileMap);
return {};
}
auto newObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map), hFileMap);
if (!newObject)
{
SysPushErrorMem();
AuWin32CloseHandle(hFileMap);
return {};
}
return newObject;
}
AuSPtr<IProcessSectionMapView> ProcessSectionView::MapFileByPath(const AuString &str,
AuUInt64 offset,
AuUInt length,
AuFS::EFileOpenMode mode,
AuFS::EFileAdvisoryLockLevel sectionLock)
{
auto file = AuFS::OpenShared(str, mode, AuFS::EFileAdvisoryLockLevel::eNoSafety);
return file ? this->MapFileByObject(file, offset, length, mode, sectionLock) : AuSPtr<IProcessSectionMapView> {};
}
AuSPtr<IProcessSectionMapView> ProcessSectionView::MapFileByObject(const AuSPtr<AuFS::IFileStream> &stream,
AuUInt64 offset,
AuUInt length,
AuFS::EFileOpenMode mode,
AuFS::EFileAdvisoryLockLevel processLockLevel)
{
HANDLE hFileMap;
ULONG desiredAccess {}, pageAttributes {};
if (!stream)
{
return {};
}
if (!length)
{
SysPushErrorArg("invalid length");
return {};
}
auto ok = AuStaticCast<AuFS::WinFileStream>(stream);
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(offset);
overlapped.OffsetHigh = AuBitsToHigher(offset);
if (!::LockFileEx(ok->GetHandle(),
dwFlags,
0,
AuBitsToLower(length),
AuBitsToHigher(length),
&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(ok->GetHandle(),
nullptr,
pageAttributes,
#if defined(AURORA_IS_64BIT)
AuBitsToHigher(length),
AuBitsToLower(length),
#else
0,
length,
#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(offset),
AuBitsToLower(offset),
length);
if (!map)
{
SysPushErrorIO("Couldn't create map of section");
AuWin32CloseHandle(hFileMap);
return {};
}
auto newObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map), hFileMap);
if (!newObject)
{
SysPushErrorMem();
AuWin32CloseHandle(hFileMap);
::UnmapViewOfFile(map);
return {};
}
return newObject;
}
AuSPtr<IProcessSectionMapView> ProcessSectionView::MapIPCMemory(const AuString &handleString,
AuUInt64 offset,
AuUInt length,
AuFS::EFileOpenMode mode)
{
AuIPC::IPCHandle handle;
HANDLE hFileMap;
ULONG desiredAccess {}, pageAttributes {};
if (!length)
{
SysPushErrorArg("invalid length");
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 < offset + length)
{
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(offset),
AuBitsToLower(offset),
length);
if (!map)
{
SysPushErrorIO("Couldn't create map of IPC section (handle: {})", handleString);
AuWin32CloseHandle(hFileMap);
return {};
}
auto newObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map), hFileMap);
if (!newObject)
{
SysPushErrorMem();
AuWin32CloseHandle(hFileMap);
::UnmapViewOfFile(map);
return {};
}
return newObject;
}
AUKN_SYM AuSPtr<IProcessSectionView> GetGlobalProcessSpace()
{
static ProcessSectionView gSingleton;
return AuUnsafeRaiiToShared(&gSingleton);
}
}