linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: [PATCH] New PT_GNU_COMPAT segment header extension
       [not found] <90c73bcf-9c80-47c2-a0de-89bc066013d1@zmail15.collab.prod.int.phx2.redhat.com>
@ 2012-01-13 13:56 ` Ramon de C Valle
  2012-01-13 15:33   ` Ramon de C Valle
  0 siblings, 1 reply; 6+ messages in thread
From: Ramon de C Valle @ 2012-01-13 13:56 UTC (permalink / raw)
  To: linux-kernel

Hi,

This is a brief example of the behavior of the system I use for some time
already. For an ELF binary with the PT_GNU_STACK segment header and the PF_X
flag not set (i.e. the default), the following are its currently virtual
memory mappings and their access permissions:

[rcvalle@Fedora-15-i386 ~]$ cat /proc/2253/maps 
004e2000-004e3000 r-xp 00000000 00:00 0          [vdso]
08048000-08049000 r-xp 00000000 fd:02 926785     /home/rcvalle/a.out
08049000-0804a000 rw-p 00000000 fd:02 926785     /home/rcvalle/a.out
495c9000-495e8000 r-xp 00000000 fd:01 1971790    /lib/ld-2.13.90.so
495e8000-495e9000 r--p 0001f000 fd:01 1971790    /lib/ld-2.13.90.so
495e9000-495ea000 rw-p 00020000 fd:01 1971790    /lib/ld-2.13.90.so
495ec000-49774000 r-xp 00000000 fd:01 1971791    /lib/libc-2.13.90.so
49774000-49776000 r--p 00188000 fd:01 1971791    /lib/libc-2.13.90.so
49776000-49777000 rw-p 0018a000 fd:01 1971791    /lib/libc-2.13.90.so
49777000-4977a000 rw-p 00000000 00:00 0 
b780c000-b780d000 rw-p 00000000 00:00 0 
b7824000-b7825000 rw-p 00000000 00:00 0 
bfdc3000-bfde4000 rw-p 00000000 00:00 0          [stack]
[rcvalle@Fedora-15-i386 ~]$

The following are its currently virtual memory mappings and their access
permissions with the PT_GNU_STACK segment header and the PF_X flag unset:

[rcvalle@Fedora-15-i386 ~]$ cat /proc/2257/maps 
00dcc000-00dcd000 r-xp 00000000 00:00 0          [vdso]
08048000-08049000 r-xp 00000000 fd:02 926825     /home/rcvalle/a.out
08049000-0804a000 rw-p 00000000 fd:02 926825     /home/rcvalle/a.out
495c9000-495e8000 r-xp 00000000 fd:01 1971790    /lib/ld-2.13.90.so
495e8000-495e9000 r--p 0001f000 fd:01 1971790    /lib/ld-2.13.90.so
495e9000-495ea000 rw-p 00020000 fd:01 1971790    /lib/ld-2.13.90.so
495ec000-49774000 r-xp 00000000 fd:01 1971791    /lib/libc-2.13.90.so
49774000-49776000 r--p 00188000 fd:01 1971791    /lib/libc-2.13.90.so
49776000-49777000 rw-p 0018a000 fd:01 1971791    /lib/libc-2.13.90.so
49777000-4977a000 rw-p 00000000 00:00 0 
b7711000-b7712000 rw-p 00000000 00:00 0 
b7729000-b772a000 rw-p 00000000 00:00 0 
bfca7000-bfcc8000 rwxp 00000000 00:00 0          [stack]
[rcvalle@Fedora-15-i386 ~]$

The following are its currently virtual memory mappings and their access
permissions with the PT_GNU_COMPAT segment header and the PF_X flag set:

[rcvalle@Fedora-15-i386 ~]$ cat /proc/2349/maps 
00850000-00851000 r-xp 00000000 00:00 0          [vdso]
00d29000-00d2a000 rwxp 00000000 00:00 0 
00fd2000-00fd3000 rwxp 00000000 00:00 0 
08048000-08049000 r-xp 00000000 fd:02 926785     /home/rcvalle/a.out
08049000-0804a000 rwxp 00000000 fd:02 926785     /home/rcvalle/a.out
495c9000-495e8000 r-xp 00000000 fd:01 1971790    /lib/ld-2.13.90.so
495e8000-495e9000 r-xp 0001f000 fd:01 1971790    /lib/ld-2.13.90.so
495e9000-495ea000 rwxp 00020000 fd:01 1971790    /lib/ld-2.13.90.so
495ec000-49774000 r-xp 00000000 fd:01 1971791    /lib/libc-2.13.90.so
49774000-49776000 r-xp 00188000 fd:01 1971791    /lib/libc-2.13.90.so
49776000-49777000 rwxp 0018a000 fd:01 1971791    /lib/libc-2.13.90.so
49777000-4977a000 rwxp 00000000 00:00 0 
bfd2b000-bfd4c000 rwxp 00000000 00:00 0          [stack]
[rcvalle@Fedora-15-i386 ~]$

Notice the difference between its currently virtual memory mappings and
their access permissions with the PT_GNU_STACK segment header and the PF_X
flag unset and their access permissions with the PT_GNU_COMPAT segment
header and the PF_X flag set. The latter is the current behavior of the
Linux kernel for any ELF binary with the PT_GNU_STACK segment header and the
PF_X flag unset (i.e. all its virtual memory mappings are executable).

Any comments about these patches would be greatly appreciated.

Thanks,


-- 
Ramon de C Valle / Red Hat Security Response Team

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] New PT_GNU_COMPAT segment header extension
  2012-01-13 13:56 ` [PATCH] New PT_GNU_COMPAT segment header extension Ramon de C Valle
@ 2012-01-13 15:33   ` Ramon de C Valle
  2012-01-13 16:03     ` Ramon de C Valle
  0 siblings, 1 reply; 6+ messages in thread
From: Ramon de C Valle @ 2012-01-13 15:33 UTC (permalink / raw)
  To: linux-kernel



> Hi,
> 
> This is a brief example of the behavior of the system I use for some
> time
> already. For an ELF binary with the PT_GNU_STACK segment header and
> the PF_X
> flag not set (i.e. the default), the following are its currently
> virtual
> memory mappings and their access permissions:
> 
> [rcvalle@Fedora-15-i386 ~]$ cat /proc/2253/maps
> 004e2000-004e3000 r-xp 00000000 00:00 0          [vdso]
> 08048000-08049000 r-xp 00000000 fd:02 926785     /home/rcvalle/a.out
> 08049000-0804a000 rw-p 00000000 fd:02 926785     /home/rcvalle/a.out
> 495c9000-495e8000 r-xp 00000000 fd:01 1971790    /lib/ld-2.13.90.so
> 495e8000-495e9000 r--p 0001f000 fd:01 1971790    /lib/ld-2.13.90.so
> 495e9000-495ea000 rw-p 00020000 fd:01 1971790    /lib/ld-2.13.90.so
> 495ec000-49774000 r-xp 00000000 fd:01 1971791    /lib/libc-2.13.90.so
> 49774000-49776000 r--p 00188000 fd:01 1971791    /lib/libc-2.13.90.so
> 49776000-49777000 rw-p 0018a000 fd:01 1971791    /lib/libc-2.13.90.so
> 49777000-4977a000 rw-p 00000000 00:00 0
> b780c000-b780d000 rw-p 00000000 00:00 0
> b7824000-b7825000 rw-p 00000000 00:00 0
> bfdc3000-bfde4000 rw-p 00000000 00:00 0          [stack]
> [rcvalle@Fedora-15-i386 ~]$
> 
> The following are its currently virtual memory mappings and their
> access
> permissions with the PT_GNU_STACK segment header and the PF_X flag
> unset:

s/unset/set

> 
> [rcvalle@Fedora-15-i386 ~]$ cat /proc/2257/maps
> 00dcc000-00dcd000 r-xp 00000000 00:00 0          [vdso]
> 08048000-08049000 r-xp 00000000 fd:02 926825     /home/rcvalle/a.out
> 08049000-0804a000 rw-p 00000000 fd:02 926825     /home/rcvalle/a.out
> 495c9000-495e8000 r-xp 00000000 fd:01 1971790    /lib/ld-2.13.90.so
> 495e8000-495e9000 r--p 0001f000 fd:01 1971790    /lib/ld-2.13.90.so
> 495e9000-495ea000 rw-p 00020000 fd:01 1971790    /lib/ld-2.13.90.so
> 495ec000-49774000 r-xp 00000000 fd:01 1971791    /lib/libc-2.13.90.so
> 49774000-49776000 r--p 00188000 fd:01 1971791    /lib/libc-2.13.90.so
> 49776000-49777000 rw-p 0018a000 fd:01 1971791    /lib/libc-2.13.90.so
> 49777000-4977a000 rw-p 00000000 00:00 0
> b7711000-b7712000 rw-p 00000000 00:00 0
> b7729000-b772a000 rw-p 00000000 00:00 0
> bfca7000-bfcc8000 rwxp 00000000 00:00 0          [stack]
> [rcvalle@Fedora-15-i386 ~]$
> 
> The following are its currently virtual memory mappings and their
> access
> permissions with the PT_GNU_COMPAT segment header and the PF_X flag
> set:
> 
> [rcvalle@Fedora-15-i386 ~]$ cat /proc/2349/maps
> 00850000-00851000 r-xp 00000000 00:00 0          [vdso]
> 00d29000-00d2a000 rwxp 00000000 00:00 0
> 00fd2000-00fd3000 rwxp 00000000 00:00 0
> 08048000-08049000 r-xp 00000000 fd:02 926785     /home/rcvalle/a.out
> 08049000-0804a000 rwxp 00000000 fd:02 926785     /home/rcvalle/a.out
> 495c9000-495e8000 r-xp 00000000 fd:01 1971790    /lib/ld-2.13.90.so
> 495e8000-495e9000 r-xp 0001f000 fd:01 1971790    /lib/ld-2.13.90.so
> 495e9000-495ea000 rwxp 00020000 fd:01 1971790    /lib/ld-2.13.90.so
> 495ec000-49774000 r-xp 00000000 fd:01 1971791    /lib/libc-2.13.90.so
> 49774000-49776000 r-xp 00188000 fd:01 1971791    /lib/libc-2.13.90.so
> 49776000-49777000 rwxp 0018a000 fd:01 1971791    /lib/libc-2.13.90.so
> 49777000-4977a000 rwxp 00000000 00:00 0
> bfd2b000-bfd4c000 rwxp 00000000 00:00 0          [stack]
> [rcvalle@Fedora-15-i386 ~]$
> 
> Notice the difference between its currently virtual memory mappings
> and
> their access permissions with the PT_GNU_STACK segment header and the
> PF_X
> flag unset and their access permissions with the PT_GNU_COMPAT
> segment
> header and the PF_X flag set. The latter is the current behavior of
> the
> Linux kernel for any ELF binary with the PT_GNU_STACK segment header
> and the
> PF_X flag unset (i.e. all its virtual memory mappings are

s/unset/set

> executable).

One of the various scenarios an attacker can take advantage of this behavior
to exploit a vulnerability is if, for example, a buffer overflow occurs
within the data segment of a such loaded ELF binary (e.g the recent telnetd
vulnerability) .

In addition, if you use a non-GNU toolchain that does not support the
PT_GNU_STACK segment header extension, or does not create this segment with
the PF_X flag unset by default. Upon loading the resulting compiled
binaries, you will end up with the third aforementioned layout (i.e. all
virtual memory mappings executable)--this completely disregards the ABI.

It is also important to note some embedded Linux distributions may use
non-GNU or custom toolchains that either does not support the PT_GNU_STACK
segment header extension, does not create this segment with the PF_X flag
unset by default, or use binaries with some segment headers stripped out.

In other words, in the absence of the PT_GNU_STACK segment header or with
the PT_GNU_STACK segment header with the PF_X flag set, you will end up with
all virtual memory mappings executable.


> 
> Any comments about these patches would be greatly appreciated.
> 
> Thanks,
> 
> 
> --
> Ramon de C Valle / Red Hat Security Response Team
> 

-- 
Ramon de C Valle / Red Hat Security Response Team

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] New PT_GNU_COMPAT segment header extension
  2012-01-13 15:33   ` Ramon de C Valle
@ 2012-01-13 16:03     ` Ramon de C Valle
  0 siblings, 0 replies; 6+ messages in thread
From: Ramon de C Valle @ 2012-01-13 16:03 UTC (permalink / raw)
  To: linux-kernel



> > Hi,
> > 
> > This is a brief example of the behavior of the system I use for
> > some
> > time
> > already. For an ELF binary with the PT_GNU_STACK segment header and
> > the PF_X
> > flag not set (i.e. the default), the following are its currently
> > virtual
> > memory mappings and their access permissions:
> > 
> > [rcvalle@Fedora-15-i386 ~]$ cat /proc/2253/maps
> > 004e2000-004e3000 r-xp 00000000 00:00 0          [vdso]
> > 08048000-08049000 r-xp 00000000 fd:02 926785
> >     /home/rcvalle/a.out
> > 08049000-0804a000 rw-p 00000000 fd:02 926785
> >     /home/rcvalle/a.out
> > 495c9000-495e8000 r-xp 00000000 fd:01 1971790    /lib/ld-2.13.90.so
> > 495e8000-495e9000 r--p 0001f000 fd:01 1971790    /lib/ld-2.13.90.so
> > 495e9000-495ea000 rw-p 00020000 fd:01 1971790    /lib/ld-2.13.90.so
> > 495ec000-49774000 r-xp 00000000 fd:01 1971791
> >    /lib/libc-2.13.90.so
> > 49774000-49776000 r--p 00188000 fd:01 1971791
> >    /lib/libc-2.13.90.so
> > 49776000-49777000 rw-p 0018a000 fd:01 1971791
> >    /lib/libc-2.13.90.so
> > 49777000-4977a000 rw-p 00000000 00:00 0
> > b780c000-b780d000 rw-p 00000000 00:00 0
> > b7824000-b7825000 rw-p 00000000 00:00 0
> > bfdc3000-bfde4000 rw-p 00000000 00:00 0          [stack]
> > [rcvalle@Fedora-15-i386 ~]$
> > 
> > The following are its currently virtual memory mappings and their
> > access
> > permissions with the PT_GNU_STACK segment header and the PF_X flag
> > unset:
> 
> s/unset/set
> 
> > 
> > [rcvalle@Fedora-15-i386 ~]$ cat /proc/2257/maps
> > 00dcc000-00dcd000 r-xp 00000000 00:00 0          [vdso]
> > 08048000-08049000 r-xp 00000000 fd:02 926825
> >     /home/rcvalle/a.out
> > 08049000-0804a000 rw-p 00000000 fd:02 926825
> >     /home/rcvalle/a.out
> > 495c9000-495e8000 r-xp 00000000 fd:01 1971790    /lib/ld-2.13.90.so
> > 495e8000-495e9000 r--p 0001f000 fd:01 1971790    /lib/ld-2.13.90.so
> > 495e9000-495ea000 rw-p 00020000 fd:01 1971790    /lib/ld-2.13.90.so
> > 495ec000-49774000 r-xp 00000000 fd:01 1971791
> >    /lib/libc-2.13.90.so
> > 49774000-49776000 r--p 00188000 fd:01 1971791
> >    /lib/libc-2.13.90.so
> > 49776000-49777000 rw-p 0018a000 fd:01 1971791
> >    /lib/libc-2.13.90.so
> > 49777000-4977a000 rw-p 00000000 00:00 0
> > b7711000-b7712000 rw-p 00000000 00:00 0
> > b7729000-b772a000 rw-p 00000000 00:00 0
> > bfca7000-bfcc8000 rwxp 00000000 00:00 0          [stack]
> > [rcvalle@Fedora-15-i386 ~]$
> > 
> > The following are its currently virtual memory mappings and their
> > access
> > permissions with the PT_GNU_COMPAT segment header and the PF_X flag
> > set:
> > 
> > [rcvalle@Fedora-15-i386 ~]$ cat /proc/2349/maps
> > 00850000-00851000 r-xp 00000000 00:00 0          [vdso]
> > 00d29000-00d2a000 rwxp 00000000 00:00 0
> > 00fd2000-00fd3000 rwxp 00000000 00:00 0
> > 08048000-08049000 r-xp 00000000 fd:02 926785
> >     /home/rcvalle/a.out
> > 08049000-0804a000 rwxp 00000000 fd:02 926785
> >     /home/rcvalle/a.out
> > 495c9000-495e8000 r-xp 00000000 fd:01 1971790    /lib/ld-2.13.90.so
> > 495e8000-495e9000 r-xp 0001f000 fd:01 1971790    /lib/ld-2.13.90.so
> > 495e9000-495ea000 rwxp 00020000 fd:01 1971790    /lib/ld-2.13.90.so
> > 495ec000-49774000 r-xp 00000000 fd:01 1971791
> >    /lib/libc-2.13.90.so
> > 49774000-49776000 r-xp 00188000 fd:01 1971791
> >    /lib/libc-2.13.90.so
> > 49776000-49777000 rwxp 0018a000 fd:01 1971791
> >    /lib/libc-2.13.90.so
> > 49777000-4977a000 rwxp 00000000 00:00 0
> > bfd2b000-bfd4c000 rwxp 00000000 00:00 0          [stack]
> > [rcvalle@Fedora-15-i386 ~]$
> > 
> > Notice the difference between its currently virtual memory mappings
> > and
> > their access permissions with the PT_GNU_STACK segment header and
> > the
> > PF_X
> > flag unset and their access permissions with the PT_GNU_COMPAT
> > segment
> > header and the PF_X flag set. The latter is the current behavior of
> > the
> > Linux kernel for any ELF binary with the PT_GNU_STACK segment
> > header
> > and the
> > PF_X flag unset (i.e. all its virtual memory mappings are
> 
> s/unset/set
> 
> > executable).
> 
> One of the various scenarios an attacker can take advantage of this
> behavior
> to exploit a vulnerability is if, for example, a buffer overflow
> occurs
> within the data segment of a such loaded ELF binary (e.g the recent
> telnetd
> vulnerability) .
> 
> In addition, if you use a non-GNU toolchain that does not support the
> PT_GNU_STACK segment header extension, or does not create this
> segment with
> the PF_X flag unset by default. Upon loading the resulting compiled
> binaries, you will end up with the third aforementioned layout (i.e.
> all
> virtual memory mappings executable)--this completely disregards the
> ABI.
> 
> It is also important to note some embedded Linux distributions may
> use
> non-GNU or custom toolchains that either does not support the
> PT_GNU_STACK
> segment header extension, does not create this segment with the PF_X
> flag
> unset by default, or use binaries with some segment headers stripped
> out.
> 
> In other words, in the absence of the PT_GNU_STACK segment header or
> with
> the PT_GNU_STACK segment header with the PF_X flag set, you will end
> up with
> all virtual memory mappings executable.

For better illustrating the current behavior of the kernel without these
patches. Try to load an ELF binary with only the stack executable by setting
the PF_X flag within the PT_GNU_STACK segment header, or just stripping out
the PT_GNU_STACK segment header entirely, and see what happens.

> 
> 
> > 
> > Any comments about these patches would be greatly appreciated.
> > 
> > Thanks,
> > 
> > 
> > --
> > Ramon de C Valle / Red Hat Security Response Team
> > 
> 
> --
> Ramon de C Valle / Red Hat Security Response Team
> 

-- 
Ramon de C Valle / Red Hat Security Response Team

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] New PT_GNU_COMPAT segment header extension
  2012-02-01 22:13   ` Andrew Morton
@ 2012-02-06 12:08     ` Ramon de C Valle
  0 siblings, 0 replies; 6+ messages in thread
From: Ramon de C Valle @ 2012-02-06 12:08 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel, Linus Torvalds

Hi Andrew,

> <I have been poked>
> 
> I saw the patch but it's one of those ones which looks tricky/risky,
> and is in an area with which I'm not sufficiently familiar.  I used
> to
> ask Roland McGrath to help out with this sort of thing, but he
> dematerialised a while back.  Perhaps Linus can give it some thought?
> I'd suggest a resend: you've added useful info in later emails so
> there
> would be benefit to bringing it all together in one place.
> 
> A couple of minor things:
> 
> - The patch will need a Signed-off-by:, as described in
>   Documentation/SubmittingPatches.

Sure. I'm going to resend the patches properly formatted with all
information together.

> 
> - The term "compat" has a well-understood meaning in the kernel: it
>   refers to the support of 32-bit executables under 64-bit kernels.
>   Adding an unrelated PT_GNU_COMPAT muddies this.  Can you think up a
>   different term?

I previously thought about using PT_GNU_LEGACY. Sounds reasonable?

> 
> 
> 

-- 
Ramon de C Valle / Red Hat Security Response Team

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] New PT_GNU_COMPAT segment header extension
  2012-01-09 11:54 ` Ramon de C Valle
@ 2012-02-01 22:13   ` Andrew Morton
  2012-02-06 12:08     ` Ramon de C Valle
  0 siblings, 1 reply; 6+ messages in thread
From: Andrew Morton @ 2012-02-01 22:13 UTC (permalink / raw)
  To: Ramon de C Valle; +Cc: linux-kernel, Linus Torvalds

On Mon, 09 Jan 2012 06:54:19 -0500 (EST)
Ramon de C Valle <rcvalle@redhat.com> wrote:

> Hi,
> 
> These patches introduces the PT_GNU_COMPAT segment header to indicate the
> kernel whether an ELF binary or a shared library needs to have all readable
> virtual memory mappings also executable (i.e. READ_IMPLIES_EXEC personality)
> and if necessary, it allows more compatibility modes to be implemented in
> the future.
> 
> Currently, an binary that needs only executable stack have unnecessarily all
> readable virtual memory mappings also executable. This is because the kernel
> does not know if the PF_X flag set in the PT_GNU_STACK segment header of the
> binary indicates it needs only stack executable or all readable virtual
> memory mappings also executable. Consequently, the kernel sets the
> READ_IMPLIES_EXEC personality upon loading any binary with the PT_GNU_STACK
> segment header and the PF_X flag set.
> 
> Furthermore, if the PT_GNU_STACK segment header with the PT_X flag is set in
> any of the shared libraries a binary is linked, the kernel does not know if
> the PF_X flag set in the PT_GNU_STACK segment header of the shared library
> indicates it needs only stack executable or all readable virtual memory
> mappings also executable either. Consequently, GCC sets the PT_GNU_STACK
> segment header with the PF_X flag set upon compiling any binary linked to a
> shared library with the PT_GNU_STACK segment header and the PF_X flag set.
> 
> This can result in applications unnoticeably having not only the stack, but
> also all readable virtual memory mappings also executable. These patches
> returns the original meaning and purpose of the PT_GNU_STACK segment header.
> 
> >From the security standpoint, these binaries will rely upon lesser security
> extensions, such as heap consistency checking and others. Thus, improving
> the security of binaries that needs only the stack executable.
> 
> These patches does not affect the current binaries that have the
> PT_GNU_STACK segment header, neither legacy binaries that most likely does
> not have this segment header either. For the existing binaries that
> necessarily need to have all readable virtual memory mappings also
> executable, the PT_GNU_STACK segment header can be easily converted to a
> PT_GNU_COMPAT segment header without recompilation.
> 
> The following are important details about the changes made to the linker:
> 
>  * The PT_GNU_STACK and PT_GNU_COMPAT segment headers are mutually
>    exclusive.
>  * The PT_GNU_STACK segment header has precedence over the PT_GNU_COMPAT
>    segment header.
>  * The PT_GNU_COMPAT segment header IS NOT created by default.
>  * The PT_GNU_STACK segment header IS ALWAYS created by default--which is
>    the original behaviour of the linker.
> 
> These patches are completely non-intrusive. Over the time, once this
> compatibility mode is no longer needed, they can be removed with no
> subsequent effect.
> 

<I have been poked>

I saw the patch but it's one of those ones which looks tricky/risky,
and is in an area with which I'm not sufficiently familiar.  I used to
ask Roland McGrath to help out with this sort of thing, but he
dematerialised a while back.  Perhaps Linus can give it some thought? 
I'd suggest a resend: you've added useful info in later emails so there
would be benefit to bringing it all together in one place.

A couple of minor things:

- The patch will need a Signed-off-by:, as described in
  Documentation/SubmittingPatches.

- The term "compat" has a well-understood meaning in the kernel: it
  refers to the support of 32-bit executables under 64-bit kernels. 
  Adding an unrelated PT_GNU_COMPAT muddies this.  Can you think up a
  different term?



^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH] New PT_GNU_COMPAT segment header extension
       [not found] <ae010933-d93f-4858-97c7-d5aeb3dd73bc@zmail15.collab.prod.int.phx2.redhat.com>
@ 2012-01-09 11:54 ` Ramon de C Valle
  2012-02-01 22:13   ` Andrew Morton
  0 siblings, 1 reply; 6+ messages in thread
From: Ramon de C Valle @ 2012-01-09 11:54 UTC (permalink / raw)
  To: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2811 bytes --]

Hi,

These patches introduces the PT_GNU_COMPAT segment header to indicate the
kernel whether an ELF binary or a shared library needs to have all readable
virtual memory mappings also executable (i.e. READ_IMPLIES_EXEC personality)
and if necessary, it allows more compatibility modes to be implemented in
the future.

Currently, an binary that needs only executable stack have unnecessarily all
readable virtual memory mappings also executable. This is because the kernel
does not know if the PF_X flag set in the PT_GNU_STACK segment header of the
binary indicates it needs only stack executable or all readable virtual
memory mappings also executable. Consequently, the kernel sets the
READ_IMPLIES_EXEC personality upon loading any binary with the PT_GNU_STACK
segment header and the PF_X flag set.

Furthermore, if the PT_GNU_STACK segment header with the PT_X flag is set in
any of the shared libraries a binary is linked, the kernel does not know if
the PF_X flag set in the PT_GNU_STACK segment header of the shared library
indicates it needs only stack executable or all readable virtual memory
mappings also executable either. Consequently, GCC sets the PT_GNU_STACK
segment header with the PF_X flag set upon compiling any binary linked to a
shared library with the PT_GNU_STACK segment header and the PF_X flag set.

This can result in applications unnoticeably having not only the stack, but
also all readable virtual memory mappings also executable. These patches
returns the original meaning and purpose of the PT_GNU_STACK segment header.

>From the security standpoint, these binaries will rely upon lesser security
extensions, such as heap consistency checking and others. Thus, improving
the security of binaries that needs only the stack executable.

These patches does not affect the current binaries that have the
PT_GNU_STACK segment header, neither legacy binaries that most likely does
not have this segment header either. For the existing binaries that
necessarily need to have all readable virtual memory mappings also
executable, the PT_GNU_STACK segment header can be easily converted to a
PT_GNU_COMPAT segment header without recompilation.

The following are important details about the changes made to the linker:

 * The PT_GNU_STACK and PT_GNU_COMPAT segment headers are mutually
   exclusive.
 * The PT_GNU_STACK segment header has precedence over the PT_GNU_COMPAT
   segment header.
 * The PT_GNU_COMPAT segment header IS NOT created by default.
 * The PT_GNU_STACK segment header IS ALWAYS created by default--which is
   the original behaviour of the linker.

These patches are completely non-intrusive. Over the time, once this
compatibility mode is no longer needed, they can be removed with no
subsequent effect.


-- 
Ramon de C Valle / Red Hat Security Response Team

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: binutils-2.22-elf-compat-pt-gnu-compat.patch --]
[-- Type: text/x-patch; name=binutils-2.22-elf-compat-pt-gnu-compat.patch, Size: 6368 bytes --]

diff -wurN a/bfd/elf-bfd.h b/bfd/elf-bfd.h
--- a/bfd/elf-bfd.h	2011-08-16 21:39:38.000000000 -0300
+++ b/bfd/elf-bfd.h	2012-01-07 19:34:53.643000012 -0200
@@ -1600,6 +1600,9 @@
   /* Segment flags for the PT_GNU_STACK segment.  */
   unsigned int stack_flags;
 
+  /* Segment flags for the PT_GNU_COMPAT segment.  */
+  unsigned int compat_flags;
+
   /* Symbol version definitions in external objects.  */
   Elf_Internal_Verdef *verdef;
 
diff -wurN a/bfd/elf.c b/bfd/elf.c
--- a/bfd/elf.c	2011-07-03 10:37:06.000000000 -0300
+++ b/bfd/elf.c	2012-01-09 08:58:01.230000009 -0200
@@ -1158,6 +1158,7 @@
     case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break;
     case PT_GNU_STACK: pt = "STACK"; break;
     case PT_GNU_RELRO: pt = "RELRO"; break;
+    case PT_GNU_COMPAT: pt = "COMPAT"; break;
     default: pt = NULL; break;
     }
   return pt;
@@ -2118,6 +2119,7 @@
 static const struct bfd_elf_special_section special_sections_n[] =
 {
   { STRING_COMMA_LEN (".note.GNU-stack"), 0, SHT_PROGBITS, 0 },
+  { STRING_COMMA_LEN (".note.GNU-compat"),0, SHT_PROGBITS, 0 },
   { STRING_COMMA_LEN (".note"),          -1, SHT_NOTE,     0 },
   { NULL,                    0,           0, 0,            0 }
 };
@@ -2484,6 +2486,9 @@
     case PT_GNU_RELRO:
       return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "relro");
 
+    case PT_GNU_COMPAT:
+      return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "compat");
+
     default:
       /* Check for any processor-specific program segment types.  */
       bed = get_elf_backend_data (abfd);
@@ -3558,6 +3563,12 @@
       ++segs;
     }
 
+  if (elf_tdata (abfd)->compat_flags)
+    {
+      /* We need a PT_GNU_COMPAT segment.  */
+      ++segs;
+    }
+
   for (s = abfd->sections; s != NULL; s = s->next)
     {
       if ((s->flags & SEC_LOAD) != 0
@@ -4160,6 +4171,21 @@
 	    }
 	}
 
+      if (elf_tdata (abfd)->compat_flags)
+	{
+	  amt = sizeof (struct elf_segment_map);
+	  m = (struct elf_segment_map *) bfd_zalloc (abfd, amt);
+	  if (m == NULL)
+	    goto error_return;
+	  m->next = NULL;
+	  m->p_type = PT_GNU_COMPAT;
+	  m->p_flags = elf_tdata (abfd)->compat_flags;
+	  m->p_flags_valid = 1;
+
+	  *pm = m;
+	  pm = &m->next;
+	}
+
       free (sections);
       elf_tdata (abfd)->segment_map = mfirst;
     }
@@ -5434,7 +5460,8 @@
        6. PT_TLS segment includes only SHF_TLS sections.
        7. SHF_TLS sections are only in PT_TLS or PT_LOAD segments.
        8. PT_DYNAMIC should not contain empty sections at the beginning
-	  (with the possible exception of .dynamic).  */
+	  (with the possible exception of .dynamic).
+       9. PT_GNU_COMPAT segments do not include any sections.  */
 #define IS_SECTION_IN_INPUT_SEGMENT(section, segment, bed)		\
   ((((segment->p_paddr							\
       ? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr)	\
@@ -5442,6 +5469,7 @@
      && (section->flags & SEC_ALLOC) != 0)				\
     || IS_NOTE (segment, section))					\
    && segment->p_type != PT_GNU_STACK					\
+   && segment->p_type != PT_GNU_COMPAT					\
    && (segment->p_type != PT_TLS					\
        || (section->flags & SEC_THREAD_LOCAL))				\
    && (segment->p_type == PT_LOAD					\
diff -wurN a/bfd/elflink.c b/bfd/elflink.c
--- a/bfd/elflink.c	2011-11-21 07:29:26.000000000 -0200
+++ b/bfd/elflink.c	2012-01-07 19:34:53.693000010 -0200
@@ -5535,6 +5535,8 @@
     elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | PF_X;
   else if (info->noexecstack)
     elf_tdata (output_bfd)->stack_flags = PF_R | PF_W;
+  else if (info->compat)
+    elf_tdata (output_bfd)->compat_flags = PF_R | PF_W | PF_X;
   else
     {
       bfd *inputobj;
diff -wurN a/binutils/readelf.c b/binutils/readelf.c
--- a/binutils/readelf.c	2011-09-21 17:49:13.000000000 -0300
+++ b/binutils/readelf.c	2012-01-07 19:34:54.027000013 -0200
@@ -2786,6 +2786,7 @@
 			return "GNU_EH_FRAME";
     case PT_GNU_STACK:	return "GNU_STACK";
     case PT_GNU_RELRO:  return "GNU_RELRO";
+    case PT_GNU_COMPAT:	return "GNU_COMPAT";
 
     default:
       if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC))
diff -wurN a/include/bfdlink.h b/include/bfdlink.h
--- a/include/bfdlink.h	2011-11-21 07:29:37.000000000 -0200
+++ b/include/bfdlink.h	2012-01-07 19:34:54.401000009 -0200
@@ -395,6 +395,9 @@
      flags.  */
   unsigned int noexecstack: 1;
 
+  /* TRUE if PT_GNU_COMPAT segment should be created.  */
+  unsigned int compat: 1;
+
   /* TRUE if we want to produced optimized output files.  This might
      need much more time and therefore must be explicitly selected.  */
   unsigned int optimize: 1;
diff -wurN a/include/elf/common.h b/include/elf/common.h
--- a/include/elf/common.h	2011-07-22 17:22:36.000000000 -0300
+++ b/include/elf/common.h	2012-01-07 19:34:54.387000009 -0200
@@ -430,6 +430,7 @@
 #define PT_SUNW_EH_FRAME PT_GNU_EH_FRAME      /* Solaris uses the same value */
 #define PT_GNU_STACK	(PT_LOOS + 0x474e551) /* Stack flags */
 #define PT_GNU_RELRO	(PT_LOOS + 0x474e552) /* Read-only after relocation */
+#define PT_GNU_COMPAT	(PT_LOOS + 0x474e553) /* GNU compatibility mode flags */
 
 /* Program segment permissions, in program header p_flags field.  */
 
diff -wurN a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em
--- a/ld/emultempl/elf32.em	2011-11-21 07:29:39.000000000 -0200
+++ b/ld/emultempl/elf32.em	2012-01-07 19:34:52.612000009 -0200
@@ -2285,6 +2285,10 @@
 	  link_info.noexecstack = TRUE;
 	  link_info.execstack = FALSE;
 	}
+      else if (strcmp (optarg, "enablecompat") == 0)
+	{
+	  link_info.compat = TRUE;
+	}
 EOF
 if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
 fragment <<EOF
@@ -2402,6 +2406,8 @@
   -z defs                     Report unresolved symbols in object files.\n"));
   fprintf (file, _("\
   -z execstack                Mark executable as requiring executable stack\n"));
+  fprintf (file, _("\
+  -z enablecompat             Create PT_GNU_COMPAT program header\n"));
 EOF
 
 if test x"$GENERATE_SHLIB_SCRIPT" = xyes; then
diff -wurN a/ld/ldgram.y b/ld/ldgram.y
--- a/ld/ldgram.y	2011-07-11 12:03:09.000000000 -0300
+++ b/ld/ldgram.y	2012-01-07 19:34:52.601000009 -0200
@@ -1215,6 +1215,8 @@
 			    $$ = exp_intop (0x6474e550);
 			  else if (strcmp (s, "PT_GNU_STACK") == 0)
 			    $$ = exp_intop (0x6474e551);
+			  else if (strcmp (s, "PT_GNU_COMPAT") == 0)
+			    $$ = exp_intop (0x6474e553);
 			  else
 			    {
 			      einfo (_("\

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: linux-3.2-elf-compat-pt-gnu-compat.patch --]
[-- Type: text/x-patch; name=linux-3.2-elf-compat-pt-gnu-compat.patch, Size: 3404 bytes --]

diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
index 5f962df..4cfc625 100644
--- a/arch/x86/include/asm/elf.h
+++ b/arch/x86/include/asm/elf.h
@@ -259,8 +259,8 @@ extern int force_personality32;
  * An executable for which elf_read_implies_exec() returns TRUE will
  * have the READ_IMPLIES_EXEC personality flag set automatically.
  */
-#define elf_read_implies_exec(ex, executable_stack)	\
-	(executable_stack != EXSTACK_DISABLE_X)
+#define elf_read_implies_exec(ex, compat_mode)	\
+	(compat_mode == COMPAT_GNU_COMPAT)
 
 struct task_struct;
 
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 21ac5ee..1d9c4d8 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -572,6 +572,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 	unsigned long start_code, end_code, start_data, end_data;
 	unsigned long reloc_func_desc __maybe_unused = 0;
 	int executable_stack = EXSTACK_DEFAULT;
+	int compat_mode = COMPAT_DEFAULT;
 	unsigned long def_flags = 0;
 	struct {
 		struct elfhdr elf_ex;
@@ -694,6 +695,9 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 				executable_stack = EXSTACK_DISABLE_X;
 			break;
 		}
+		else if (elf_ppnt->p_type == PT_GNU_COMPAT)
+			if (elf_ppnt->p_flags & PF_X)
+				compat_mode = COMPAT_GNU_COMPAT;
 
 	/* Some simple consistency checks for the interpreter */
 	if (elf_interpreter) {
@@ -718,7 +722,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 	/* Do this immediately, since STACK_TOP as used in setup_arg_pages
 	   may depend on the personality.  */
 	SET_PERSONALITY(loc->elf_ex);
-	if (elf_read_implies_exec(loc->elf_ex, executable_stack))
+	if (elf_read_implies_exec(loc->elf_ex, compat_mode))
 		current->personality |= READ_IMPLIES_EXEC;
 
 	if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index fd88a39..1366919 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -123,6 +123,15 @@ extern int suid_dumpable;
 #define EXSTACK_DISABLE_X 1	/* Disable executable stacks */
 #define EXSTACK_ENABLE_X  2	/* Enable executable stacks */
 
+/* Compatibility modes */
+#define COMPAT_DEFAULT    0	/* Default compatibility mode */
+/* The value of COMPAT_GNU_COMPAT is set to the same as the value of
+ * EXSTACK_ENABLE_X for architectures that still expect the value of
+ * the executable_stack variable (although not recommended)
+ * in elf_read_implies_exec().
+ */
+#define COMPAT_GNU_COMPAT 2	/* GNU compatibility mode */
+
 extern int setup_arg_pages(struct linux_binprm * bprm,
 			   unsigned long stack_top,
 			   int executable_stack);
diff --git a/include/linux/elf.h b/include/linux/elf.h
index 31f0508..a336740 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -13,7 +13,7 @@ struct file;
   /* Executables for which elf_read_implies_exec() returns TRUE will
      have the READ_IMPLIES_EXEC personality flag set automatically.
      Override in asm/elf.h as needed.  */
-# define elf_read_implies_exec(ex, have_pt_gnu_stack)	0
+# define elf_read_implies_exec(ex, compat_mode)	0
 #endif
 
 /* 32-bit ELF base types. */
@@ -49,6 +49,7 @@ typedef __s64	Elf64_Sxword;
 #define PT_GNU_EH_FRAME		0x6474e550
 
 #define PT_GNU_STACK	(PT_LOOS + 0x474e551)
+#define PT_GNU_COMPAT	(PT_LOOS + 0x474e553)
 
 /*
  * Extended Numbering

^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2012-02-06 12:08 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <90c73bcf-9c80-47c2-a0de-89bc066013d1@zmail15.collab.prod.int.phx2.redhat.com>
2012-01-13 13:56 ` [PATCH] New PT_GNU_COMPAT segment header extension Ramon de C Valle
2012-01-13 15:33   ` Ramon de C Valle
2012-01-13 16:03     ` Ramon de C Valle
     [not found] <ae010933-d93f-4858-97c7-d5aeb3dd73bc@zmail15.collab.prod.int.phx2.redhat.com>
2012-01-09 11:54 ` Ramon de C Valle
2012-02-01 22:13   ` Andrew Morton
2012-02-06 12:08     ` Ramon de C Valle

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).