Does anyone need executable stack?

Discussions on more advanced topics such as monolithic vs micro-kernels, transactional memory models, and paging vs segmentation should go here. Use this forum to expand and improve the wiki!
nullplan
Member
Member
Posts: 1790
Joined: Wed Aug 30, 2017 8:24 am

Does anyone need executable stack?

Post by nullplan »

Hi all!

By default, Linux will map the main stack of a new process as executable, unless a marking is present in the file to tell it to stop. I have also seen in dietlibc that the thread stacks are mapped executable, because according to a sad comment at that place, some architectures need that. And now I really want to know who could ever need the stack to be executable and why. And I can already tell you one area where it isn't needed anymore: Signal handling.

UNIX signal handling is supposed to work like this: When a signal arrives and has a custom handler, the program state is modified to invoke the handler function immediately. Now, since this can happen at any time, there is no ABI boundary here. Which means caller saved registers are not saved or restored. So to prevent the main program from going haywire, the entire unmodified register state (including FPU registers) is placed on the userspace stack when the signal handler is invoked. When the signal handler returns, it has to make a system call to restore the register state from the stuff on stack. And there's the problem: The OS requires a few instructions to be executed to invoke that system call. Now Linux used to - and still does - place this code on stack. But only for compatibility. The code is not actually used and is only there to mark a stack frame as a signal frame for the debugger. Instead, every signal handler is registered with a "restorer", a second code pointer, which becomes the return address of the signal handler. Or, if that wasn't provided (but it always is in modern libcs), a restorer in the VDSO is used. The code on stack is entirely useless.

The reason I'm asking is because I would like to just forego executable stack altogether in my OS, but I don't know what I would break, and Google seems to not like my query about "executable stack".
Carpe diem!
Korona
Member
Member
Posts: 1000
Joined: Thu May 17, 2007 1:27 pm
Contact:

Re: Does anyone need executable stack?

Post by Korona »

I don't think there is a valid reason. Managarm runs just fine w/o executable stacks. As you said, the SA_RESTORE flag and/or VDSO fixes the need for an executable signal trampoline.
managarm: Microkernel-based OS capable of running a Wayland desktop (Discord: https://discord.gg/7WB6Ur3). My OS-dev projects: [mlibc: Portable C library for managarm, qword, Linux, Sigma, ...] [LAI: AML interpreter] [xbstrap: Build system for OS distributions].
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: Does anyone need executable stack?

Post by Gigasoft »

but I don't know what I would break
That one is easy to answer. Nothing, since no applications have been written yet. Your OS, your rules.
User avatar
mid
Member
Member
Posts: 31
Joined: Thu Mar 04, 2021 7:25 am

Re: Does anyone need executable stack?

Post by mid »

I've heard of techniques like pushing code to the stack (a form of self-modifying code), but I can't name where it was used off the top of my head. I think some 6502-based systems? Considering that these hacks are much less useful on modern systems and hardware, I'd say it's okay to make the stack non-executable.
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: Does anyone need executable stack?

Post by pvc »

I was using executable stack to implement signals. My OS used 3 stacks per thread.
  • kernel stack - used at thread startup, for interrupts and syscalls (created for every thread), required
  • user stack - your plain old usermode stack (created by the kernel when entering user mode for the first time), optional
  • signal stack - used only for handling signals (normally created at run time in crt0), optional
Separate signal stack was required because things like red zone on x86-64 and semi-asynchronous nature of signals. And, IMO, it would be best not to touch regular program stack when executing signal handlers. Kernel and user stacks would be perfectly fine as non-executable. But signal stack had to be executable, as return from signal handler was implemented as a syscall in my OS and POSIX/Unix-like signal handlers expected that you can return from them just as you would from any other subroutine (with return statement or something equivalent). I also didn't want to hardcode any addresses in usermode address space. I wanted my usermode address space to be 100% flexible. So I decided to put signal return handler on the signal stack and spoof the return address to point to it. This approach was absolutely fine for x86, x86-64, ARM, and ARM64.
nullplan
Member
Member
Posts: 1790
Joined: Wed Aug 30, 2017 8:24 am

Re: Does anyone need executable stack?

Post by nullplan »

mid wrote:I've heard of techniques like pushing code to the stack (a form of self-modifying code), but I can't name where it was used off the top of my head.
Well, OK, I have actually done something like that before, but the use case is so esoteric, and it only works on one particular platform, so I thought it shouldn't occur in the wild. I had written a program for OS-9 on PowerPC that could read out arbitrary SPRs. The opcode to read an SPR in PowerPC does not accept indirect addressing, so your only options are to program every single possibility or use self-modifying code (sort of like the "int" instruction on x86). But this only works on PowerPC, because "mfspr" only exists there, and only on OS-9 because I could make executables run in system state there. And if stack was not executable in that system, I could have done the same thing with a dedicated memory mapping.
pvc wrote:Separate signal stack was required because things like red zone on x86-64 and semi-asynchronous nature of signals.
You can implement the red zone just by leaving enough space beyond the stack pointer untouched when allocating the signal frame.
pvc wrote:And, IMO, it would be best not to touch regular program stack when executing signal handlers.
Why? You must copy data to userspace anyway, whether you do it to the normal stack or a signal stack. And it is going to be a lot of data.
pvc wrote:But signal stack had to be executable, as return from signal handler was implemented as a syscall in my OS and POSIX/Unix-like signal handlers expected that you can return from them just as you would from any other subroutine (with return statement or something equivalent).
That is literally what I just explained, and the solution is to require your applications to register a restorer along with the signal handler (can be done in the library), and then no code on stack is ever executed. Or to inject a VDSO at a random address and use a trampoline in there.
pvc wrote:This approach was absolutely fine for x86, x86-64, ARM, and ARM64.
Oh it works, obviously. A lot of things in this world work even though we really don't want them to. In this case you have created a writable and executable memory area for your own convenience.
Carpe diem!
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: Does anyone need executable stack?

Post by pvc »

@nullplan I never said that it was the right or best way to do things. It was just the way I did it. It could all be done without executable stack but I don't see much of a reason for that. BTW. what is so wrong about having writeable executable area? I mean, you are allowed to load absolutely anything into user space anyway. As long as there is no access to kernel space or hardware it shouldn't be a problem.
nullplan
Member
Member
Posts: 1790
Joined: Wed Aug 30, 2017 8:24 am

Re: Does anyone need executable stack?

Post by nullplan »

pvc wrote:BTW. what is so wrong about having writeable executable area?
Security. The trend has been going massively towards W^X lately, and with good reason. I do not want programs on my OS to get their stacks smashed like it's 1999. Yes, non-executable stack is merely a mitigation, and ROP is the way around it. There are also ways to make ROP harder. In general, having any writable and executable memory accessible in address space makes executing shell code a lot easier, so not allowing that is a valid mitigation for a start. Having an executable stack in particular is a security problem, since often vulnerable programs allow access to the stack no matter where it is mapped.
pvc wrote:As long as there is no access to kernel space or hardware it shouldn't be a problem.
As XKCD once put it, regarding the root password: If an attacker takes over my web browser without getting the root password, they will be able to
  • Access my web cam and make surreptitious photos or videos
  • Access my personal data, encrypt it, publish it, delete it
  • Spy on my browsing habits, including all the passwords I enter
  • Turn my computer into a bitcoin miner and make it burn tons of energy
  • ...
But at least they won't be able to install any drivers!!

The same is true for attackers that manage to take over a userspace process but not kernel space. They can already do a lot of damage, but at least the - to the user - most irrelevant part of the system is still safe.
Carpe diem!
User avatar
Velko
Member
Member
Posts: 153
Joined: Fri Oct 03, 2008 4:13 am
Location: Ogre, Latvia, EU

Re: Does anyone need executable stack?

Post by Velko »

nullplan wrote:As XKCD once put it, regarding the root password: If an attacker takes over my web browser without getting the root password, they will be able to
That is an issue of insufficient compartmentation. I can think on only single case when browser needs a read access to any of my personal files: when I'm about to upload a file somewhere. Write access? Never! There's a download folder, please place downloaded files there. For everything else (cache, cookies) there should be a set of writable folders, access regulated on per-site basis, enforced by OS. For example, if Facebook somehow manage to set a cookie while I was visiting "website1", browser process should not even be able to read that while I'm visiting "website2".

The security model of mainstream OSes assumes that user can trust programs s/he is running. That might have been true in the 70s, when everybody had to write their own software, but those days are long gone. There are some improvements with SELinux, but it's no use as even plain GNU/Linux is rarely used on desktop. I'm not sure if there are similar features in Windows.

Modern browsers are complex beasts and try to do some compartmentation internally, but they could offload most of that to the OS. As a minimum, browser should run under different user, but ideally there should be a virtual user account for each website.
If something looks overcomplicated, most likely it is.
User avatar
AndrewAPrice
Member
Member
Posts: 2300
Joined: Mon Jun 05, 2006 11:00 pm
Location: USA (and Australia)

Re: Does anyone need executable stack?

Post by AndrewAPrice »

This is very similar to a thread we had last month: viewtopic.php?f=15&t=40700&hilit=permissions&start=30

When it comes to single user systems (personal computers, smart phones, even game consoles) - my most valuable files are my personal files (code, documents, save games - things I've put hundreds of hours into), and my least valuable files are binaries and operating system files that are an inconvenience but I can re-install. User based permissions give the opposite effect - they lock down system files, but any program you run has free rein on your personal files.

That's why I believe capability-based/permission systems are superior. e.g.:
"Skype would like access to your camera. [Always allow] [Just this once] [Deny]"
"Sublime would like access to ~/Source Code/My Cool Project/main.cpp. [Allow] [Configure file permissions to Sublime] [Deny]"

User based permissions make sense on mainframes that are running production services and you don't want one bad service taking down the OS.
My OS is Perception.
User avatar
Brynet-Inc
Member
Member
Posts: 2426
Joined: Tue Oct 17, 2006 9:29 pm
Libera.chat IRC: brynet
Location: Canada
Contact:

Re: Does anyone need executable stack?

Post by Brynet-Inc »

OpenBSD doesn't have executable stacks, and also goes a step further by prohibiting them entirely. Additionally, all stacks must be mapped as MAP_STACK which allows the system to do opportunistic stack pointer checking on kernel entry (e.g: on synchronous faults), potentially making pivots from ROP code more difficult.

https://www.openbsd.org/innovations.htm ... =MAP_STACK

Other operating systems have a misfeature called PT_GNU_STACK which has lead to the problem of infectious executable stacks, meaning a miscompiled dynamic library (e.g. PAM) can contaminate things in such a way to force the process to have an executable stack. There was a thread on HN I replied to in 2019 which remains a problem on Linux/FreeBSD and a number of other systems.

https://news.ycombinator.com/item?id=21553882
Image
Twitter: @canadianbryan. Award by smcerm, I stole it. Original was larger.
nullplan
Member
Member
Posts: 1790
Joined: Wed Aug 30, 2017 8:24 am

Re: Does anyone need executable stack?

Post by nullplan »

Velko wrote:For example, if Facebook somehow manage to set a cookie while I was visiting "website1", browser process should not even be able to read that while I'm visiting "website2".
How would that work? The organization of the cookie database is very definitely an internal part of the browser. In this case, neither AppArmor nor SELinux could do anything, since the identity of the process reading the cookies is the same as the process that wrote them. In both cases it is the web browser. Unless the browser were to change contexts on each site call, but then it would be an opt-in thing for the browser, and they could just choose not to.
AndrewAPrice wrote:When it comes to single user systems (personal computers, smart phones, even game consoles) - my most valuable files are my personal files (code, documents, save games - things I've put hundreds of hours into), and my least valuable files are binaries and operating system files that are an inconvenience but I can re-install. User based permissions give the opposite effect - they lock down system files, but any program you run has free rein on your personal files.
Yeah, I should probably implement something akin to AppArmor (SELinux is for people with too much time. That would allow you to lock down your file system better. And indeed, much of Android's security system seems to go in that direction, requiring direct user consent for each permission for each app on installation, and then giving each app their own file systems (with the capability to browse the whole FS being a capability listed on installation). Implementing something like that might also be interesting.

Doesn't have anything to do with executable stacks, though.
Brynet-Inc wrote:Other operating systems have a misfeature called PT_GNU_STACK which has lead to the problem of infectious executable stacks, meaning a miscompiled dynamic library (e.g. PAM) can contaminate things in such a way to force the process to have an executable stack.
Erm... how does that work? The main stack is mapped by the kernel, and the kernel doesn't see any library dependency other than the dependency on the program interpreter (dynamic linker). Unless GNU ld were to set the attributes of the main program's PT_GNU_STACK according to the stack attributes of the dependent libraries... but that would be dumb, as the library present at run time does not have to be the same as the one present at link time.

Yeah, anyway, that is precisely why I'm asking. So apparently I would be breaking GNU C local functions. Oh well, I shall survive. I rarely see those used at all.
Carpe diem!
User avatar
Brynet-Inc
Member
Member
Posts: 2426
Joined: Tue Oct 17, 2006 9:29 pm
Libera.chat IRC: brynet
Location: Canada
Contact:

Re: Does anyone need executable stack?

Post by Brynet-Inc »

nullplan wrote:
Brynet-Inc wrote:Other operating systems have a misfeature called PT_GNU_STACK which has lead to the problem of infectious executable stacks, meaning a miscompiled dynamic library (e.g. PAM) can contaminate things in such a way to force the process to have an executable stack.
Erm... how does that work? The main stack is mapped by the kernel, and the kernel doesn't see any library dependency other than the dependency on the program interpreter (dynamic linker). Unless GNU ld were to set the attributes of the main program's PT_GNU_STACK according to the stack attributes of the dependent libraries... but that would be dumb, as the library present at run time does not have to be the same as the one present at link time.
It is covered in the [url=lhttps://nullprogram.com/blog/2019/11/15/]linked article[/url] from the HN post, but yes. On Linux et al., if even a single object fails to include this PT_GNU_STACK segment, the entire program gets an executable stack. Not only that, but this also happens at runtime via the dynamic linker. If any (yes, even via dlopen(3)) shared library omits this segment, or includes it but has the flags set to RWE, then it changes the stack to be executable. I wish I were joking.

New hobby operating systems need not repeat this mistake.
Image
Twitter: @canadianbryan. Award by smcerm, I stole it. Original was larger.
nullplan
Member
Member
Posts: 1790
Joined: Wed Aug 30, 2017 8:24 am

Re: Does anyone need executable stack?

Post by nullplan »

Brynet-Inc wrote:It is covered in the linked article from the HN post, but yes. On Linux et al., if even a single object fails to include this PT_GNU_STACK segment, the entire program gets an executable stack. Not only that, but this also happens at runtime via the dynamic linker. If any (yes, even via dlopen(3)) shared library omits this segment, or includes it but has the flags set to RWE, then it changes the stack to be executable. I wish I were joking.
And then people wonder why I dislike glibc. musl uses PT_GNU_STACK as well, but only to set the stack size.
Brynet-Inc wrote:New hobby operating systems need not repeat this mistake.
Agreed.
Carpe diem!
User avatar
Velko
Member
Member
Posts: 153
Joined: Fri Oct 03, 2008 4:13 am
Location: Ogre, Latvia, EU

Re: Does anyone need executable stack?

Post by Velko »

nullplan wrote:How would that work? The organization of the cookie database is very definitely an internal part of the browser. In this case, neither AppArmor nor SELinux could do anything, since the identity of the process reading the cookies is the same as the process that wrote them. In both cases it is the web browser. Unless the browser were to change contexts on each site call, but then it would be an opt-in thing for the browser, and they could just choose not to.
It might require some cooperation from browser developers to make the cookie database externally controllable. Of course browser has to use different contexts for each site. To "encourage" it to do that, the "main" context might also be quite restricted, just rights to initialize and switch into site-contexts. No network access or anything for the main. Of course this is still an opt-in from browser developers as they may choose not to support such OS / security model at all.


Back to the topic about stacks. I'm not getting why would one want to inject code into stack for returns from signal handler. Can not that be handled by having a bit of prologue and epilogue code in libc / glue library? Instead of registering the address of signal handler directly with kernel, store the signal handler callback in userspace variable and register the beginning of the prologue code instead.
If something looks overcomplicated, most likely it is.
Post Reply