diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f70193e3..d1b711bde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Native: clean up stale envelopes after crashes with `SENTRY_TRANSPORT=none`. ([#2049](https://github.com/getsentry/sentry-native/pull/2049)) - `sentry_set_trace` omits `parent_span_id` when the caller does not provide one, instead of serializing it as `null`. ([#2047](https://github.com/getsentry/sentry-native/pull/2047)) - Native/Linux i386: write valid thread stack descriptors to minidumps when stack addresses use the upper half of the 32-bit address space. ([#2054](https://github.com/getsentry/sentry-native/pull/2054)) +- Native/Linux: cap ELF metadata section reads when resolving module SONAMEs. ([#2066](https://github.com/getsentry/sentry-native/pull/2066)) - Linux/ARM32: fix builds on 32-bit ARM systems, including 32-bit Raspberry Pi OS installations running a 64-bit kernel. ([#2063](https://github.com/getsentry/sentry-native/pull/2063)) - Guard size arithmetic when parsing envelopes and Linux OS release data, copying slices, and allocating memory during crash handling. ([#2059](https://github.com/getsentry/sentry-native/pull/2059)) diff --git a/src/backends/native/minidump/sentry_minidump_linux.c b/src/backends/native/minidump/sentry_minidump_linux.c index 1011b60a6..753a1939d 100644 --- a/src/backends/native/minidump/sentry_minidump_linux.c +++ b/src/backends/native/minidump/sentry_minidump_linux.c @@ -1123,45 +1123,25 @@ read_elf_soname(const char *elf_path, char *soname_buf, size_t soname_buf_size) } // Read .dynstr - size_t dynstr_size = dynstr_shdr->sh_size; - if (dynstr_size > 1024 * 1024) { // Sanity: max 1MB - sentry_free(shdr_buf); - close(fd); - return false; - } - char *dynstr = sentry_malloc(dynstr_size); + char *dynstr = sentry__elf_read_metadata_section( + fd, dynstr_shdr->sh_offset, dynstr_shdr->sh_size); if (!dynstr) { sentry_free(shdr_buf); close(fd); return false; } - if (lseek(fd, dynstr_shdr->sh_offset, SEEK_SET) - != (off_t)dynstr_shdr->sh_offset - || read(fd, dynstr, dynstr_size) != (ssize_t)dynstr_size) { - sentry_free(dynstr); - sentry_free(shdr_buf); - close(fd); - return false; - } + size_t dynstr_size = (size_t)dynstr_shdr->sh_size; // Read .dynamic entries and find DT_SONAME - size_t dyn_size = dynamic_shdr->sh_size; - void *dyn_buf = sentry_malloc(dyn_size); + void *dyn_buf = sentry__elf_read_metadata_section( + fd, dynamic_shdr->sh_offset, dynamic_shdr->sh_size); if (!dyn_buf) { sentry_free(dynstr); sentry_free(shdr_buf); close(fd); return false; } - if (lseek(fd, dynamic_shdr->sh_offset, SEEK_SET) - != (off_t)dynamic_shdr->sh_offset - || read(fd, dyn_buf, dyn_size) != (ssize_t)dyn_size) { - sentry_free(dyn_buf); - sentry_free(dynstr); - sentry_free(shdr_buf); - close(fd); - return false; - } + size_t dyn_size = (size_t)dynamic_shdr->sh_size; DynT *dyn_entries = (DynT *)dyn_buf; size_t dyn_count = dyn_size / sizeof(DynT); diff --git a/src/sentry_elf.h b/src/sentry_elf.h index cc02022a6..bb80d3f01 100644 --- a/src/sentry_elf.h +++ b/src/sentry_elf.h @@ -108,6 +108,34 @@ sentry__elf_has_phdr_size( # endif } +# define SENTRY_ELF_MAX_METADATA_SECTION_SIZE (1024 * 1024) + +static inline void * +sentry__elf_read_metadata_section(int fd, uint64_t offset, uint64_t size) +{ + if (size == 0 || size > SENTRY_ELF_MAX_METADATA_SECTION_SIZE) { + return NULL; + } + + off_t file_offset = (off_t)offset; + if (file_offset < 0 || (uint64_t)file_offset != offset) { + return NULL; + } + + size_t len = (size_t)size; + void *buf = sentry_malloc(len); + if (!buf) { + return NULL; + } + + if (lseek(fd, file_offset, SEEK_SET) != file_offset + || read(fd, buf, len) != (ssize_t)len) { + sentry_free(buf); + return NULL; + } + return buf; +} + /** * Safely iterate ELF notes in a buffer to find one matching the given type * and name. Alignment must be 4 or 8 (per ELF spec, PT_NOTE uses p_align, diff --git a/tests/unit/test_modulefinder.c b/tests/unit/test_modulefinder.c index cd16a45ac..c48538f80 100644 --- a/tests/unit/test_modulefinder.c +++ b/tests/unit/test_modulefinder.c @@ -84,6 +84,30 @@ SENTRY_TEST(module_addr) #endif } +SENTRY_TEST(elf_metadata_section) +{ +#if !defined(SENTRY_PLATFORM_LINUX) || defined(SENTRY_PLATFORM_ANDROID) + SKIP_TEST(); +#else + char tmp_path[] = "/tmp/sentry-native-elf-section-XXXXXX"; + int fd = mkstemp(tmp_path); + TEST_ASSERT(fd >= 0); + TEST_ASSERT(write(fd, "test", 4) == 4); + + char *buf = sentry__elf_read_metadata_section(fd, 1, 3); + TEST_ASSERT(!!buf); + TEST_CHECK(memcmp(buf, "est", 3) == 0); + sentry_free(buf); + + TEST_CHECK(!sentry__elf_read_metadata_section( + fd, 0, SENTRY_ELF_MAX_METADATA_SECTION_SIZE + 1)); + TEST_CHECK(!sentry__elf_read_metadata_section(fd, UINT64_MAX, 1)); + + close(fd); + unlink(tmp_path); +#endif +} + SENTRY_TEST(mmap_file_closes_fd_zero_on_failure) { #if !defined(SENTRY_PLATFORM_LINUX) || defined(SENTRY_PLATFORM_ANDROID) diff --git a/tests/unit/tests.inc b/tests/unit/tests.inc index 78ad34542..824411f05 100644 --- a/tests/unit/tests.inc +++ b/tests/unit/tests.inc @@ -168,6 +168,7 @@ XX(dsn_without_url_scheme_is_invalid) XX(effective_org_id_resolution) XX(elf_find_note) XX(elf_header_entry_sizes) +XX(elf_metadata_section) XX(elf_rejects_non_regular_files) XX(embedded_info_basic) XX(embedded_info_build_id)