linker: never mark pages simultaneously writable / executable
When the Android dynamic linker handles a text relocation, it first relaxes the permissions on the segment being modified, performs the modifications, and then restores the page permissions. The relaxation worked by adding PROT_WRITE to whatever protection bits were set in the section. In effect, the pages were getting set to PROT_READ|PROT_WRITE|PROT_EXEC, modified, then restored to PROT_READ|PROT_EXEC The SELinux kernel code differentiates between 4 different kinds of executable memory: * Executable stack (execstack) * Executable heap (execheap) * File-based executable code which has been modified (execmod) * All other executable memory (execmem) The execmod capability is only triggered by the kernel when a dirty but non-executable mmap()ed page becomes executable. When that occurs, an SELinux policy check is done to see if the execmod capability is provided by policy. However, if the page is already executable, and PROT_WRITE is added to the page, it's considered an execmem permission check, not an execmod permission check. There are certain circumstances where we may want to distinguish between execmod and execmem. This change adjusts the dynamic linker to avoid using RWX pages, so that an RX -> RW -> RX transition will properly be detected as an execmod permission check instead of an execmem permission check. Bug: 20013628 Change-Id: I14d7be29170b156942f9809023f3b2fc1f37846c
This commit is contained in:
parent
ab7c79e22e
commit
8fdb3419a5
@ -429,9 +429,15 @@ static int _phdr_table_set_load_prot(const ElfW(Phdr)* phdr_table, size_t phdr_c
|
||||
ElfW(Addr) seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
|
||||
ElfW(Addr) seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
|
||||
|
||||
int prot = PFLAGS_TO_PROT(phdr->p_flags);
|
||||
if ((extra_prot_flags & PROT_WRITE) != 0) {
|
||||
// make sure we're never simultaneously writable / executable
|
||||
prot &= ~PROT_EXEC;
|
||||
}
|
||||
|
||||
int ret = mprotect(reinterpret_cast<void*>(seg_page_start),
|
||||
seg_page_end - seg_page_start,
|
||||
PFLAGS_TO_PROT(phdr->p_flags) | extra_prot_flags);
|
||||
prot | extra_prot_flags);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user