Reputation: 6031
I would like to grant full permissions (read, write, and execute) to all memory pages in an ELF binary. Ideally, I'd like to be able to do this as a transformation on a binary or object file, in the same way that symbols can be changed with objcopy
. I have not yet found a good way to do this. I would also be okay with a solution that involves running code at startup that calls mprotect
on every page with the flags PROT_READ | PROT_WRITE | PROT_EXEC
. I've tried this briefly, but I haven't found a good way to know which pages are mapped, and therefore which pages need to be mprotect
ed.
It isn't required that dynamically allocated pages have all permissions, only the pages mapped at program startup.
Upvotes: 3
Views: 1738
Reputation: 56
The following script implements Employed Russian's answer in code:
p_type
of the RELRO
segment to PT_NULL
Flags
on LOAD
segments to PF_X|PF_W|PF_R
.It depends on pyelftools
for python3
, which can be installed with pip3 install pyelftools
.
#!/usr/bin/env python3
import sys
from elftools.elf.elffile import ELFFile
from elftools.elf.descriptions import describe_p_type
if len(sys.argv) != 2:
print("Usage: elf_rwe <elf>")
name = sys.argv[1]
with open(name, "rb") as f:
elf = ELFFile(f)
rwe_offsets = []
relro_offsets = []
for i in range(elf['e_phnum']):
program_offset = elf['e_phoff'] + i * elf['e_phentsize']
f.seek(program_offset)
program_header = elf.structs.Elf_Phdr.parse_stream(f)
if program_header['p_type'] == "PT_LOAD":
rwe_offsets.append(program_offset)
if program_header['p_type'] == "PT_GNU_RELRO":
relro_offsets.append(program_offset)
f.seek(0)
b = list(f.read())
# Zap RELRO
pt_null = 0
for off in relro_offsets:
b[off] = pt_null
# Fix permissions
p_flags_offset = 4
for off in rwe_offsets:
b[off + p_flags_offset] = 0x7 # PF_X|PF_W|PF_R
with open(name, "wb") as f:
f.write(bytes(b))
Upvotes: 4
Reputation: 213754
I would like to grant full permissions (read, write, and execute) to all memory pages in an ELF binary.
Note that some security policies, such as W^X
in selinux will prevent your binary from running.
Ideally, I'd like to be able to do this as a transformation on a binary or object file
Run readelf -Wl
on your binary. You'll see something similar to:
$ readelf -Wl /bin/date
Elf file type is EXEC (Executable file)
Entry point 0x4021cf
There are 9 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000040 0x0000000000400040 0x0000000000400040 0x0001f8 0x0001f8 R E 0x8
INTERP 0x000238 0x0000000000400238 0x0000000000400238 0x00001c 0x00001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x00dde4 0x00dde4 R E 0x200000
LOAD 0x00de10 0x000000000060de10 0x000000000060de10 0x0004e4 0x0006b0 RW 0x200000
DYNAMIC 0x00de28 0x000000000060de28 0x000000000060de28 0x0001d0 0x0001d0 RW 0x8
NOTE 0x000254 0x0000000000400254 0x0000000000400254 0x000044 0x000044 R 0x4
GNU_EH_FRAME 0x00cb8c 0x000000000040cb8c 0x000000000040cb8c 0x0002f4 0x0002f4 R 0x4
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
GNU_RELRO 0x00de10 0x000000000060de10 0x000000000060de10 0x0001f0 0x0001f0 R 0x1
What you want to do then is to change Flags
on LOAD
segments to have PF_X|PF_W|PF_R
. The flags are part of Elf{32,64}_Phdr
table, and the offset to the table is in stored in e_phoff
of the Elf{32,64}_Ehdr
(which is stored at the start of every ELF file).
Look in /usr/include/elf.h
. Parsing fixed-sized ELF structures involved here isn't complicated.
You are unlikely to find any standard tool that would do this for you (given that this is such an unusual and unsecure thing to do), but a program to change flags is trivial to write in C
, Python
or Perl
.
P.S. You may also need to "zap" the RELRO
segment, which could be done by changing its p_type
to PT_NULL
.
I haven't found a good way to know which pages are mapped, and therefore which pages need to be
mprotected
.
On Linux, you could parse /proc/self/maps
to get that info. Other OSes may offer a different way to achieve the same.
Upvotes: 4