Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 120967f

Browse files
committed
Make some parts of _zend_mm_heap read-only at runtime.
As [presented at OffensiveCon 2024](https://youtu.be/dqKFHjcK9hM?t=1622), having trivially callable writeable function pointers at the top of the heap makes it straightforward to turn a limited write into an arbitrary code execution. Disabling ZEND_MM_HEAP by default isn't doable, as it's used by a couple of profilers, so we're making some parts of `_zend_mm_heap` read-only at runtime instead: this will prevent the custom heap functions pointers from being hijacked, and we're also throwing the `shadow_key` there as it doesn't hurt to make it read-only as well.
1 parent 37488d6 commit 120967f

File tree

1 file changed

+19
-6
lines changed

1 file changed

+19
-6
lines changed

‎Zend/zend_alloc.c‎

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,20 @@ static bool zend_mm_use_huge_pages = false;
296296
*/
297297

298298
struct _zend_mm_heap {
299+
union { /* This union contains security-relevant properties, and is thus made read-only at run-time. */
300+
struct {
301+
uintptr_t shadow_key; /* free slot shadow ptr xor key */
302+
#if ZEND_MM_CUSTOM
303+
struct {
304+
void *(*_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
305+
void (*_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
306+
void *(*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
307+
} custom_heap;
308+
#endif
309+
};
310+
char padding [ZEND_MM_PAGE_SIZE];
311+
};
312+
299313
#if ZEND_MM_CUSTOM
300314
int use_custom_heap;
301315
#endif
@@ -306,7 +320,6 @@ struct _zend_mm_heap {
306320
size_t size; /* current memory usage */
307321
size_t peak; /* peak memory usage */
308322
#endif
309-
uintptr_t shadow_key; /* free slot shadow ptr xor key */
310323
zend_mm_free_slot *free_slot[ZEND_MM_BINS]; /* free lists for small sizes */
311324
#if ZEND_MM_STAT || ZEND_MM_LIMIT
312325
size_t real_size; /* current size of allocated pages */
@@ -330,11 +343,6 @@ struct _zend_mm_heap {
330343
int last_chunks_delete_boundary; /* number of chunks after last deletion */
331344
int last_chunks_delete_count; /* number of deletion over the last boundary */
332345
#if ZEND_MM_CUSTOM
333-
struct {
334-
void *(*_malloc)(size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
335-
void (*_free)(void* ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
336-
void *(*_realloc)(void*, size_t ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
337-
} custom_heap;
338346
HashTable *tracked_allocs;
339347
#endif
340348
pid_t pid;
@@ -2103,6 +2111,9 @@ static zend_mm_heap *zend_mm_init(void)
21032111
#endif
21042112
heap->huge_list = NULL;
21052113
heap->pid = getpid();
2114+
2115+
mprotect(heap, ZEND_MM_PAGE_SIZE, PROT_READ);
2116+
21062117
return heap;
21072118
}
21082119

@@ -3141,6 +3152,7 @@ ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
31413152
#if ZEND_MM_CUSTOM
31423153
zend_mm_heap *_heap = (zend_mm_heap*)heap;
31433154

3155+
mprotect(heap, ZEND_MM_PAGE_SIZE, PROT_WRITE);
31443156
if (!_malloc && !_free && !_realloc) {
31453157
_heap->use_custom_heap = ZEND_MM_CUSTOM_HEAP_NONE;
31463158
} else {
@@ -3149,6 +3161,7 @@ ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
31493161
_heap->custom_heap._free = _free;
31503162
_heap->custom_heap._realloc = _realloc;
31513163
}
3164+
mprotect(heap, ZEND_MM_PAGE_SIZE, PROT_READ);
31523165
#endif
31533166
}
31543167

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /