This is an archive of the discontinued LLVM Phabricator instance.

[ELF2] - Implemented PT_GNU_STACK support, -z execstack option.
ClosedPublic

Authored by grimar on Nov 11 2015, 6:13 AM.

Details

Summary

PT_GNU_STACK is a entry in the elf file format which contains the access rights (read, write, execute) of the stack,
it is always generated now. By default stack is not executable in this implementation.
-z execstack can be used to make executable.

Diff Detail

Repository
rL LLVM

Event Timeline

grimar updated this revision to Diff 39908.Nov 11 2015, 6:13 AM
grimar retitled this revision from to [ELF2] - Implemented PT_GNU_STACK support.
grimar updated this object.
grimar added reviewers: ruiu, rafael.
grimar added subscribers: llvm-commits, grimar.
ruiu edited edge metadata.Nov 11 2015, 12:56 PM

Is the logic implemented in this patch correct?

The stack is executable if and only if all object files contain .note.GNU-stack section. The logic implemented in this patch seems to make the stack executable at least one of input files contains .note.GNU-stack section.

In D14571#287432, @ruiu wrote:

Is the logic implemented in this patch correct?

The stack is executable if and only if all object files contain .note.GNU-stack section. The logic implemented in this patch seems to make the stack executable at least one of input files contains .note.GNU-stack section.

It makes it executable only if this one .note.GNU-stack section marked as "x".
I think stack is executable always by default. When the linker performs linking, it marks the stack as executable based on the lowest common demoninator. For example, if everything is marked non-executable except one .o file, the entire library would get marked for an executable stack

Logic implemented makes PT_GNU_STACK header to be generated if at least one of input files contains .note.GNU-stack section. Will it be executable depends on flags of .note.GNU-stack section then. If at least one is executable then stack is marked as executable.

What is incorrect in this patch (just noticed) that if for example we have two .o files and one has ".section .note.GNU-stack,"",@progbits" (non executable) but second does not have .note.GNU-stack section at all then stack should be marked executable, but this patch does not makes it to be so. I`ll fix that in updated diff.

I would also suggest to think about changing the default logic from "stack is always executable by default" to opposite one. At least for some targets.
I dont think there are many apps that uses executable stacks. But having it executable is huge security hole.
We can implement -z execstack/-z noexecstack to control that for those who heeds executable one.

In D14571#287432, @ruiu wrote:

Is the logic implemented in this patch correct?

The stack is executable if and only if all object files contain .note.GNU-stack section. The logic implemented in this patch seems to make the stack executable at least one of input files contains .note.GNU-stack section.

Below is the link to gold source comment about how stack stuff works.
https://android.googlesource.com/toolchain/binutils/+/53b6ed3bceea971857c996b6dcb96de96b99335f/binutils-2.19/gold/layout.cc#1942

I think that's a good suggestion, but that made me think of this: we may want to force users to specify -z execstack if they really want to make the stack executable. To me, controlling the stack executable-ness using .note.GNU-stack section is too subtle and fragile. If you have thousands of object files, and only one file >lacks .note.GNU-stack, the entire program's stack will be executable. It's unlikely to be an intended behavior, and if it is actually intended, I believe it is reasonable to tell so to the linker using the -z flag.

So I guess my point is

  • ignore .note.GNU-stack sections at all,
  • make stack non-executable by default,
  • and implement -z execstack

What do you think?

For me sounds good.
I can update the patch to handle -z exectack instead of looking at .note.GNU-stack flags tomorrow.

grimar updated this revision to Diff 40211.Nov 14 2015, 3:10 AM
grimar edited edge metadata.

PT_GNU_STACK header is always created (stack is readonly by default).
Lots of test were updated because of above.
-z execstack implemented.

grimar retitled this revision from [ELF2] - Implemented PT_GNU_STACK support to [ELF2] - Implemented PT_GNU_STACK support, -z execstack option..Nov 14 2015, 3:45 AM
grimar updated this object.
ruiu added inline comments.Nov 14 2015, 6:13 AM
ELF/Driver.cpp
177 ↗(On Diff #40211)

Sort

ELF/Writer.cpp
545–546 ↗(On Diff #40211)

We don't use input files' .note.GNU-stack sections at all. Maybe we should ignore them in .note.GNU-stack?

898 ↗(On Diff #40211)
// 3 for PT_PHDR, first PT_LOAD and PT_GNU_STACK
grimar added inline comments.Nov 14 2015, 6:59 AM
ELF/Writer.cpp
545–546 ↗(On Diff #40211)

Do you mean ignore them in initializeSections ? Something like next ?

switch (Sec.sh_type) {
...
 default:
    if (NameOrErr == ".note.GNU-stack")
      Sections[I] = &InputSection<ELFT>::Discarded;
ruiu added a subscriber: ruiu.Nov 14 2015, 8:35 AM

Yes.
2015/11/14 6:59 "George Rimar" <grimar@accesssoftek.com>:

grimar added inline comments.

Comment at: ELF/Writer.cpp:545-546
@@ -538,2 +544,4 @@

continue;

+ if (!shouldOutputSection(C))
+ continue;

const Elf_Shdr *H = C->getSectionHdr();

ruiu wrote:

We don't use input files' .note.GNU-stack sections at all. Maybe we

should ignore them in .note.GNU-stack?
Do you mean ignore them in initializeSections ? Something like next ?

switch (Sec.sh_type) {
...
 default:
    if (NameOrErr == ".note.GNU-stack")
      Sections[I] = &InputSection<ELFT>::Discarded;

http://reviews.llvm.org/D14571

grimar updated this revision to Diff 40212.Nov 14 2015, 9:28 AM

Review comments addressed.

ELF/Driver.cpp
177 ↗(On Diff #40211)

Done

ELF/Writer.cpp
545–546 ↗(On Diff #40211)

Done

898 ↗(On Diff #40211)

Done

rafael added inline comments.Nov 14 2015, 11:03 AM
test/elf2/gnustack.s
16 ↗(On Diff #40212)

This is checking way more than it needs. Check just the contents of PT_GNU_STACK and that we eat the section.

grimar updated this revision to Diff 40214.Nov 14 2015, 11:59 AM

Review comments addressed.

test/elf2/gnustack.s
16 ↗(On Diff #40212)

Ok. My way also checked that PT_GNU_STACK header is the last one but thats really probably not needed.

rafael accepted this revision.Nov 14 2015, 12:53 PM
rafael edited edge metadata.

LGTM

This revision is now accepted and ready to land.Nov 14 2015, 12:53 PM
This revision was automatically updated to reflect the committed changes.
joerg added a subscriber: joerg.Nov 16 2015, 2:31 AM

This is breaking compatibility with legacy ELF loaders :( It should really be possible to create binaries without this stupid mess.

grimar added a comment.EditedNov 16 2015, 3:26 AM

This is breaking compatibility with legacy ELF loaders :( It should really be possible to create binaries without this stupid mess.

Can -z execstack help this ? It restores original behavior (no header, rw stack).

That needs the build systems patched. IMHO it would be better to be compatible with bfd & gold here and default to execstack.

ismail

On the other side almost no apps really needs stack to be executable and having it is a security issue in most cases.
Returning to the problem itself, do really many loaders does not support PT_GNU_STACK ? It seems to be old enough feature (I can see mails of 2007 year in main archive of the binutils@sourceware.org).

emaste added a subscriber: emaste.Nov 16 2015, 7:04 AM

Returning to the problem itself, do really many loaders does not support PT_GNU_STACK ? It seems to be old enough feature (I can see mails of 2007 year in main archive of the binutils@sourceware.org).

For FreeBSD we added support in January 2011, r217153. Because the issue was raised by @joerg I'd guess NetBSD's rtld doesn't support it.

Do we have a list of the ELF systems we desire to support in lld?

What do you mean by legacy? An old loader will just ignore this
program header, no?

Sorry, just read that that was not the case.

OK, I think we are all in agreement on the objective: non executable
stacks by default.

The problem them is that how to do it is dependent on the dynamic
linker, and we don't have a reliable way saying which dynamic linker
will be used.

How about

  • -z execstack: add the program header marking the stack exectuable.
  • -z noexecstack: add the program header marking the stack non exectuable.
  • If neither, mark the stack non executable if we ever see

.note.GNU-stack. I.E., use it as an indication that the dynamic linker
uses that segment.

Cheers,
Rafael

Works for me. Worst case is using objcopy on every input file, but that's doable.