Skip to content

Commit 5fe8a39

Browse files
committed
Fix mmap() failure with EPROT on CHERI
Issue ivmai#627 (bdwgc). It is essential for CHERI to have only address part in `last_addr` without metadata (thus the variable is of `word` type intentionally), otherwise `mmap()` fails setting `errno` to `EPROT`. * dyn_load.c [DYNAMIC_LOADING && !ANY_MSWIN && (USE_PROC_FOR_LIBRARIES && !LINUX || IRIX5)] (GC_register_dynamic_libraries): Do not use `ADDR()` for `HEAP_START`. * include/private/gcconfig.h [SOLARIS && USE_MMAP || I386 && (DGUX || LINUX) || MIPS && IRIX5 && USE_MMAP] (HEAP_START): Cast to `word` instead of use of `MAKE_CPTR()`. * include/private/gcconfig.h [SOLARIS && !USE_MMAP || MIPS && IRIX5 && !USE_MMAP] (HEAP_START): Use `ADDR()`. * include/private/gcconfig.h [!HEAP_START] (HEAP_START): Remove cast to `ptr_t`. * os_dep.c [NEED_UNIX_GET_MEM && MMAP_SUPPORTED && !MSWIN_XBOX1] (GC_unix_mmap_get_mem): Change type of `last_addr` from `ptr_t` to `word`; do not use `MAKE_CPTR()` for `last_addr`; add comment near `last_addr` usage; reduce length of abort message; do not align `(ptr_t)result+bytes` because `result` and `bytes` should be page-aligned; update `last_addr` value after checking that `result` is HBLKSIZE-aligned; add assertion that updated `last_addr` value is page-aligned.
1 parent 5fcc06d commit 5fe8a39

File tree

3 files changed

+16
-14
lines changed

3 files changed

+16
-14
lines changed

dyn_load.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -991,7 +991,7 @@ GC_register_dynamic_libraries(void)
991991
long flags;
992992
ptr_t start;
993993
ptr_t limit;
994-
word heap_start = ADDR(HEAP_START);
994+
word heap_start = HEAP_START;
995995
word heap_end = heap_start;
996996
# ifdef SOLARISDL
997997
# define MA_PHYS 0

include/private/gcconfig.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,9 +1102,9 @@ extern int _end[];
11021102
/* doesn't interact correctly with the system malloc. */
11031103
# endif
11041104
# ifdef USE_MMAP
1105-
# define HEAP_START MAKE_CPTR(0x40000000)
1105+
# define HEAP_START ((word)0x40000000)
11061106
# else
1107-
# define HEAP_START DATAEND
1107+
# define HEAP_START ADDR(DATAEND)
11081108
# endif
11091109
# ifndef GC_THREADS
11101110
# define MPROTECT_VDB
@@ -1447,12 +1447,12 @@ extern int _etext, _end;
14471447
# define USE_MMAP 1
14481448
# endif
14491449
# define MAP_FAILED (void *)((GC_uintptr_t)-1)
1450-
# define HEAP_START MAKE_CPTR(0x40000000)
1450+
# define HEAP_START ((word)0x40000000)
14511451
# endif /* DGUX */
14521452
# ifdef LINUX
14531453
/* This encourages mmap to give us low addresses, */
14541454
/* thus allowing the heap to grow to ~3 GB. */
1455-
# define HEAP_START MAKE_CPTR(0x1000)
1455+
# define HEAP_START ((word)0x1000)
14561456
# ifdef __ELF__
14571457
# if GC_GLIBC_PREREQ(2, 0) || defined(HOST_ANDROID)
14581458
# define SEARCH_FOR_DATA_START
@@ -1718,9 +1718,9 @@ extern int _fdata[];
17181718
/* there. In either case it is used to identify heap sections so */
17191719
/* they are not considered as roots. */
17201720
# ifdef USE_MMAP
1721-
# define HEAP_START MAKE_CPTR(0x30000000)
1721+
# define HEAP_START ((word)0x30000000)
17221722
# else
1723-
# define HEAP_START DATASTART
1723+
# define HEAP_START ADDR(DATASTART)
17241724
# endif
17251725
/* MPROTECT_VDB should work, but there is evidence of a breakage. */
17261726
# define DYNAMIC_LOADING
@@ -2992,7 +2992,7 @@ extern ptr_t GC_data_start;
29922992
#endif
29932993

29942994
#ifndef HEAP_START
2995-
# define HEAP_START ((ptr_t)0)
2995+
# define HEAP_START 0
29962996
#endif
29972997

29982998
#ifndef CLEAR_DOUBLE

os_dep.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2335,7 +2335,7 @@ STATIC void *
23352335
GC_unix_mmap_get_mem(size_t bytes)
23362336
{
23372337
void *result;
2338-
static ptr_t last_addr = HEAP_START;
2338+
static word last_addr = HEAP_START;
23392339

23402340
# ifndef USE_MMAP_ANON
23412341
static GC_bool initialized = FALSE;
@@ -2362,8 +2362,11 @@ GC_unix_mmap_get_mem(size_t bytes)
23622362
GC_ASSERT(GC_page_size != 0);
23632363
if (bytes & (GC_page_size - 1))
23642364
ABORT("Bad GET_MEM arg");
2365+
/* Note: it is essential for CHERI to have only address part in */
2366+
/* last_addr without metadata (thus the variable is of word type */
2367+
/* intentionally), otherwise mmap() fails setting errno to EPROT. */
23652368
result
2366-
= mmap(last_addr, bytes,
2369+
= mmap(MAKE_CPTR(last_addr), bytes,
23672370
(PROT_READ | PROT_WRITE) | (GC_pages_executable ? PROT_EXEC : 0),
23682371
GC_MMAP_FLAGS | OPT_MAP_ANON, zero_fd, 0 /* offset */);
23692372
# undef IGNORE_PAGES_EXECUTABLE
@@ -2387,11 +2390,10 @@ GC_unix_mmap_get_mem(size_t bytes)
23872390
return GC_unix_mmap_get_mem(bytes);
23882391
}
23892392
# endif
2390-
last_addr = PTR_ALIGN_UP((ptr_t)result + bytes, GC_page_size);
2391-
23922393
if ((ADDR(result) % HBLKSIZE) != 0)
2393-
ABORT("GC_unix_get_mem: Memory returned by mmap is not aligned to "
2394-
"HBLKSIZE.");
2394+
ABORT("Memory returned by mmap is not aligned to HBLKSIZE");
2395+
last_addr = ADDR(result) + bytes;
2396+
GC_ASSERT((last_addr & (GC_page_size - 1)) == 0);
23952397
return result;
23962398
}
23972399
# endif /* !MSWIN_XBOX1 */

0 commit comments

Comments
 (0)