With the rise of mainstream consumer machines with hardware stack protection
(e.g. the
The purpose of this document is to help package maintainers fix their packages
when they break. We will be focusing our attention on the GNU_STACK ELF
marking. ELF is simply a file format which all modern linux distros use. An
ELF can be an executable (say
Before getting started, you should read through the Wikipedia entry on the
ELF files end up with executable stack markings in one of three ways:
GCC generates code to be executed on the stack when it implements a
If an assembler source file includes a GNU-stack note that indicates it needs an executable stack, presumably this is by design. Again, in order to remove the need for an executable stack, the code probably needs to be rewritten.
If an assembler source contains no GNU-stack note, the system by default assumes that an executable stack may be required. However, usually if there's no GNU-stack note, this is simply because the author didn't include one, rather than the code actually needing an executable stack.
In the first two cases above, the executable stack marking is correct, and should only be removed by rewriting the code to eliminate the executable stack requirement. Such rewriting has to be considered on a case-by-case basis and is outside the scope of this document, at least for now. Here we focus on the third case, where the upstream author has not indicated whether the assembler object needs an executable stack; fixing this means adding the GNU-stack note to the source to indicate an executable stack is not necessary.
Before you can start fixing something, you have to make sure it's broken first,
right? For this reason, we've developed a suite of tools named
Let's see if your system has any ELFs that want an executable stack.
$ scanelf -lpqe RWX --- --- /usr/lib/opengl/xorg-x11/lib/libGL.so.1.2 RWX --- --- /usr/lib/libcrypto.so.0.9.7 RWX --- --- /usr/lib/libmp.so.3.1.7 RWX --- --- /usr/lib/libSDL-1.2.so.0.7.2 RWX --- --- /usr/lib/libsmpeg-0.4.so.0.1.3 RWX --- --- /usr/lib/libImlib2.so.1.2.0 RWX --- --- /usr/lib/libOSMesa.so.4.0 RWX --- --- /usr/lib/libxvidcore.so.4.1 RWX --- --- /usr/lib/libgmp.so.3.3.3 RWX --- --- /usr/bin/mencoder RWX --- --- /usr/bin/Xorg RWX --- --- /usr/bin/mplayer
We really only need to look at the first column (which corresponds to the ELF
GNU_STACK markings). Most of the time, if we fix that field, all the others
fall into place. As we can see above, many files are marked with an
executable stack (
We now know what files need to be fixed, but what source files are causing this breakage? The only way to find this out is to compile the package and analyze the object files before they are combined into the final executable or library.
So we first have to compile smpeg before we can analyze it.
$ ebuild /usr/portage/media-libs/smpeg/smpeg-0.4.4-r6.ebuild clean unpack compile $ cd /var/tmp/portage/smpeg-0.4.4-r6/work/smpeg-0.4.4/
Now we need to look at each object file and see if it has a
$ scanelf -qeR . !WX --- --- ./video/mmxflags_asm.o !WX --- --- ./video/mmxflags_asm.lo !WX --- --- ./video/mmxidct_asm.o !WX --- --- ./video/mmxidct_asm.lo
Sure enough, these objects lack the
For fun, lets see how we could use the more common
This is what the output should look like, notice the .note.GNU-stack line $ readelf -S plaympeg.o There are 12 section headers, starting at offset 0x256c: Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .text PROGBITS 00000000 000040 001ede 00 AX 0 0 16 [ 2] .rel.text REL 00000000 0030c0 000728 08 10 1 4 [ 3] .data PROGBITS 00000000 001f20 000000 00 WA 0 0 4 [ 4] .bss NOBITS 00000000 001f20 000000 00 WA 0 0 4 [ 5] .rodata.str1.4 PROGBITS 00000000 001f20 0003db 01 AMS 0 0 4 [ 6] .rodata.str1.1 PROGBITS 00000000 0022fb 0001c9 01 AMS 0 0 1 [ 7] .note.GNU-stack PROGBITS 00000000 0024c4 000000 00 0 0 1 [ 8] .comment PROGBITS 00000000 0024c4 00003e 00 0 0 1 [ 9] .shstrtab STRTAB 00000000 002502 000067 00 0 0 1 [10] .symtab SYMTAB 00000000 00274c 0005e0 10 11 9 4 [11] .strtab STRTAB 00000000 002d2c 000394 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings) I (info), L (link order), G (group), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific)Notice how there is no .note.GNU-stack section here $ readelf -S video/mmxidct_asm.o There are 8 section headers, starting at offset 0x738: Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .text PROGBITS 00000000 000034 0005ee 00 AX 0 0 4 [ 2] .rel.text REL 00000000 000a4c 0000f0 08 6 1 4 [ 3] .data PROGBITS 00000000 000630 0000d8 00 WA 0 0 16 [ 4] .bss NOBITS 00000000 000708 000000 00 WA 0 0 4 [ 5] .shstrtab STRTAB 00000000 000708 000030 00 0 0 1 [ 6] .symtab SYMTAB 00000000 000878 000120 10 7 17 4 [ 7] .strtab STRTAB 00000000 000998 0000b1 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings) I (info), L (link order), G (group), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific)
When you compile source code normally, gcc takes care of adding the GNU_STACK
markings so that the final object code is not marked with an executable
stack unless it actually needs it. However, if you compile assembly code,
gcc will not automatically add GNU_STACK markings. So, the most common source
of executable stacks in ELF binaries are packages which include raw assembly
code. Note that we're not talking about inline assembly code, but rather
files like
We can either patch each source file written in assembler and send the fixes
upstream, or we can be lazy and simply force the package build system to
assemble the source files with the GNU as option
The advantage to patching the code is that it's easy to do, it's portable, and we can usually convince upstream to add it to their packages with little fuss. The disadvantage to patching is that we may have to patch many many files.
The advantage to just using
The great thing about patching is that you can copy and paste this stuff
everywhere. Just make sure the code will be preprocessed (e.g. the source
file is named with
#if defined(__linux__) && defined(__ELF__) .section .note.GNU-stack,"",%progbits #endif
%ifidn __OUTPUT_FORMAT__,elf section .note.GNU-stack noalloc noexec nowrite progbits %endif %ifidn __OUTPUT_FORMAT__,elf32 section .note.GNU-stack noalloc noexec nowrite progbits %endif %ifidn __OUTPUT_FORMAT__,elf64 section .note.GNU-stack noalloc noexec nowrite progbits %endif
Often times you only need to add the following code in your ebuild. You must first be sure that the code does not actually require an executable stack as forcing this flag will break the package otherwise.
# This line goes at the top of your ebuild inherit flag-o-matic# This line goes before CFLAGS is used (either by the ebuild or by econf/emake) append-flags -Wa,--noexecstack
On the off chance that you cannot assemble the files, you can tell the linker to disable execstack stack.
# This line goes at the top of your ebuild inherit flag-o-matic# This line goes before LDFLAGS is used (either by the ebuild or by econf/emake) append-ldflags -Wl,-z,noexecstack
If all else fails, ask around on #gentoo-dev on the irc server
irc.freenode.net. Or send an e-mail to the
Arch | Status |
---|---|