Does anyone need executable stack?
Does anyone need executable stack?
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".
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!
Re: Does anyone need executable stack?
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].
Re: Does anyone need executable stack?
That one is easy to answer. Nothing, since no applications have been written yet. Your OS, your rules.but I don't know what I would break
Re: Does anyone need executable stack?
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.
Re: Does anyone need executable stack?
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
Re: Does anyone need executable stack?
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.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.
You can implement the red zone just by leaving enough space beyond the stack pointer untouched when allocating the signal frame.pvc wrote:Separate signal stack was required because things like red zone on x86-64 and semi-asynchronous nature of signals.
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:And, IMO, it would be best not to touch regular program stack when executing signal handlers.
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: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).
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.pvc wrote:This approach was absolutely fine for x86, x86-64, ARM, and ARM64.
Carpe diem!
Re: Does anyone need executable stack?
@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.
Re: Does anyone need executable stack?
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:BTW. what is so wrong about having writeable executable area?
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 topvc wrote:As long as there is no access to kernel space or hardware it shouldn't be a problem.
- 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
- ...
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!
Re: Does anyone need executable stack?
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".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
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.
- AndrewAPrice
- Member
- Posts: 2300
- Joined: Mon Jun 05, 2006 11:00 pm
- Location: USA (and Australia)
Re: Does anyone need executable stack?
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.
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.
- Brynet-Inc
- Member
- Posts: 2426
- Joined: Tue Oct 17, 2006 9:29 pm
- Libera.chat IRC: brynet
- Location: Canada
- Contact:
Re: Does anyone need executable stack?
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
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
Re: Does anyone need executable stack?
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.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".
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.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.
Doesn't have anything to do with executable stacks, though.
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.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.
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!
- Brynet-Inc
- Member
- Posts: 2426
- Joined: Tue Oct 17, 2006 9:29 pm
- Libera.chat IRC: brynet
- Location: Canada
- Contact:
Re: Does anyone need executable stack?
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.nullplan wrote: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.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.
New hobby operating systems need not repeat this mistake.
Re: Does anyone need executable stack?
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: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.
Agreed.Brynet-Inc wrote:New hobby operating systems need not repeat this mistake.
Carpe diem!
Re: Does anyone need executable stack?
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.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.
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.