diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
index f072e97..61e46fc 100644
--- a/arch/powerpc/include/asm/page.h
+++ b/arch/powerpc/include/asm/page.h
@@ -215,15 +215,7 @@ extern long long virt_phys_offset;
#define __pa(x) ((unsigned long)(x) - PAGE_OFFSET + MEMORY_START)
#endif
-/*
- * Unfortunately the PLT is in the BSS in the PPC32 ELF ABI,
- * and needs to be executable. This means the whole heap ends
- * up being executable.
- */
-#define VM_DATA_DEFAULT_FLAGS32 (VM_READ | VM_WRITE | VM_EXEC | \
- VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
-#define VM_DATA_DEFAULT_FLAGS64 (VM_READ | VM_WRITE | \
+#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \
VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
#ifdef __powerpc64__
diff --git a/arch/powerpc/include/asm/page_32.h b/arch/powerpc/include/asm/page_32.h
index 68d73b2..aaae5a6 100644
--- a/arch/powerpc/include/asm/page_32.h
+++ b/arch/powerpc/include/asm/page_32.h
@@ -7,8 +7,6 @@
#endif
#endif
-#define VM_DATA_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS32
-
#ifdef CONFIG_NOT_COHERENT_CACHE
#define ARCH_DMA_MINALIGN L1_CACHE_BYTES
#endif
diff --git a/arch/powerpc/include/asm/page_64.h b/arch/powerpc/include/asm/page_64.h
index fed85e6..615d88b 100644
--- a/arch/powerpc/include/asm/page_64.h
+++ b/arch/powerpc/include/asm/page_64.h
@@ -136,10 +136,6 @@ do { \
#endif /* !CONFIG_HUGETLB_PAGE */
-#define VM_DATA_DEFAULT_FLAGS \
- (is_32bit_task() ? \
- VM_DATA_DEFAULT_FLAGS32 : VM_DATA_DEFAULT_FLAGS64)
-
/*
* This is the default if a program doesn't have a PT_GNU_STACK
* program header entry. The PPC64 ELF ABI has a non executable stackdiff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 1b52956..c26b40d 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -76,13 +76,20 @@ static struct linux_binfmt elf_format = {
#define BAD_ADDR(x) ((unsigned long)(x) >= TASK_SIZE)
-static int set_brk(unsigned long start, unsigned long end)
+static int set_brk(unsigned long start, unsigned long end, int prot)
{
start = ELF_PAGEALIGN(start);
end = ELF_PAGEALIGN(end);
if (end > start) {
unsigned long addr;
- addr = vm_brk(start, end - start);
+ /* Map the non-file portion of the last load header. If the
+ header is requesting these pages to be executeable then
+ we have to honour that, otherwise assume they are bss. */
+ if (prot & PROT_EXEC)
+ addr = vm_mmap(0, start, end - start, prot,
+ MAP_PRIVATE | MAP_FIXED, 0);
+ else
+ addr = vm_brk(start, end - start);
if (BAD_ADDR(addr))
return addr;
}@@ -381,6 +388,7 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
unsigned long load_addr = 0;
int load_addr_set = 0;
unsigned long last_bss = 0, elf_bss = 0;
+ int bss_prot = 0;
unsigned long error = ~0UL;
unsigned long total_size;
int retval, i, size;
@@ -489,8 +497,10 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
* elf_bss and last_bss is the bss section.
*/
k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
- if (k > last_bss)
+ if (k > last_bss) {
last_bss = k;
+ bss_prot = elf_prot;
+ }
}
}
@@ -509,8 +519,19 @@ static unsigned long load_elf_interp(struct elfhdr *interp_elf_ex,
/* What we have mapped so far */
elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1);
- /* Map the last of the bss segment */
- error = vm_brk(elf_bss, last_bss - elf_bss);
+ if (last_bss > elf_bss) {
+ /* Map the non-file portion of the last load
+ header. If the header is requesting these pages to
+ be executeable then we have to honour that,
+ otherwise assume they are bss. */
+ if ((bss_prot & PROT_EXEC) && last_bss > elf_bss)
+ error = vm_mmap(0, elf_bss,
+ ELF_PAGEALIGN(last_bss - elf_bss),
+ bss_prot, MAP_PRIVATE | MAP_FIXED, 0);
+ else
+ error = vm_brk(elf_bss, last_bss - elf_bss);
+ }
+
if (BAD_ADDR(error))
goto out_close;
}@@ -560,6 +581,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
unsigned long error;
struct elf_phdr *elf_ppnt, *elf_phdata;
unsigned long elf_bss, elf_brk;
+ int bss_prot = 0;
int retval, i;
unsigned int size;
unsigned long elf_entry;
@@ -750,7 +772,8 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
before this one. Map anonymous pages, if needed,
and clear the area. */
retval = set_brk(elf_bss + load_bias,
- elf_brk + load_bias);
+ elf_brk + load_bias,
+ bss_prot);
if (retval) {
send_sig(SIGKILL, current, 0);
goto out_free_dentry;@@ -852,8 +875,10 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
if (end_data < k)
end_data = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
- if (k > elf_brk)
+ if (k > elf_brk) {
+ bss_prot = elf_prot;
elf_brk = k;
+ }
}
loc->elf_ex.e_entry += load_bias;@@ -869,7 +894,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
* mapping in the interpreter, to make sure it doesn't wind
* up getting placed where the bss needs to go.
*/
- retval = set_brk(elf_bss, elf_brk);
+ retval = set_brk(elf_bss, elf_brk, bss_prot);
if (retval) {
send_sig(SIGKILL, current, 0);
goto out_free_dentry;--
1.7.5.4