Re: [PATCH v7] powerpc: Do not make the entire heap executable

2016-12-12 Thread Jason Gunthorpe
On Wed, Dec 07, 2016 at 02:15:27PM -0800, Kees Cook wrote:
> Can you resend this patch with /proc/$pid/maps output showing the
> before/after effects of this change also included here? Showing that
> reduction in executable mapping should illustrate the benefit of
> avoiding having the execute bit set on the brk area (which is a clear
> security weakness, having writable/executable code in the process's
> memory segment, especially when it was _not_ requested by the ELF
> headers).

Denys, I'll leave it to you to re-sumbit again..

I suggest this reworded commit message:

powerpc: Do not make the entire heap executable

gcc has a configure option to generate ELF files that are W^X:
--enable-secureplt

However the PPC32 kernel is hardwired to add PROT_EXEC to the heap and
BSS segments, totally defeating this security protection.

This is done because the common ELF loader does not properly respect
the load header permissions when mapping a region that is not file
backed.

For example, non-secure PPC creates these segments:

  [21] .data PROGBITS10061254 051254 001868 00  WA  0   0  4
  [22] .got  PROGBITS10062abc 052abc 14 04 WAX  0   0  4
  [23] .sdataPROGBITS10062ad0 052ad0 58 00  WA  0   0  4
  [24] .sbss NOBITS  10062b28 052b28 40 00  WA  0   0  8
  [25] .plt  NOBITS  10062b68 052b28 000d38 00 WAX  0   0  4
  [26] .bss  NOBITS  100638a0 052b28 006424 00  WA  0   0 16

Which results in an ELF load header covering those segments:

  Type   Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD   0x051160 0x10061160 0x10061160 0x019c8 0x08b64 RWE 0x1

If we just remove the PROT_EXEC PPC32 hack then the kernel will do
something like:

10061000-10063000 rwxp 00051000 07:00 3208784/app/bin/busybox.dynamic
10063000-1006a000 rw-p  00:00 0
104a6000-104c7000 rw-p  00:00 0  [heap]

The 2nd mapping is the anonymous 0 filled pages requested by FileSiz <
MemSiz, but it is not executable. This causes instant crashes of
normal PPC32 ELFs as their PLT and GOTs must be executable.

This patches fixes the above bug in the ELF loader and removes the
forced PROT_EXEC from PPC32.

The improvement is seen in /proc/PID/maps. After the patch a normal
ELF looks like:

10061000-10063000 rwxp 00051000 07:00 3208784/app/bin/busybox.dynamic
10063000-1006a000 rwxp  00:00 0
104a6000-104c7000 rw-p  00:00 0  [heap]

while a secure-PLT ELF looks like:

1005-10052000 rw-p 0005 07:00 3208780/app/bin/busybox.dynamic
10052000-10059000 rw-p  00:00 0 
1074-10761000 rw-p  00:00 0  [heap]

Critically, with this patch applied all of the maps within a
secure-plt ELF are W^X.

While before this patch we see undeseriable W

normal ELF:

10061000-10063000 rwxp 00051000 07:00 3208784/app/bin/busybox.dynamic
10063000-1006a000 rwxp  00:00 0
104a6000-104c7000 rwxp  00:00 0  [heap]

secure-plt ELF:

1005-10052000 rw-p 0005 07:00 3208780/app/bin/busybox.dynamic
10052000-10059000 rwxp  00:00 0 
104c7000-104e8000 rwxp  00:00 0  [heap]

-

Andrew/Kees/Denys:

Here are full dumps from my PPC405 system.

Before patch (secure-plt):

0010-00103000 r-xp  00:00 0  [vdso]
0fe25000-0fe3 r-xp  07:00 6557504/app/lib/libnss_files-2.23.so
0fe3-0fe44000 ---p b000 07:00 6557504/app/lib/libnss_files-2.23.so
0fe44000-0fe45000 r--p f000 07:00 6557504/app/lib/libnss_files-2.23.so
0fe45000-0fe46000 rw-p 0001 07:00 6557504/app/lib/libnss_files-2.23.so
0fe46000-0fe4c000 rw-p  00:00 0 
0fe5c000-0ffd2000 r-xp  07:00 4094672/app/lib/libc-2.23.so
0ffd2000-0ffe8000 ---p 00176000 07:00 4094672/app/lib/libc-2.23.so
0ffe8000-0ffec000 r--p 0017c000 07:00 4094672/app/lib/libc-2.23.so
0ffec000-0ffed000 rw-p 0018 07:00 4094672/app/lib/libc-2.23.so
0ffed000-0fff rw-p  00:00 0 
1000-1004e000 r-xp  07:00 3208780/app/bin/busybox.dynamic
1005-10052000 rw-p 0005 07:00 3208780/app/bin/busybox.dynamic
10052000-10059000 rwxp  00:00 0 
104c7000-104e8000 rwxp  00:00 0  [heap]
b7ab1000-b7ad2000 r-xp  07:00 4009940/app/lib/ld-2.23.so
b7aee000-b7af rw-p  00:00 0 
b7af-b7af1000 r--p 0002f000 07:00 4009940/app/lib/ld-2.23.so
b7af1000-b7af2000 rw-p 0003 07:00 4009940/app/lib/ld-2.23.so
bfee1000-bff02000 rw-p  00:00 0  [stack]

After Patch (secure-plt):

0010-00103000 r-xp  00:00 0  [vdso]
0fe25000-0fe3 r-xp  07:00 6557504/app/lib/libnss_files-2.23.so
0fe3-0fe44000 ---p b000 07:00 6557504/app/lib/libnss_files-2.23.so
0fe44000-0fe45000 r--p f000 07:00 6557504/app/lib/libnss_files-2.23.so
0fe45000-0fe46000 

Re: [PATCH v7] powerpc: Do not make the entire heap executable

2016-12-07 Thread Kees Cook
On Wed, Nov 9, 2016 at 9:06 AM, Denys Vlasenko  wrote:
> On 32-bit powerpc the ELF PLT sections of binaries (built with --bss-plt,
> or with a toolchain which defaults to it) look like this:
>
>   [17] .sbss NOBITS  0002aff8 01aff8 14 00  WA  0   0 
>  4
>   [18] .plt  NOBITS  0002b00c 01aff8 84 00 WAX  0   0 
>  4
>   [19] .bss  NOBITS  0002b090 01aff8 a4 00  WA  0   0 
>  4
>
> Which results in an ELF load header:
>
>   Type   Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
>   LOAD   0x019c70 0x00029c70 0x00029c70 0x01388 0x014c4 RWE 0x1
>
> This is all correct, the load region containing the PLT is marked as
> executable. Note that the PLT starts at 0002b00c but the file mapping ends at
> 0002aff8, so the PLT falls in the 0 fill section described by the load header,
> and after a page boundary.
>
> Unfortunately the generic ELF loader ignores the X bit in the load headers
> when it creates the 0 filled non-file backed mappings. It assumes all of these
> mappings are RW BSS sections, which is not the case for PPC.
>
> gcc/ld has an option (--secure-plt) to not do this, this is said to incur
> a small performance penalty.
>
> Currently, to support 32-bit binaries with PLT in BSS kernel maps *entire
> brk area* with executable rights for all binaries, even --secure-plt ones.

Can you resend this patch with /proc/$pid/maps output showing the
before/after effects of this change also included here? Showing that
reduction in executable mapping should illustrate the benefit of
avoiding having the execute bit set on the brk area (which is a clear
security weakness, having writable/executable code in the process's
memory segment, especially when it was _not_ requested by the ELF
headers).

Thanks!

-Kees

>
> Stop doing that.
>
> Teach the ELF loader to check the X bit in the relevant load header
> and create 0 filled anonymous mappings that are executable
> if the load header requests that.
>
> The patch was originally posted in 2012 by Jason Gunthorpe
> and apparently ignored:
>
> https://lkml.org/lkml/2012/9/30/138
>
> Lightly run-tested.
>
> Signed-off-by: Jason Gunthorpe 
> Signed-off-by: Denys Vlasenko 
> Acked-by: Kees Cook 
> Acked-by: Michael Ellerman 
> Tested-by: Jason Gunthorpe 
> CC: Andrew Morton 
> CC: Benjamin Herrenschmidt 
> CC: Paul Mackerras 
> CC: "Aneesh Kumar K.V" 
> CC: Kees Cook 
> CC: Oleg Nesterov 
> CC: Michael Ellerman 
> CC: Florian Weimer 
> CC: linux...@kvack.org
> CC: linuxppc-dev@lists.ozlabs.org
> CC: linux-ker...@vger.kernel.org
> ---
> Changes since v6:
> * rebased to current Linus tree
> * sending to akpm
>
> Changes since v5:
> * made do_brk_flags() error out if any bits other than VM_EXEC are set.
>   (Kees Cook: "With this, I'd be happy to Ack.")
>   See https://patchwork.ozlabs.org/patch/661595/
>
> Changes since v4:
> * if (current->personality & READ_IMPLIES_EXEC), still use VM_EXEC
>   for 32-bit executables.
>
> Changes since v3:
> * typo fix in commit message
> * rebased to current Linus tree
>
> Changes since v2:
> * moved capability to map with VM_EXEC into vm_brk_flags()
>
> Changes since v1:
> * wrapped lines to not exceed 79 chars
> * improved comment
> * expanded CC list
>
>  arch/powerpc/include/asm/page.h |  4 +++-
>  fs/binfmt_elf.c | 30 ++
>  include/linux/mm.h  |  1 +
>  mm/mmap.c   | 24 +++-
>  4 files changed, 45 insertions(+), 14 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
> index 56398e7..17d3d2c 100644
> --- a/arch/powerpc/include/asm/page.h
> +++ b/arch/powerpc/include/asm/page.h
> @@ -230,7 +230,9 @@ extern long long virt_phys_offset;
>   * 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 | \
> +#define VM_DATA_DEFAULT_FLAGS32 \
> +   (((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
> +VM_READ | VM_WRITE | \
>  VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
>
>  #define VM_DATA_DEFAULT_FLAGS64(VM_READ | VM_WRITE | \
> diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
> index 2472af2..065134b 100644
> --- a/fs/binfmt_elf.c
> +++ b/fs/binfmt_elf.c
> @@ -91,12 +91,18 @@ 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 

Re: [PATCH v7] powerpc: Do not make the entire heap executable

2016-11-15 Thread Kees Cook
On Wed, Nov 9, 2016 at 9:06 AM, Denys Vlasenko  wrote:
> On 32-bit powerpc the ELF PLT sections of binaries (built with --bss-plt,
> or with a toolchain which defaults to it) look like this:
>
>   [17] .sbss NOBITS  0002aff8 01aff8 14 00  WA  0   0 
>  4
>   [18] .plt  NOBITS  0002b00c 01aff8 84 00 WAX  0   0 
>  4
>   [19] .bss  NOBITS  0002b090 01aff8 a4 00  WA  0   0 
>  4
>
> Which results in an ELF load header:
>
>   Type   Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
>   LOAD   0x019c70 0x00029c70 0x00029c70 0x01388 0x014c4 RWE 0x1
>
> This is all correct, the load region containing the PLT is marked as
> executable. Note that the PLT starts at 0002b00c but the file mapping ends at
> 0002aff8, so the PLT falls in the 0 fill section described by the load header,
> and after a page boundary.
>
> Unfortunately the generic ELF loader ignores the X bit in the load headers
> when it creates the 0 filled non-file backed mappings. It assumes all of these
> mappings are RW BSS sections, which is not the case for PPC.
>
> gcc/ld has an option (--secure-plt) to not do this, this is said to incur
> a small performance penalty.
>
> Currently, to support 32-bit binaries with PLT in BSS kernel maps *entire
> brk area* with executable rights for all binaries, even --secure-plt ones.
>
> Stop doing that.
>
> Teach the ELF loader to check the X bit in the relevant load header
> and create 0 filled anonymous mappings that are executable
> if the load header requests that.
>
> The patch was originally posted in 2012 by Jason Gunthorpe
> and apparently ignored:
>
> https://lkml.org/lkml/2012/9/30/138
>
> Lightly run-tested.
>
> Signed-off-by: Jason Gunthorpe 
> Signed-off-by: Denys Vlasenko 
> Acked-by: Kees Cook 
> Acked-by: Michael Ellerman 
> Tested-by: Jason Gunthorpe 
> CC: Andrew Morton 
> CC: Benjamin Herrenschmidt 
> CC: Paul Mackerras 
> CC: "Aneesh Kumar K.V" 
> CC: Kees Cook 
> CC: Oleg Nesterov 
> CC: Michael Ellerman 
> CC: Florian Weimer 
> CC: linux...@kvack.org
> CC: linuxppc-dev@lists.ozlabs.org
> CC: linux-ker...@vger.kernel.org

Hi,

Friendly ping to Andrew... I'd like to get this landed in -mm...

-Kees

> ---
> Changes since v6:
> * rebased to current Linus tree
> * sending to akpm
>
> Changes since v5:
> * made do_brk_flags() error out if any bits other than VM_EXEC are set.
>   (Kees Cook: "With this, I'd be happy to Ack.")
>   See https://patchwork.ozlabs.org/patch/661595/
>
> Changes since v4:
> * if (current->personality & READ_IMPLIES_EXEC), still use VM_EXEC
>   for 32-bit executables.
>
> Changes since v3:
> * typo fix in commit message
> * rebased to current Linus tree
>
> Changes since v2:
> * moved capability to map with VM_EXEC into vm_brk_flags()
>
> Changes since v1:
> * wrapped lines to not exceed 79 chars
> * improved comment
> * expanded CC list
>
>  arch/powerpc/include/asm/page.h |  4 +++-
>  fs/binfmt_elf.c | 30 ++
>  include/linux/mm.h  |  1 +
>  mm/mmap.c   | 24 +++-
>  4 files changed, 45 insertions(+), 14 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
> index 56398e7..17d3d2c 100644
> --- a/arch/powerpc/include/asm/page.h
> +++ b/arch/powerpc/include/asm/page.h
> @@ -230,7 +230,9 @@ extern long long virt_phys_offset;
>   * 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 | \
> +#define VM_DATA_DEFAULT_FLAGS32 \
> +   (((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
> +VM_READ | VM_WRITE | \
>  VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
>
>  #define VM_DATA_DEFAULT_FLAGS64(VM_READ | VM_WRITE | \
> diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
> index 2472af2..065134b 100644
> --- a/fs/binfmt_elf.c
> +++ b/fs/binfmt_elf.c
> @@ -91,12 +91,18 @@ 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) {
> -   int error = vm_brk(start, end - start);
> +   /*
> +* Map the last of the bss segment.
> +* If the header is requesting these pages to be
> +* 

[PATCH v7] powerpc: Do not make the entire heap executable

2016-11-09 Thread Denys Vlasenko
On 32-bit powerpc the ELF PLT sections of binaries (built with --bss-plt,
or with a toolchain which defaults to it) look like this:

  [17] .sbss NOBITS  0002aff8 01aff8 14 00  WA  0   0  4
  [18] .plt  NOBITS  0002b00c 01aff8 84 00 WAX  0   0  4
  [19] .bss  NOBITS  0002b090 01aff8 a4 00  WA  0   0  4

Which results in an ELF load header:

  Type   Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD   0x019c70 0x00029c70 0x00029c70 0x01388 0x014c4 RWE 0x1

This is all correct, the load region containing the PLT is marked as
executable. Note that the PLT starts at 0002b00c but the file mapping ends at
0002aff8, so the PLT falls in the 0 fill section described by the load header,
and after a page boundary.

Unfortunately the generic ELF loader ignores the X bit in the load headers
when it creates the 0 filled non-file backed mappings. It assumes all of these
mappings are RW BSS sections, which is not the case for PPC.

gcc/ld has an option (--secure-plt) to not do this, this is said to incur
a small performance penalty.

Currently, to support 32-bit binaries with PLT in BSS kernel maps *entire
brk area* with executable rights for all binaries, even --secure-plt ones.

Stop doing that.

Teach the ELF loader to check the X bit in the relevant load header
and create 0 filled anonymous mappings that are executable
if the load header requests that.

The patch was originally posted in 2012 by Jason Gunthorpe
and apparently ignored:

https://lkml.org/lkml/2012/9/30/138

Lightly run-tested.

Signed-off-by: Jason Gunthorpe 
Signed-off-by: Denys Vlasenko 
Acked-by: Kees Cook 
Acked-by: Michael Ellerman 
Tested-by: Jason Gunthorpe 
CC: Andrew Morton 
CC: Benjamin Herrenschmidt 
CC: Paul Mackerras 
CC: "Aneesh Kumar K.V" 
CC: Kees Cook 
CC: Oleg Nesterov 
CC: Michael Ellerman 
CC: Florian Weimer 
CC: linux...@kvack.org
CC: linuxppc-dev@lists.ozlabs.org
CC: linux-ker...@vger.kernel.org
---
Changes since v6:
* rebased to current Linus tree
* sending to akpm

Changes since v5:
* made do_brk_flags() error out if any bits other than VM_EXEC are set.
  (Kees Cook: "With this, I'd be happy to Ack.")
  See https://patchwork.ozlabs.org/patch/661595/

Changes since v4:
* if (current->personality & READ_IMPLIES_EXEC), still use VM_EXEC
  for 32-bit executables.

Changes since v3:
* typo fix in commit message
* rebased to current Linus tree

Changes since v2:
* moved capability to map with VM_EXEC into vm_brk_flags()

Changes since v1:
* wrapped lines to not exceed 79 chars
* improved comment
* expanded CC list

 arch/powerpc/include/asm/page.h |  4 +++-
 fs/binfmt_elf.c | 30 ++
 include/linux/mm.h  |  1 +
 mm/mmap.c   | 24 +++-
 4 files changed, 45 insertions(+), 14 deletions(-)

diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
index 56398e7..17d3d2c 100644
--- a/arch/powerpc/include/asm/page.h
+++ b/arch/powerpc/include/asm/page.h
@@ -230,7 +230,9 @@ extern long long virt_phys_offset;
  * 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 | \
+#define VM_DATA_DEFAULT_FLAGS32 \
+   (((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
+VM_READ | VM_WRITE | \
 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #define VM_DATA_DEFAULT_FLAGS64(VM_READ | VM_WRITE | \
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 2472af2..065134b 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -91,12 +91,18 @@ 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) {
-   int error = vm_brk(start, end - start);
+   /*
+* Map the last of the bss segment.
+* If the header is requesting these pages to be
+* executable, honour that (ppc32 needs this).
+*/
+   int error = vm_brk_flags(start, end - start,
+   prot & PROT_EXEC ? VM_EXEC : 0);
if (error)
return error;
}
@@ -524,6 +530,7 @@ static unsigned long load_elf_interp(struct elfhdr 
*interp_elf_ex,
unsigned long