4 ms·
I've always been in favor of all OpenBSD security enhancements I've seen, but I have to say, and please hear me out, this is an objectively terrible idea. Yes,
by byuu 10y ago
I've always been in favor of all OpenBSD security enhancements I've seen, but I have to say, and please hear me out, this is an objectively terrible idea.
Yes, most programs should disallow W|X by default. But trying to banish the entire practice with a mount flag, knowing full well few people will go that far to run a W|X application, is bad practice. I'd rather see this as another specialty chmod flag ala SUID, SGID, etc. Or something along those lines. One shouldn't have to enable filesystem-wide W|X just to run one application.
The thing is, when you actually do need W|X, there is no simple workaround. Many emulators and JITs need to be able to dynamically recompile instructions to native machine code to achieve acceptable performance (emulating a 3GHz processor is just not going to happen with an interpreter.) For a particularly busy dynamic recompiler, having to constantly call mprotect to toggle the page flags between W!X and X!W will impact performance too greatly, since that is a syscall requiring a kernel-level transition.
We also have app stores banning the use of this technique as well. This is a very troubling trend lately; it is throwing the baby out with the bathwater.
EDIT: tj responded to me on Twitter: "the per-mountpoint idea is just an initial method; it'll be refined as time goes on. i think per-binary w^x is in the pipeline." -- that will not only resolve my concerns, but in fact would be my ideal design to balance security and performance.
- yoklov 10y ago> One shouldn't have to enable filesystem-wide W|X just to run one application This is a very good point, and it seems like enabling it more granularly would be worth it. But, for your second point, I have trouble believing that switching between W!X and X!W is going to happen frequently enough to be substantial for performance. (It was very small in Firefox's JavaScript JIT, causing something like a 1%-4% performance hit depending on system).
- byuu 10y agoAn emulator is a very different use case than Firefox's JIT. Take Dolphin (the Gamecube / Wii emulator) for example: you have a 4GiB DVD, it has a massive 80-hour game's entire code engine on there. You cannot recompile the entire disc at startup. Even if you could (you really can't), these games tend to push code into RAM to execute, which a static recompiler cannot handle. The way dynamic recompilers handle the tremendous burden is to recompile small blocks at a time, and track which ones are hot and cold. When the buffers fill up, they start dropping old, stale code. It's hard to say exactly what the performance impact would be, and it'd probably vary per game title. But it'd be a lot worse than a web browser recompiling jQuery plus another 200KiB of custom Javascript once on page load. Plus, I am sure there are many more uses cases for W|X than just emulators and JITs. It would be a shame to try and eradicate them all from existence.
- hyperpape 10y agoHow often is too often? When I output compilation logs for HotSpot, it's almost never not compiling (in terms of human perception of how fast the messages are output).
- bzbarsky 10y agoBrowser JITs don't just recompile things on page load. They have to add inline cache entries whenever the existing IC is missed. Now in practice ICs usually hit (that's the point!) so once you've been running for a bit things should hopefully not need more recompiling. Which is a significant difference from the situation you describe.
- lisivka 10y agoMap page two times at separate addresses: for executing and for writing. See http://nullprogram.com/blog/2016/04/10/ http://nullprogram.com/blog/2016/04/10/ for details.
- yoklov 10y agoExtremely clever. Wouldn't this still violate W^X though? I would have thought the OS would see through a trick like this.
- nanofortnight 10y agoIt doesn't violate W^X, because the same virtual memory address isn't writable and executable at the same time.
- PeterisP 10y agoAn emulator is a particular niche application, and a prime example of an exception for which one could enable W|X - acknowledging that most apps don't need W|X doesn't mean that W|X apps would be eradicated.
- byuu 10y agoI agree completely, but from the linked article: > One day far in the future upstream software developers will understand that W^X violations are a tremendously risky practice and that style of programming will be banished outright. Whoever wrote that they should be banned outright, I feel is being very short-sighted. It would be like banning cars because it's possible to seriously injure a person with one. tj later replied to me on Twitter saying they meant for it to become per-process in the future. Once that happens, I'll be okay with this change. Right now, I think filesystem-level is far too broad. I often will want an emulator on the same filesystem as I want W^X protections for other applications on.
- Nyan 10y agoJust FYI, here's an algorithm [https://github.com/animetosho/ParPar/blob/master/xor_depends/info.md#optimisations https://github.com/animetosho/ParPar/blob/master/xor_depends...] which explicitly relies on JIT being a fast operation. It's different from your typical language interpreter type JIT in that it's used as an optimisation for generating an optimal processing kernel. Once generated, it's only used once before it's thrown away, as a different input requires a different processing kernel. Have actually tested using syscalls (not for W^X but rather as a potential workaround for newer Intel CPUs exhibiting weird SMC detection) and have found the overhead to be way too much, even for just one syscall (whilst switching between W/X would require two).
- jandrese 10y agoHow does Wine work on OpenBSD? I would think it would suffer quite badly under this restriction.
- ryuuchin 10y agoCould they not have done something like how paxctl works on Linux? Such as globally enabling it but allowing for application specific control if you have to disable it (either through paxctl/xattr's or some policy file (rbac))? To me that seems to make more sense than a global mount flag but I admit I'm not that knowledgeable about OpenBSD stuff. I suppose it's better late than never considering we've had this stuff in PaX since 2000[1]. [1] https://pax.grsecurity.net/docs/mprotect.txt https://pax.grsecurity.net/docs/mprotect.txt
- ben_bai 10y agoSince /usr/local is where all the packages are installed and by default it is a separate mount point, this is a acceptable first step. A ELF-header-flag to allow W|X on a per binary basis is in the works.
- burfog 10y agoWould you really have to call mprotect on OpenBSD? When SELinux is enforcing this on Linux, you don't. The trick is to map the page twice, once for writing and once for executing. Assuming both mappings are ASLR randomized, it's actually safer than allowing mprotect. SELinux actually has OpenBSD beat on this one: in some configurations, written pages can not be made executable.
- api 10y agoFor app stores it's also about banning anything that might rob the platform of lock in e.g. a good VM language that runs across OSes.
- yellowapple 10y agoOpenBSD's policy is "secure by default", meaning that users/administrators should have to go out of their way to make their systems insecure; I'm personally quite alright with the handful of non-W^X-compatible programs no longer running if it means having W^X globally-enabled by default. You're right that per-binary or per-file might be better in terms of providing a fine-grained approach, but on the other hand, I'd very much like to enforce this on a machine-wide basis on my workstations and servers, and having per-filesystem settings seems to be the most effective way to go about this, and I hope that remains an option (similar to OpenBSD's "nosuid" and "noexec" mount options).