diff options
author | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/system/protect.cpp |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/system/protect.cpp')
-rw-r--r-- | util/system/protect.cpp | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/util/system/protect.cpp b/util/system/protect.cpp new file mode 100644 index 00000000000..bbb8d410dfb --- /dev/null +++ b/util/system/protect.cpp @@ -0,0 +1,95 @@ +#include "protect.h" + +#include <util/generic/yexception.h> +#include <util/generic/string.h> +#include <util/stream/output.h> + +#include "yassert.h" + +#if defined(_unix_) || defined(_darwin_) + #include <sys/mman.h> +#endif + +#ifdef _win_ + #include <Windows.h> +#endif + +static TString ModeToString(const EProtectMemory mode) { + TString strMode; + if (mode == PM_NONE) { + return "PM_NONE"; + } + + if (mode & PM_READ) { + strMode += "PM_READ|"; + } + if (mode & PM_WRITE) { + strMode += "PM_WRITE|"; + } + if (mode & PM_EXEC) { + strMode += "PM_EXEC|"; + } + return strMode.substr(0, strMode.size() - 1); +} + +void ProtectMemory(void* addr, const size_t length, const EProtectMemory mode) { + Y_VERIFY(!(mode & ~(PM_READ | PM_WRITE | PM_EXEC)), "Invalid memory protection flag combination. "); + +#if defined(_unix_) || defined(_darwin_) + int mpMode = PROT_NONE; + if (mode & PM_READ) { + mpMode |= PROT_READ; + } + if (mode & PM_WRITE) { + mpMode |= PROT_WRITE; + } + if (mode & PM_EXEC) { + mpMode |= PROT_EXEC; + } + // some old manpages for mprotect say 'const void* addr', but that's wrong + if (mprotect(addr, length, mpMode) == -1) { + ythrow TSystemError() << "Memory protection failed for mode " << ModeToString(mode) << ". "; + } +#endif + +#ifdef _win_ + DWORD mpMode = PAGE_NOACCESS; + // windows developers are not aware of bit flags :( + + /* + * It's unclear that we should NOT fail on Windows that does not support write-only + * memory protection. As we don't know, what behavior is more correct, we choose + * one of them. A discussion was here: REVIEW: 39725 + */ + switch (mode.ToBaseType()) { + case PM_READ: + mpMode = PAGE_READONLY; + break; + case PM_WRITE: + mpMode = PAGE_READWRITE; + break; // BUG: no write-only support + /*case PM_WRITE: + ythrow TSystemError() << "Write-only protection mode is not supported under Windows. ";*/ + case PM_READ | PM_WRITE: + mpMode = PAGE_READWRITE; + break; + case PM_EXEC: + mpMode = PAGE_EXECUTE; + break; + case PM_READ | PM_EXEC: + mpMode = PAGE_EXECUTE_READ; + break; + case PM_WRITE | PM_EXEC: + mpMode = PAGE_EXECUTE_READWRITE; + break; // BUG: no write-only support + /*case PM_WRITE | PM_EXEC: + ythrow TSystemError() << "Write-execute-only protection mode is not supported under Windows. ";*/ + case PM_READ | PM_WRITE | PM_EXEC: + mpMode = PAGE_EXECUTE_READWRITE; + break; + } + DWORD oldMode = 0; + if (!VirtualProtect(addr, length, mpMode, &oldMode)) + ythrow TSystemError() << "Memory protection failed for mode " << ModeToString(mode) << ". "; +#endif +} |