aboutsummaryrefslogtreecommitdiffstats
path: root/util/system/protect.cpp
blob: 615a8231bbe84ec4fadae3203430e86db8ae3908 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
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 
}