【问题标题】:memset/memcpy on mmap region failsmmap 区域上的 memset/memcpy 失败
【发布时间】:2019-04-06 18:21:01
【问题描述】:

我正在尝试从另一个程序加载 静态链接 程序并执行它。我的步骤是:

  • 解析 ELF
  • 从程序头解析段
  • 对于每个 PT_LOAD
  • 加载它
  • 跳转到起始地址

如果elf_bytes是mmap的ELF文件,加载一个PT_LOAD段是load(&p, elf_bytes + p.p_offset)

加载函数:

int load(const Elf64_Phdr *phdr, const void *elf_bytes_for_phdr) {
    fprintf(stderr, "loading phdr of type %x from 0x%x to +=%zu bytes\n", phdr->p_type, phdr->p_vaddr, phdr->p_memsz);
    const size_t pagesize = getpagesize();
    const size_t unaligned_bytes = phdr->p_vaddr % pagesize;

    void *base_addr = phdr->p_vaddr - unaligned_bytes;
    size_t total_bytes = phdr->p_memsz + unaligned_bytes;

    void *region = mmap(
            base_addr,
            total_bytes,
            phdr->p_flags,
            MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
            0, 0
    );
    if (region != MAP_FAILED) {
        memset(region, 0, unaligned_bytes);
        // return memcpy(region + unaligned_bytes, elf_bytes_for_phdr, phdr->p_filesz) == region + unaligned_bytes;
        return memset(region + unaligned_bytes, /*elf_bytes_for_phdr*/0, 1) == region + unaligned_bytes;
    }
    return 1;
}

memset 和 memcpy 都失败了;内核在地址 0x400000 发送一个 SIGSEGV,恰好是region。 那里什么都没有:

gdb$ shell pmap 10751
00007ff000000000      8K r-x-- ld_simple_loader
00007ff000201000      4K r---- ld_simple_loader
00007ff000202000      4K rw--- ld_simple_loader
00007ffff79e4000   1948K r-x-- libc-2.27.so
00007ffff7bcb000   2048K ----- libc-2.27.so
00007ffff7dcb000     16K r---- libc-2.27.so
00007ffff7dcf000      8K rw--- libc-2.27.so
00007ffff7dd1000     16K rw---   [ anon ]
00007ffff7dd5000    156K r-x-- ld-2.27.so
00007ffff7fdc000      8K rw---   [ anon ]
00007ffff7ff7000     12K r----   [ anon ]
00007ffff7ffa000      8K r-x--   [ anon ]
00007ffff7ffc000      4K r---- ld-2.27.so
00007ffff7ffd000      4K rw--- ld-2.27.so
00007ffff7ffe000      4K rw---   [ anon ]
00007ffffffde000    132K rw---   [ stack ]
ffffffffff600000      4K r-x--   [ anon ]
 total             4384K

因为加载器从一个非常高的地址开始(实际上是为了避免这个问题)。这通过与-Wl,-Ttext-segment=00007ff000000000 链接。

(我也尝试过首先对该区域进行 munmap 映射。)

【问题讨论】:

标签: c linux elf mmap


【解决方案1】:
void *region = mmap(
        base_addr,
        total_bytes,
        phdr->p_flags,
        MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
        0, 0
);

mmap的第一段通常覆盖.text并拥有R-X(但没有)权限。

如果没有 .p_flags 中的 write 权限,写入该内存的尝试(自然)会失败。

您可能想改用phdr->p_flags | PROT_WRITE

注意:某些安全策略(例如 SELinux)不允许可写和可执行的映射。在这样的系统上,您需要使用PROT_WRITE 映射内存,根据需要复制数据,然后使用所需的保护mprotect

【讨论】:

    猜你喜欢
    • 2018-04-25
    • 1970-01-01
    • 2010-12-04
    • 1970-01-01
    • 2020-09-20
    • 1970-01-01
    • 1970-01-01
    • 2015-02-01
    • 1970-01-01
    相关资源
    最近更新 更多