summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGHC GitLab CI <ghc-ci@gitlab-haskell.org>2022-01-28 22:33:52 -0500
committerMarge Bot <ben+marge-bot@smart-cactus.org>2022-02-06 01:43:56 -0500
commit86589b893c092ae900723e76848525f20f6cafbf (patch)
tree3a77beccb4db660a3212e0aef7b330d91effa3b7
parent2e9248b7f7f645851ceb49931d10b9c5e58d2bbb (diff)
downloadhaskell-86589b893c092ae900723e76848525f20f6cafbf.tar.gz
rts: Generalize mmapForLinkerMarkExecutable
Renamed to mprotectForLinker and allowed setting of arbitrary protection modes.
-rw-r--r--rts/ExecPage.c2
-rw-r--r--rts/Linker.c56
-rw-r--r--rts/LinkerInternals.h10
-rw-r--r--rts/linker/Elf.c2
-rw-r--r--rts/linker/M32Alloc.c2
-rw-r--r--rts/linker/MachO.c4
-rw-r--r--rts/linker/SymbolExtras.c2
7 files changed, 61 insertions, 17 deletions
diff --git a/rts/ExecPage.c b/rts/ExecPage.c
index 6f5b6e281a..24d4d65bad 100644
--- a/rts/ExecPage.c
+++ b/rts/ExecPage.c
@@ -15,7 +15,7 @@ ExecPage *allocateExecPage() {
}
void freezeExecPage(ExecPage *page) {
- mmapForLinkerMarkExecutable(page, getPageSize());
+ mprotectForLinker(page, getPageSize(), MEM_READ_EXECUTE);
flushExec(getPageSize(), page);
}
diff --git a/rts/Linker.c b/rts/Linker.c
index c79f184f23..6468e7818d 100644
--- a/rts/Linker.c
+++ b/rts/Linker.c
@@ -1008,6 +1008,17 @@ resolveSymbolAddr (pathchar* buffer, int size,
#endif /* OBJFORMAT_PEi386 */
}
+static const char *memoryAccessDescription(MemoryAccess mode)
+{
+ switch (mode) {
+ case MEM_NO_ACCESS: return "no-access";
+ case MEM_READ_ONLY: return "read-only";
+ case MEM_READ_WRITE: return "read-write";
+ case MEM_READ_EXECUTE: return "read-execute";
+ default: barf("invalid MemoryAccess");
+ }
+}
+
#if defined(mingw32_HOST_OS)
//
@@ -1028,16 +1039,29 @@ munmapForLinker (void *addr, size_t bytes, const char *caller)
}
}
+/**
+ * Change the allowed access modes of a region of memory previously allocated
+ * with mmapAnonForLinker.
+ */
void
-mmapForLinkerMarkExecutable(void *start, size_t len)
+mprotectForLinker(void *start, size_t len, MemoryAccess mode)
{
DWORD old;
if (len == 0) {
return;
}
- if (VirtualProtect(start, len, PAGE_EXECUTE_READ, &old) == 0) {
- sysErrorBelch("mmapForLinkerMarkExecutable: failed to protect %zd bytes at %p",
- len, start);
+ DWORD prot;
+ switch (mode) {
+ case MEM_NO_ACCESS: prot = PAGE_NOACCESS; break;
+ case MEM_READ_ONLY: prot = PAGE_READONLY; break;
+ case MEM_READ_WRITE: prot = PAGE_READWRITE; break;
+ case MEM_READ_EXECUTE: prot = PAGE_EXECUTE_READ; break;
+ default: barf("invalid MemoryAccess");
+ }
+
+ if (VirtualProtect(start, len, prot, &old) == 0) {
+ sysErrorBelch("mprotectForLinker: failed to protect %zd bytes at %p as %s",
+ len, start, memoryAccessDescription(mode));
ASSERT(false);
}
}
@@ -1189,7 +1213,7 @@ void munmapForLinker (void *addr, size_t bytes, const char *caller)
*
* Consequently mmapForLinker now maps its memory with PROT_READ|PROT_WRITE.
* After the linker has finished filling/relocating the mapping it must then
- * call mmapForLinkerMarkExecutable on the sections of the mapping which
+ * call mprotectForLinker on the sections of the mapping which
* contain executable code.
*
* Note that the m32 allocator handles protection of its allocations. For this
@@ -1205,16 +1229,28 @@ void munmapForLinker (void *addr, size_t bytes, const char *caller)
* Mark an portion of a mapping previously reserved by mmapForLinker
* as executable (but not writable).
*/
-void mmapForLinkerMarkExecutable(void *start, size_t len)
+void mprotectForLinker(void *start, size_t len, MemoryAccess mode)
{
if (len == 0) {
return;
}
IF_DEBUG(linker_verbose,
- debugBelch("mmapForLinkerMarkExecutable: protecting %" FMT_Word
- " bytes starting at %p\n", (W_)len, start));
- if (mprotect(start, len, PROT_READ|PROT_EXEC) == -1) {
- barf("mmapForLinkerMarkExecutable: mprotect: %s\n", strerror(errno));
+ debugBelch("mprotectForLinker: protecting %" FMT_Word
+ " bytes starting at %p as %s\n",
+ (W_)len, start, memoryAccessDescription(mode)));
+
+ int prot;
+ switch (mode) {
+ case MEM_NO_ACCESS: prot = 0; break;
+ case MEM_READ_ONLY: prot = PROT_READ; break;
+ case MEM_READ_WRITE: prot = PROT_READ | PROT_WRITE; break;
+ case MEM_READ_EXECUTE: prot = PROT_READ | PROT_EXEC; break;
+ default: barf("invalid MemoryAccess");
+ }
+
+ if (mprotect(start, len, prot) == -1) {
+ sysErrorBelch("mprotectForLinker: failed to protect %zd bytes at %p as %s",
+ len, start, memoryAccessDescription(mode));
}
}
#endif
diff --git a/rts/LinkerInternals.h b/rts/LinkerInternals.h
index d2836310cb..af72ad587a 100644
--- a/rts/LinkerInternals.h
+++ b/rts/LinkerInternals.h
@@ -375,9 +375,17 @@ void exitLinker( void );
void freeObjectCode (ObjectCode *oc);
SymbolAddr* loadSymbol(SymbolName *lbl, RtsSymbolInfo *pinfo);
+/** Access modes for mprotectForLinker */
+typedef enum {
+ MEM_NO_ACCESS,
+ MEM_READ_ONLY,
+ MEM_READ_WRITE,
+ MEM_READ_EXECUTE,
+} MemoryAccess;
+
void *mmapAnonForLinker (size_t bytes);
void *mmapForLinker (size_t bytes, uint32_t prot, uint32_t flags, int fd, int offset);
-void mmapForLinkerMarkExecutable (void *start, size_t len);
+void mprotectForLinker(void *start, size_t len, MemoryAccess mode);
void munmapForLinker (void *addr, size_t bytes, const char *caller);
void addProddableBlock ( ObjectCode* oc, void* start, int size );
diff --git a/rts/linker/Elf.c b/rts/linker/Elf.c
index 76145dbbf4..10ac5d2896 100644
--- a/rts/linker/Elf.c
+++ b/rts/linker/Elf.c
@@ -1821,7 +1821,7 @@ ocMprotect_Elf( ObjectCode *oc )
if (section->alloc != SECTION_M32) {
// N.B. m32 handles protection of its allocations during
// flushing.
- mmapForLinkerMarkExecutable(section->mapped_start, section->mapped_size);
+ mprotectForLinker(section->mapped_start, section->mapped_size, MEM_READ_EXECUTE);
}
break;
default:
diff --git a/rts/linker/M32Alloc.c b/rts/linker/M32Alloc.c
index 6d42ea3599..c4496a7f7d 100644
--- a/rts/linker/M32Alloc.c
+++ b/rts/linker/M32Alloc.c
@@ -362,7 +362,7 @@ m32_allocator_flush(m32_allocator *alloc) {
while (page != NULL) {
struct m32_page_t *next = m32_filled_page_get_next(page);
m32_allocator_push_filled_list(&alloc->protected_list, page);
- mmapForLinkerMarkExecutable(page, page->filled_page.size);
+ mprotectForLinker(page, page->filled_page.size, MEM_READ_EXECUTE);
page = next;
}
alloc->unprotected_list = NULL;
diff --git a/rts/linker/MachO.c b/rts/linker/MachO.c
index 02f2a30605..79d14a2d55 100644
--- a/rts/linker/MachO.c
+++ b/rts/linker/MachO.c
@@ -1436,7 +1436,7 @@ ocMprotect_MachO( ObjectCode *oc )
if(segment->size == 0) continue;
if(segment->prot == SEGMENT_PROT_RX) {
- mmapForLinkerMarkExecutable(segment->start, segment->size);
+ mprotectForLinker(segment->start, segment->size, MEM_READ_EXECUTE);
}
}
@@ -1451,7 +1451,7 @@ ocMprotect_MachO( ObjectCode *oc )
if(section->alloc == SECTION_M32) continue;
switch (section->kind) {
case SECTIONKIND_CODE_OR_RODATA: {
- mmapForLinkerMarkExecutable(section->mapped_start, section->mapped_size);
+ mprotectForLinker(section->mapped_start, section->mapped_size, MEM_READ_EXECUTE);
break;
}
default:
diff --git a/rts/linker/SymbolExtras.c b/rts/linker/SymbolExtras.c
index ddb58e4a4e..5c04e9b3a8 100644
--- a/rts/linker/SymbolExtras.c
+++ b/rts/linker/SymbolExtras.c
@@ -142,7 +142,7 @@ void ocProtectExtras(ObjectCode* oc)
* non-executable.
*/
} else if (USE_CONTIGUOUS_MMAP || RtsFlags.MiscFlags.linkerAlwaysPic) {
- mmapForLinkerMarkExecutable(oc->symbol_extras, sizeof(SymbolExtra) * oc->n_symbol_extras);
+ mprotectForLinker(oc->symbol_extras, sizeof(SymbolExtra) * oc->n_symbol_extras, MEM_READ_EXECUTE);
} else {
/*
* The symbol extras were allocated via m32. They will be protected when