From e6252bfc3e5517301d370e393d7251faf97c9c9b Mon Sep 17 00:00:00 2001 From: Yuan <3051596481@qq.com> Date: Thu, 1 Oct 2026 03:50:02 +0800 Subject: [PATCH 1/2] Copy the contents of the ELF file used for symbol resolution into anonymous memory to avoid an additional mapping of the same ELF file in `/proc/self/maps`, thereby preventing certain applications from mistakenly identifying this read-only resolution mapping as the actual module load base address and crashing. --- native/src/elf/elf_image.cpp | 40 ++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/native/src/elf/elf_image.cpp b/native/src/elf/elf_image.cpp index fa5e22a14..21aad5081 100644 --- a/native/src/elf/elf_image.cpp +++ b/native/src/elf/elf_image.cpp @@ -48,18 +48,50 @@ ElfImage::ElfImage(std::string_view lib_name) : path_(lib_name) { base_ = nullptr; return; } - file_size_ = file_info.st_size; - file_map_ = mmap(nullptr, file_size_, PROT_READ, MAP_SHARED, fd, 0); - close(fd); + /* + * To avoid selecting a read-only ELF file mapping intended for symbol resolution + * when duplicate ELF file mappings appear in `/proc/self/maps`, attempts to use + * an anonymous memory mapping for the ELF file used in symbol resolution. + */ + file_size_ = file_info.st_size; + file_map_ = mmap(nullptr, file_size_, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (file_map_ == MAP_FAILED) { - PLOGE("mmap failed for {}", path_.c_str()); + PLOGE("Anonymous mmap failed for {}", path_.c_str()); file_map_ = nullptr; + close(fd); base_ = nullptr; return; } + size_t copied = 0; + while (copied < file_size_) { + const size_t remaining = file_size_ - copied; + const size_t chunk = + std::min(remaining, static_cast(std::numeric_limits::max())); + const ssize_t read_size = + pread(fd, static_cast(file_map_) + copied, chunk, + static_cast(copied)); + + if (read_size < 0 && errno == EINTR) continue; + if (read_size <= 0) { + if (read_size < 0) { + PLOGE("Failed to read ELF file: {}", path_.c_str()); + } else { + LOGE("Unexpected EOF while reading ELF file: {}", path_.c_str()); + } + close(fd); + munmap(file_map_, file_size_); + file_map_ = nullptr; + base_ = nullptr; + return; + } + copied += static_cast(read_size); + } + close(fd); + // The path is whatever the linker or the maps file named, which is not necessarily an ELF at // all (a library loaded straight out of an APK names the APK). parseHeaders() walks section // headers by offset and would read wild pointers, so check the magic before trusting it. From 12d00d6a9fe8983b51c7a814175feeca327d8585 Mon Sep 17 00:00:00 2001 From: Yuan <3051596481@qq.com> Date: Thu, 1 Oct 2026 03:57:36 +0800 Subject: [PATCH 2/2] Copy the contents of the ELF file used for symbol resolution into anonymous memory to avoid an additional mapping of the same ELF file in `/proc/self/maps`, thereby preventing certain applications from mistakenly identifying this read-only resolution mapping as the actual module load base address and crashing. --- native/src/elf/elf_image.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/native/src/elf/elf_image.cpp b/native/src/elf/elf_image.cpp index 21aad5081..e05be4a6e 100644 --- a/native/src/elf/elf_image.cpp +++ b/native/src/elf/elf_image.cpp @@ -92,6 +92,14 @@ ElfImage::ElfImage(std::string_view lib_name) : path_(lib_name) { } close(fd); + if (mprotect(file_map_, file_size_, PROT_READ) != 0) { + PLOGE("Failed to make ELF image read-only: {}", path_.c_str()); + munmap(file_map_, file_size_); + file_map_ = nullptr; + base_ = nullptr; + return; + } + // The path is whatever the linker or the maps file named, which is not necessarily an ELF at // all (a library loaded straight out of an APK names the APK). parseHeaders() walks section // headers by offset and would read wild pointers, so check the magic before trusting it.