From 362e7d7865ae90ee2fb08f9a11a7bc38362994e0 Mon Sep 17 00:00:00 2001 From: Derek Bruening Date: Mon, 22 Jun 2026 20:21:53 -0400 Subject: [PATCH 1/3] i#7962: Fix elfutils crash Fixes a crash where elfutils tries to un-compress in-place onto read-only memory by changing drsyms for UNIX to mmap as copy-on-write. This should have no extra cost when the mapping are never written. Tested on a local Linux distro where 16 tests crash without the fix and work with the fix. Fixes #7962 --- ext/drsyms/drsyms_unix_common.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/ext/drsyms/drsyms_unix_common.c b/ext/drsyms/drsyms_unix_common.c index d2530f89da..d3ab876145 100644 --- a/ext/drsyms/drsyms_unix_common.c +++ b/ext/drsyms/drsyms_unix_common.c @@ -1,5 +1,5 @@ /* ********************************************************** - * Copyright (c) 2011-2025 Google, Inc. All rights reserved. + * Copyright (c) 2011-2026 Google, Inc. All rights reserved. * **********************************************************/ /* @@ -130,8 +130,12 @@ load_module(const char *modpath) mod->file_size = (size_t)file_size; /* XXX: ignoring truncation */ mod->map_size = mod->file_size; + /* Map as copy-on-write so that elfutils can directly write for cases like + * compressed sections. This avoids requiring a separate allocation (and + * patching elfutils to support that use case). + */ mod->map_base = - dr_map_file(mod->fd, &mod->map_size, 0, NULL, DR_MEMPROT_READ, DR_MAP_PRIVATE); + dr_map_file(mod->fd, &mod->map_size, 0, NULL, DR_MEMPROT_WRITE, DR_MAP_PRIVATE); /* map_size can be larger than file_size */ if (mod->map_base == NULL || mod->map_size < mod->file_size) { NOTIFY("%s: unable to map %s\n", __FUNCTION__, modpath); @@ -191,14 +195,15 @@ load_module(const char *modpath) dwarf_lib_handle_t dbg; /* If there is no .gnu_debuglink, initialize parsing. */ #ifdef WINDOWS - /* i#1395: support switching to expots-only for MinGW, for which we + /* i#1395: support switching to exports-only for MinGW, for which we * need an image mapping. We don't need the file mapping anymore. */ if (drsym_obj_remap_as_image(mod->obj_info)) { dr_unmap_file(mod->map_base, mod->map_size); mod->map_size = 0; - mod->map_base = dr_map_file(mod->fd, &mod->map_size, 0, NULL, DR_MEMPROT_READ, - DR_MAP_PRIVATE | DR_MAP_IMAGE); + /* As above, map as copy-on-write. */ + mod->map_base = dr_map_file(mod->fd, &mod->map_size, 0, NULL, + DR_MEMPROT_WRITE, DR_MAP_PRIVATE | DR_MAP_IMAGE); if (mod->map_base == NULL || mod->map_size < mod->file_size) { NOTIFY("%s: unable to map %s\n", __FUNCTION__, modpath); goto error; From 318d9e41f3c678f715fc76d42ce29c743c21467e Mon Sep 17 00:00:00 2001 From: Derek Bruening Date: Mon, 22 Jun 2026 21:04:11 -0400 Subject: [PATCH 2/3] Do not map writable on Windows --- ext/drsyms/drsyms_unix_common.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ext/drsyms/drsyms_unix_common.c b/ext/drsyms/drsyms_unix_common.c index d3ab876145..c7fb184639 100644 --- a/ext/drsyms/drsyms_unix_common.c +++ b/ext/drsyms/drsyms_unix_common.c @@ -130,12 +130,16 @@ load_module(const char *modpath) mod->file_size = (size_t)file_size; /* XXX: ignoring truncation */ mod->map_size = mod->file_size; + int map_prot = DR_MEMPROT_READ; +#ifndef WINDOWS /* Map as copy-on-write so that elfutils can directly write for cases like * compressed sections. This avoids requiring a separate allocation (and * patching elfutils to support that use case). */ + map_prot = DR_MEMPROT_WRITE; +#endif mod->map_base = - dr_map_file(mod->fd, &mod->map_size, 0, NULL, DR_MEMPROT_WRITE, DR_MAP_PRIVATE); + dr_map_file(mod->fd, &mod->map_size, 0, NULL, map_prot, DR_MAP_PRIVATE); /* map_size can be larger than file_size */ if (mod->map_base == NULL || mod->map_size < mod->file_size) { NOTIFY("%s: unable to map %s\n", __FUNCTION__, modpath); @@ -201,9 +205,8 @@ load_module(const char *modpath) if (drsym_obj_remap_as_image(mod->obj_info)) { dr_unmap_file(mod->map_base, mod->map_size); mod->map_size = 0; - /* As above, map as copy-on-write. */ - mod->map_base = dr_map_file(mod->fd, &mod->map_size, 0, NULL, - DR_MEMPROT_WRITE, DR_MAP_PRIVATE | DR_MAP_IMAGE); + mod->map_base = dr_map_file(mod->fd, &mod->map_size, 0, NULL, map_prot, + DR_MAP_PRIVATE | DR_MAP_IMAGE); if (mod->map_base == NULL || mod->map_size < mod->file_size) { NOTIFY("%s: unable to map %s\n", __FUNCTION__, modpath); goto error; From f8ba887b1b01d8a6c6f5863c37306f924fee7860 Mon Sep 17 00:00:00 2001 From: Derek Bruening Date: Mon, 22 Jun 2026 23:51:16 -0400 Subject: [PATCH 3/3] Preserve read permission when adding write --- ext/drsyms/drsyms_unix_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/drsyms/drsyms_unix_common.c b/ext/drsyms/drsyms_unix_common.c index c7fb184639..84b8194f8b 100644 --- a/ext/drsyms/drsyms_unix_common.c +++ b/ext/drsyms/drsyms_unix_common.c @@ -136,7 +136,7 @@ load_module(const char *modpath) * compressed sections. This avoids requiring a separate allocation (and * patching elfutils to support that use case). */ - map_prot = DR_MEMPROT_WRITE; + map_prot |= DR_MEMPROT_WRITE; #endif mod->map_base = dr_map_file(mod->fd, &mod->map_size, 0, NULL, map_prot, DR_MAP_PRIVATE);