
Warn HN: stacks made executable on GNU by mere presence of assembly code - kazinator
If you&#x27;re developing some native executables (C, C++, whatever) on a GNU&#x2F;Linux platform and possibly GNU&#x2F;WhateverElse, and some of your object files are custom assembly language produced by hand (or not by a compiler whose developers are aware of this), and not inline assembly but in their own .S or .s file assembled to a separate .o, watch out!<p>If you do <i>not</i> have this blurb:<p><pre><code>  .section .note.GNU-stack,&quot;&quot;,@progbits
</code></pre>
in your assembly code, and do not use a linker option to prevent it, your entire executable or shared library will be silently marked as requiring an executable stack (in all threads).<p>When such an executable is loaded, the stack is made executable. So are any new thread stacks after that.<p>If such a shared library is loaded into an application (even late, with dlopen, I think), a hook is called out of the linker into glibc, which will call mprotect() on all of the existing thread stacks to allow execution.<p>Oops!<p>(This is, of course, a monumentally stupid programmer trap. Write correct, good assembly code without a secret GNU handshake: unknowingly inflict added security risk on your users.)
======
fefe23
The title is slightly misleading. Inline assembly code in asm statements has
no effect on the stack.

If you have your own .S files, and those do not contain the magic handshake,
then the stack will stay executable, and this is indeed a programmer trap.

The reason for this is that historically the stack was always executable, so
it could not be make non-executable by default, it had to be opt in. In fact,
gcc will generate code that requires the stack to be executable if you use a
certain gcc extension (related to nested functions).

The other way to opt-in into non-executable stack is passing --noexecstack to
as(1) (or when via gcc, use -Wa,--noexecstack)

This ought to be better documented, but it's not. The rationaly is probably
that you should not be writing assembly code if you don't know this kind of
detail? I can only guess about this.

~~~
tbirdz
I just checked and it's mentioned in the elf and ld manpages. It should
probably be called out more, but there is at least some documentation for it.

from man elf:

.note.GNU-stack This section is used in Linux object files for declaring stack
attributes. This section is of type SHT_PROGBITS. The only attribute used is
SHF_EXECINSTR. This indicates to the GNU linker that the object file requires
an executable stack.

~~~
kazinator
The text you quoted doesn't inform anyone that if you don't have that section
at all, an executable stack is _also_ required. I can't find any such
explanation in the elf man page.

Nobody is going to read "man elf" or "man ld", if they already know how to
write assembly code and link it to their C, and whatever they know appears to
be working fine.

~~~
djcapelis
People who know how to write assembly code and link it into their C programs
are probably one of the most likely folks to read man elf and man ld, but I
definitely agree the documentation should be better. Submit a patch?

------
JoshTriplett
I've seen toolchains emit a warning for programs that require an executable
stack; however, I can't seem to track down what toolchains and warning options
produce that. In any case, I've filed
[https://sourceware.org/bugzilla/show_bug.cgi?id=20025](https://sourceware.org/bugzilla/show_bug.cgi?id=20025)
to get such a warning enabled by default.

While I don't think it's possible at this point to default to marking the
stack non-executable without explicit information, it seems perfectly
reasonable to emit a warning about that by default. That would cause far more
developers to notice.

~~~
burfog
People ignore warnings.

The build should just fail if the result would have an executable stack,
unless the final linking step includes an option to explicitly demand an
executable stack.

The error message should mention how to get rid of the code that causes the
stack to be executable. No mention should be made of how to continue on with
an executable stack; people can read the man page if they really really want
to have that.

~~~
kazinator
Also, dlopen should fail on an object that requires an executable stack,
unless some RTLD_WHATEVER flag is passed to allow it. There should also be
some finer granularity than opening execute access in every single thread's
stack.

------
to3m
As discussed earlier today, but without the obvious conclusion called out:
[https://news.ycombinator.com/item?id=11601725](https://news.ycombinator.com/item?id=11601725)

I'm surprised the stack is still left executable. They should have taken the
64-bit transition as an opportunity to change the defaults.

~~~
kazinator
> _earlier today_

That's not earlier. It is a semantic, if not literal, dupe inspired by my
submission (look at the item numbers).

My own submission was prompted by actually running into this, rather than
reading about it on HN.

~~~
to3m
The discussion is older, so I stand by the wording. The post is dated earlier
as well... a mystery. Perhaps this is some artefact of the ever-fickle HN
voting process.

------
olalonde
> marked as requiring an executable stack (in all threads)

Not a C/C++ developer here. What's the significance of this? Would it make
buffer overflows easier to exploit?

~~~
timtamboy63
Yes - a common way to exploit a stack overflow is to basically "write code" in
the stack and then execute it. If the stack isn't executable, you can't
execute the "code you wrote" in the stack.

------
jey
> and do not use a linker option to prevent it

What's the linker option?

~~~
tbirdz
-z noexecstack

------
yuhong
I think SafeSEH on Windows has a similar pitfall, though in this case it is a
/SAFESEH switch in ML.

~~~
cremno
Only on x86 though.

------
cm3
Many distros build with CFLAGS that include -fstack-protector-strong. Is that
enough?

------
openasocket
are there any potential cons to switching the linker to default to adding
stack protection? I'm trying to think of any legitimate use cases for an
executable stack, and can't think of any. It should definitely be better
documented, but I'm wondering if we could just change the default behavior and
have done with it.

~~~
kazinator
It does seem as if these mechanisms were put in place in a transitional time
when non-executable stacks weren't completely "taken to heart", and it didn't
seem like a big deal to default to what had until that time been the normal
behavior of executable stacks, since the dawn of computing.

