22
33#include " Monkeypatcher.h"
44
5+ #include < elf.h>
56#include < limits.h>
67#include < linux/auxvec.h>
78
@@ -1423,9 +1424,8 @@ void patch_after_exec_arch<X64Arch>(RecordTask* t, Monkeypatcher& patcher) {
14231424
14241425 for (const auto & m : t->vm ()->maps ()) {
14251426 auto & km = m.map ;
1426- patcher.patch_after_mmap (t, km.start (), km.size (),
1427- km.file_offset_bytes (), -1 ,
1428- Monkeypatcher::MMAP_EXEC);
1427+ patcher.patch_after_mmap (t, km.start (), km.size (), km.file_offset_bytes (),
1428+ km.prot (), -1 , Monkeypatcher::MMAP_EXEC);
14291429 }
14301430
14311431 if (!t->vm ()->has_vdso ()) {
@@ -1443,9 +1443,8 @@ void patch_after_exec_arch<ARM64Arch>(RecordTask* t, Monkeypatcher& patcher) {
14431443
14441444 for (const auto & m : t->vm ()->maps ()) {
14451445 auto & km = m.map ;
1446- patcher.patch_after_mmap (t, km.start (), km.size (),
1447- km.file_offset_bytes (), -1 ,
1448- Monkeypatcher::MMAP_EXEC);
1446+ patcher.patch_after_mmap (t, km.start (), km.size (), km.file_offset_bytes (),
1447+ km.prot (), -1 , Monkeypatcher::MMAP_EXEC);
14491448 }
14501449
14511450 if (!t->vm ()->has_vdso ()) {
@@ -1498,27 +1497,46 @@ void Monkeypatcher::patch_at_preload_init(RecordTask* t) {
14981497
14991498static remote_ptr<void > resolve_address (ElfReader& reader, uintptr_t elf_addr,
15001499 remote_ptr<void > map_start,
1501- size_t map_size,
1502- uintptr_t map_offset ) {
1503- uintptr_t file_offset ;
1504- if (!reader.addr_to_offset (elf_addr, file_offset )) {
1500+ size_t map_size, uintptr_t map_offset,
1501+ uint64_t prot ) {
1502+ PhdrInfo phdr ;
1503+ if (!reader.addr_to_phdr (elf_addr, phdr )) {
15051504 LOG (warn) << " ELF address " << HEX (elf_addr) << " not in file" ;
15061505 }
1507- if (file_offset < map_offset || file_offset + 32 > map_offset + map_size) {
1508- // The value(s) to be set are outside the mapped range. This happens
1509- // because code and data can be mapped in separate, partial mmaps in which
1510- // case some symbols will be outside the mapped range.
1506+ if (phdr.offset < map_offset ||
1507+ phdr.offset + phdr.filesz > map_offset + map_size ||
1508+ bool (phdr.flags & PF_R) != bool (prot & PROT_READ) ||
1509+ bool (phdr.flags & PF_W) != bool (prot & PROT_WRITE) ||
1510+ bool (phdr.flags & PF_X) != bool (prot & PROT_EXEC)) {
1511+ // The value(s) to be set are outside the mapped range or belong to another
1512+ // mapping as indicated by the flags. This happens because code and data can
1513+ // be mapped in separate, partial mmaps in which case some symbols will be
1514+ // outside the mapped range.
15111515 return nullptr ;
15121516 }
1513- return map_start + uintptr_t (file_offset - map_offset);
1517+
1518+ // This is the distance from the file offset of the mapping to p_offset, which
1519+ // is the same as the distance from map_start to p_vaddr + load bias.
1520+ auto page_start_offset = phdr.offset - map_offset;
1521+
1522+ // Adjust map_start so that it points to p_vaddr + load bias.
1523+ map_start += page_start_offset;
1524+
1525+ // Now subtract p_vaddr to make it point to virtual address 0 (the load bias).
1526+ map_start -= phdr.vaddr ;
1527+
1528+ // Finally, add the address from the symbol table to adjust it by the load
1529+ // bias.
1530+ return map_start + elf_addr;
15141531}
15151532
15161533static void set_and_record_bytes (RecordTask* t, ElfReader& reader,
15171534 uintptr_t elf_addr, const void * bytes,
15181535 size_t size, remote_ptr<void > map_start,
1519- size_t map_size, size_t map_offset) {
1536+ size_t map_size, size_t map_offset,
1537+ uint64_t prot) {
15201538 remote_ptr<void > addr =
1521- resolve_address (reader, elf_addr, map_start, map_size, map_offset);
1539+ resolve_address (reader, elf_addr, map_start, map_size, map_offset, prot );
15221540 if (!addr) {
15231541 return ;
15241542 }
@@ -1539,13 +1557,13 @@ static void set_and_record_bytes(RecordTask* t, ElfReader& reader,
15391557void Monkeypatcher::patch_dl_runtime_resolve (RecordTask* t, ElfReader& reader,
15401558 uintptr_t elf_addr,
15411559 remote_ptr<void > map_start,
1542- size_t map_size,
1543- size_t map_offset ) {
1560+ size_t map_size, size_t map_offset,
1561+ uint64_t prot ) {
15441562 if (t->arch () != x86_64) {
15451563 return ;
15461564 }
15471565 remote_ptr<void > addr =
1548- resolve_address (reader, elf_addr, map_start, map_size, map_offset);
1566+ resolve_address (reader, elf_addr, map_start, map_size, map_offset, prot );
15491567 if (!addr) {
15501568 return ;
15511569 }
@@ -1641,14 +1659,13 @@ static bool is_aarch64_ldrb(uint32_t instruction, uint32_t* offset) {
16411659 * Patch the __aarch64_have_lse_atomics variable to ensure that LSE atomics are
16421660 * always used even if init_lse_atomics
16431661 */
1644- void Monkeypatcher::patch_aarch64_have_lse_atomics (RecordTask* t, ElfReader& reader,
1645- uintptr_t ldadd4_addr,
1646- remote_ptr<void > map_start,
1647- size_t map_size,
1648- size_t map_offset) {
1662+ void Monkeypatcher::patch_aarch64_have_lse_atomics (
1663+ RecordTask* t, ElfReader& reader, uintptr_t ldadd4_addr,
1664+ remote_ptr<void > map_start, size_t map_size, size_t map_offset,
1665+ uint64_t prot) {
16491666 ASSERT (t, t->arch () == aarch64);
16501667 remote_ptr<void > addr =
1651- resolve_address (reader, ldadd4_addr, map_start, map_size, map_offset);
1668+ resolve_address (reader, ldadd4_addr, map_start, map_size, map_offset, prot );
16521669 if (!addr) {
16531670 return ;
16541671 }
@@ -1694,7 +1711,7 @@ static bool file_may_need_instrumentation(const AddressSpace::Mapping& map) {
16941711}
16951712
16961713void Monkeypatcher::patch_after_mmap (RecordTask* t, remote_ptr<void > start,
1697- size_t size, size_t offset_bytes,
1714+ size_t size, size_t offset_bytes, uint64_t prot,
16981715 int child_fd, MmapMode mode) {
16991716 const auto & map = t->vm ()->mapping_of (start);
17001717 if (!file_may_need_instrumentation (map)) {
@@ -1747,7 +1764,7 @@ void Monkeypatcher::patch_after_mmap(RecordTask* t, remote_ptr<void> start,
17471764 // pthread rwlocks don't try to use elision at all. See ELIDE_LOCK
17481765 // in glibc's elide.h.
17491766 set_and_record_bytes (t, reader, syms.addr (i) + 8 , &zero, sizeof (zero),
1750- start, size, offset_bytes);
1767+ start, size, offset_bytes, prot );
17511768 }
17521769 if (syms.is_name (i, " elision_init" )) {
17531770 // Make elision_init return without doing anything. This means
@@ -1756,7 +1773,7 @@ void Monkeypatcher::patch_after_mmap(RecordTask* t, remote_ptr<void> start,
17561773 // elision-conf.c.
17571774 static const uint8_t ret = 0xC3 ;
17581775 set_and_record_bytes (t, reader, syms.addr (i), &ret, sizeof (ret), start,
1759- size, offset_bytes);
1776+ size, offset_bytes, prot );
17601777 }
17611778 // The following operations can only be applied once because after the
17621779 // patch is applied the code no longer matches the expected template.
@@ -1768,15 +1785,15 @@ void Monkeypatcher::patch_after_mmap(RecordTask* t, remote_ptr<void> start,
17681785 syms.is_name (i, " _dl_runtime_resolve_xsave" ) ||
17691786 syms.is_name (i, " _dl_runtime_resolve_xsavec" ))) {
17701787 patch_dl_runtime_resolve (t, reader, syms.addr (i), start, size,
1771- offset_bytes);
1788+ offset_bytes, prot );
17721789 }
17731790 }
17741791 break ;
17751792 case aarch64:
17761793 for (size_t i = 0 ; i < syms.size (); ++i) {
17771794 if (syms.is_name (i, " __aarch64_ldadd4_relax" )) {
17781795 patch_aarch64_have_lse_atomics (t, reader, syms.addr (i), start, size,
1779- offset_bytes);
1796+ offset_bytes, prot );
17801797 }
17811798 }
17821799 break ;
0 commit comments