[HN Gopher] OpenBSD may soon gain further memory protections: im...
       ___________________________________________________________________
        
       OpenBSD may soon gain further memory protections: immutable
       userland mappings
        
       Author : fcambus
       Score  : 153 points
       Date   : 2022-09-02 15:06 UTC (7 hours ago)
        
 (HTM) web link (marc.info)
 (TXT) w3m dump (marc.info)
        
       | roopy wrote:
       | What exploit technique is this mitigating?
        
         | saagarjha wrote:
         | That's always a good question to ask :) Seems like the claim is
         | that it prevents exploits where you'd map libc executable and
         | then spray code there. IMO if you have the ability to do this
         | you usually have lost already but -\\_(tsu)_/-
        
       | dang wrote:
       | Url changed from
       | https://undeadly.org/cgi?action=article;sid=20220902100648, which
       | points to this.
        
       | [deleted]
        
       | rwmj wrote:
       | I'm curious why Theo used a new syscall. Wouldn't it be
       | sufficient to add a new MAP_IMMUTABLE flag to mmap which would
       | "fix" the given range of pages' mappings and protections
       | permanently? Can't call it MAP_FIXED sadly :-)
        
         | akira2501 wrote:
         | mmap explicitly is allowed to create new maps in place of
         | existing mappings by just freeing the underlying mapping, in
         | fact that's one use for MAP_FIXED in safely create circularly
         | mapped buffers.
         | 
         | And using MAP_IMMUTABLE with MAP_ANONYMOUS wouldn't seemingly
         | be possible. I would think mprotect() would work, though. Since
         | the new call works more like minherit() under the hood, he
         | decided to just duplicate that mechanism for this.
        
       | teknopurge wrote:
       | I'm not adding insight to this thread, but I love the OpenBSD
       | project. Theo and the team are goat engineers and industry
       | advocates.
        
       | jart wrote:
       | Now all we need is for PROT_EXEC to not imply PROT_READ like
       | Android.
        
         | crest wrote:
         | Why do you expect removing PROT_READ to provide a security gain
         | when running open source software compiled using reproducible
         | builds? Just the offset into an executable memory mapping is
         | enough to know the executable code to be found. Sure it's a bit
         | annoying, but it wouldn't prevent attackers from using it as
         | ROP gadget.
        
         | brynet wrote:
         | There was some work done on XOM (eXecute-only-memory) for
         | arm64, but on at least x86 there isn't a separate page table
         | bit for just read permissions, so there's no way[0][1] to
         | express R^X, PROT_EXEC without PROT_READ is not possible.
         | 
         | Amusingly the 80286 supported execute-only segments, but this
         | was dropped from 32-bit x86.
         | 
         | [0] It is possible on Intel in VM guests using EPT (Extended
         | Page Tables), mlarkin@ experimented with protecting the host
         | kernel in a special VM, called "Underjack". AMD SVM supports
         | nothing like this.
         | 
         | [1] The custom AMD APU SoC in Sony's PS5 console supports
         | "xotext" via NDA'd extensions, but there's no public
         | documentation. (If _anyone_ knows details, pls share)
         | 
         | ... btw, PROT_WRITE-only mappings are also impossible on x86 as
         | well, so PROT_WRITE implicitly means PROT_READ. Not that I'm
         | aware of any valid reason anyone might want this.
        
           | hansendc wrote:
           | > there's no way[0][1] to express R^X, PROT_EXEC without
           | PROT_READ is not possible.
           | 
           | I'll also add a [2]:
           | 
           | [2] There's no way to do it in the page tables. But, if you
           | have Protection Keys for Userspace (PKU), you can get it ...
           | kinda. You can have a PROT_READ|PROT_EXEC mapping, assign it
           | a pkey, then set PKEY_DISABLE_ACCESS in the PKRU register for
           | that key. In fact, if you have a PKU CPU and you do an
           | unadorned mmap(PROT_EXEC), the kernel will allocate you a
           | pkey and do this under the covers _FOR_ you. Anyone who can
           | execute WRPKRU can easily undo this protection, but it 's
           | better than nothing.
        
             | brynet wrote:
             | _kinda_ indeed.
             | 
             | As far as I can tell Intel PKU was only on Server-
             | CPUs/Xeons until at least the 11th Gen (only later
             | models?), and AMD Zen 3.
             | 
             | OpenBSD doesn't support protection keys, in any case.
        
         | saagarjha wrote:
         | This breaks PAN on ARM due to various unfortunate choices in
         | the spec.
        
       | staticassertion wrote:
       | I was just discussing this sort of thing with some colleagues.
       | Because the stack frame for main contains a bunch of other stuff
       | - environment variables, cli args, etc - it makes it unreliable
       | to try to instrument Linux systems and collect that information.
       | A process can change its name, args, env, at any time. That sort
       | of information is really helpful for forensics.
       | 
       | Currently your only option is to pull data directly from kernel
       | structures, which is fine, but most people aren't doing that.
       | 
       | And then of course there's other cool stuff like being able to
       | 'lock' system calls to the system provided libc, which openbsd
       | can do since they already only support their provided libc.
       | 
       | Unfortunately none of this is likely to get to Linux at any point
       | because:
       | 
       | a) I bet some insane userland processes fuck with their stacks
       | 
       | b) Linux doesn't mandate any libc
       | 
       | edit: Seems like there's some "what is this" being asked. Here's
       | my loose understand!
       | 
       | For starters, libc is the interface to the kernel. Very few
       | programs make syscalls directly (except go programs i guess? lol)
       | on Linux, but on openbsd it's just flat out not allowed. OpenBSD
       | doesn't have the "GNU/Linux" dichotomy - it's all one package
       | deal. As such, they get to mandate how userland calls into the
       | kernel.
       | 
       | Of course, you don't have to listen to openbsd today, because you
       | can just... make those system calls directly. Easy. And this is
       | relevant for security because attackers will do something called
       | ROP, which effectively "reuses" bits of your already-executable
       | code to issue system calls (you can google "return to libc" or
       | "ret2libc").
       | 
       | So, first thing's first, have the kernel actually ensure that the
       | sycall is issued from the memory that libc is mapped into. Cool,
       | solved sort of.
       | 
       | But what if the attacker overwrites that libc? Now you've
       | verified that the call is coming from libc but you don't have
       | _integrity_.
       | 
       | With immutability the kernel will now enforce that system calls
       | come from libc _and_ that the code can 't be overwritten.
       | 
       | Of course, this can extend beyond libc, but I'm assuming that's
       | the main point. This would presumably be a general system call
       | that programs can use themselves to do all sorts of fun things.
       | 
       | edit: Can't respond to replies, HN rate limited me :) sorry.
       | Sounds like I need to read up a bit more, this doesn't address
       | the use case I'd had in mind sadly, but still very cool
       | nonetheless.
        
         | eqvinox wrote:
         | > Because the stack frame for main contains a bunch of other
         | stuff - environment variables, cli args, etc - [...] > a) I bet
         | some insane userland processes fuck with their stacks
         | 
         | The new OpenBSD `mimmutable()` call, when applied on the stack,
         | does absolutely nothing to prevent writing or reading the
         | stack. It prevents changing the (virtual memory/pagetable)
         | mapping itself, i.e. mapping in something else, removing the
         | mapping, or changing the mapping attributes (primarily RWX).
         | 
         | Even if some userland process requires an executable stack,
         | that would be indicated with ELF flags and set up by the loader
         | - and then frozen in place.
        
           | jart wrote:
           | Well it technically does if you make a new stack with
           | mmap(MAP_STACK) (or simply round down the stack pointer by a
           | page size) and remove the write access to the top of the
           | original stack and mimmutable it.
        
             | eqvinox wrote:
             | Problem is that those "magic variables" are defined by ABI
             | to be directly above main()'s stack frame... if you're
             | throwing that out, you may equally well leave the stack
             | alone and put the magic stuff in some new place :)
             | 
             | ...
             | 
             | Actually, now that I think about it, I guess you could try
             | to put the boundary between main() and the magic bits right
             | on a page boundary, and then change attrs on the magic
             | bits?
        
               | jart wrote:
               | You mean _start()'s stack pointer. Libc can secure them
               | and it's fine. It would probably break the ANSI C
               | standard though if you can't modify argv and environ
               | though. So Libc would need to copy them. But that limits
               | the usefulness of the original tooling proposal unless
               | the operating system has something like /proc/pid/maps
               | that tells you the extent of the system provided stack. I
               | don't think OpenBSD has that. Please prove me wrong since
               | if it does, I'd love to know how.
        
               | eqvinox wrote:
               | > You mean _start()'s stack pointer.
               | 
               | Right, yeah.
               | 
               | > It would probably break the ANSI C standard though if
               | you can't modify argv and environ though.
               | 
               | AFAIK it would also break setproctitle(), unless my
               | memory is off that works by just writing over the argv
               | space.
               | 
               | On the plus side, on Linux /proc/<pid>/environ is a
               | snapshot created at the time of execve() and kept by the
               | kernel, nothing other than execve() can change it (don't
               | quote me on this, I'm only 90% sure.)
        
               | 7vUYjPAG2fnx7fd wrote:
               | No setproctitle on Linux. As far as I know you have to
               | overwrite the argv space (and hopefully not also the
               | environment space).
        
               | jcranmer wrote:
               | > On the plus side, on Linux /proc/<pid>/environ is a
               | snapshot created at the time of execve() and kept by the
               | kernel, nothing other than execve() can change it (don't
               | quote me on this, I'm only 90% sure.)
               | 
               | prctl(PR_SET_MM_ENV_{START,END}) will change the contents
               | of /proc/<pid>/environ.
               | 
               | From what it looks like in Linux's source code, twiddling
               | the bits at the base of the stack will also cause the
               | procfs file to change--it seems to read directly from the
               | process's memory. Ditto for /cmdline and /auxv, it seems.
        
         | leni536 wrote:
         | > a) I bet some insane userland processes fuck with their
         | stacks
         | 
         | What do you mean by "insane" here? In standard C you get char**
         | argv, and the arguments live on the stack. I believe you are
         | allowed to modify those cli arguments through the pointers, it
         | is not undefined behavior.
        
         | saagarjha wrote:
         | > And this is relevant for security because attackers will do
         | something called ROP, which effectively "reuses" bits of your
         | already-executable code to issue system calls (you can google
         | "return to libc" or "ret2libc").
         | 
         | You've just described why system call integrity is useless
         | without strong CFI :)
        
         | 10000truths wrote:
         | > Very few programs make syscalls directly (except go programs
         | i guess? lol) on Linux
         | 
         | You're forgetting statically compiled binaries, which are very
         | important for ease of deployment and distro-agnostic execution.
        
         | jart wrote:
         | > Linux doesn't mandate any libc
         | 
         | Neither does OpenBSD. You're misunderstanding how msyscall()
         | works. It's like Highlander. There can be only one.
        
           | staticassertion wrote:
           | Ah, interesting, I'll have to dig into it more :) I've never
           | used OpenBSD so I've just had to watch on the sidelines.
           | Anywhere I can read more about this?
        
             | jart wrote:
             | The msyscall() man page. The Cosmopolitan Libc source code.
             | In the cosmoverse, we produce static executables that run
             | on six operating systems. The only Libc we use is obviously
             | our own. So when our executables get loaded on OpenBSD, we
             | do the same thing OpenBSD Libc does, which is calling
             | msyscall() so that only a privileged subset of the
             | application is able to use SYSCALL. In our static binary
             | world, that's basically any function that uses the
             | `privileged` keyword. It makes things a little dicey if we
             | want to dynamically link OpenBSD Libc since we have to pull
             | out some aggressive hacks like Xed in that case. But
             | overall it's fine.
        
       | kyledrake wrote:
       | This security tech usually ends up in other platforms too,
       | strongly recommend donating to their work:
       | https://www.openbsdfoundation.org/donations.html
        
         | bell-cot wrote:
         | +1...but OpenBSD's webmaster might want to update that page, so
         | it doesn't link to their 2020 Fundraising Campaign. (Their
         | current Campaign -
         | https://www.openbsdfoundation.org/campaign2022.html )
         | 
         | And "This security tech usually..." is a bit too modest. Just
         | one example - OpenBSD is the origin of OpenSSH, which has been
         | rather widely used for a decade or two now.
        
           | fsckboy wrote:
           | OpenBSD does great work, but for the record _OpenSSH started
           | as a fork of the free SSH program developed by Tatu Ylonen;
           | later versions of Ylonen 's SSH were proprietary software
           | offered by SSH Communications Security._
           | 
           | https://en.wikipedia.org/wiki/OpenSSH
        
             | chasil wrote:
             | Realistically, OpenBSD completely reimplemented protocol 2
             | themselves.
             | 
             | Since nobody uses protocol 1 anymore, very little of the
             | original code from Tatu Ylonen remains in operation with
             | default settings.
             | 
             | ps I have had to use the SSH commercial release under VMS,
             | and the compatibilities with OpenSSH are quite unpleasant.
        
               | gigantaure wrote:
               | i just read that page[1] earlier this week. this gives a
               | great view on the amount of work performed by the openssh
               | project after the fork of the last open source version.
               | 
               | [1] https://www.openssh.com/history.html
        
         | saagarjha wrote:
         | This happens to already exist on macOS as VM_FLAGS_PERMANENT
         | when setting up the mapping.
        
         | hggh wrote:
         | Too bad they don't accept peer-to-peer electronic cash
        
           | 7vUYjPAG2fnx7fd wrote:
           | > Bitcoin donation via BitPay: The OpenBSD Foundation can
           | accept donations in BTC via BitPay
        
         | hansendc wrote:
         | There honestly isn't that much "tech" to speak of here. We were
         | literally talking about "immutable" mappings last week in Linux
         | land:
         | https://lore.kernel.org/all/b4f0dca5-1d15-67f7-4600-9a0a91e9...
         | 
         | That said, this would be great to see in OpenBSD (or any other
         | OS).
        
         | chasil wrote:
         | The ROP-gadget stuff hasn't migrated to any other kernels that
         | I have seen.
         | 
         | As I understand it, previous ROP-gadget hardening included
         | compiler modifications on system/function call return, trap
         | sleds, and some other stuff that I don't remember. This is on
         | top of the kernel and library relink at every boot (to _really_
         | make ASLR more potent).
         | 
         | These modifications include a verification that the jump is in
         | the stack, and not at the tail of some function (and the other
         | thing eludes my understanding).
         | 
         | These are some OpenBSD references on ROP hardening:
         | 
         | https://undeadly.org/cgi?action=article;sid=20170622065629
         | 
         | https://www.openbsd.org/papers/rop.pdf
         | 
         | https://www.openbsd.org/papers/asiabsdcon2019-rop-paper.pdf
         | 
         | I think that the most notorious exploit of "Return-Oriented
         | Programming" (ROP-gadget) flaws was Solarwinds; I understand
         | that a ROP exploit sealed their fate. Maybe Windows is doing
         | some of this in their kernel.
         | 
         | "At this point, we noticed that Serv-U.dll and RhinoNET.dll
         | both have ASLR support disabled, making them prime locations
         | for ROP gadgets..."
         | 
         | https://www.microsoft.com/security/blog/2021/09/02/a-deep-di...
        
           | saagarjha wrote:
           | This is because the ROP gadget hardening OpenBSD does is
           | generally considered to be mostly useless by other kernels,
           | which are moving to hardware-enforced control flow integrity
           | instead.
        
             | beachhead wrote:
             | Is the ROP gadget hardening OpenBSD does mostly useless
             | tho? Can you elaborate?
        
               | Veliladon wrote:
               | ARM for instance has pointer authentication built into
               | its hardware since version 8.3 of the ISA. While it's not
               | the same implementation as OpenBSD, it has the same
               | practical effect of making sure the return address is
               | valid.
        
               | beachhead wrote:
               | Right. So, how does that render OpenBSD's useless? Maybe
               | I'm not being clear about what I'm asking here. I'm not
               | comparing software vs hardware CFI. OpenBSD doesn't have
               | support for PAC or CET (That I know of) but that doesn't
               | mean they won't in the future. Should there be no
               | software CFI then? Perhaps they would eventually
               | complement each other?
        
             | chasil wrote:
             | I prefer to do all my financial transactions from Chromium
             | on OpenBSD, on a machine where I have run me_cleaner.
             | 
             | Am I happy to have ROP safeguards? You bet!
        
         | na85 wrote:
         | And thus the failure of BSD-style licensing is thrown into
         | sharp relief:
         | 
         | Why are these projects that are used by many large and
         | extraordinarily profitable tech enterprises dependent on
         | community donations?
         | 
         | I recommend not donating, because to do so directly supports
         | corporate parasitism.
        
           | Sunspark wrote:
           | The flip side of course is that improvements also come at the
           | pace of volunteerism, and there are no boardroom meetings
           | where a manager tells the BSD developers that they didn't
           | type enough lines of code that week.
           | 
           | If a corp wants a feature improved or implemented if it
           | doesn't exist, they will have to pay someone and then they
           | have to decide whether they will contribute it. If they do
           | not, then they have to maintain a fork themselves which
           | requires ongoing resources.
           | 
           | At the end of the day, I don't think it really matters that
           | much. The corps are providing a service not a software
           | application. If they weren't using BSD, they'd be using
           | something else.
        
           | [deleted]
        
           | chasil wrote:
           | There used to be complaint from OpenBSD that large corporate
           | users of OpenSSH weren't donating anything, so I sent them
           | $100.
           | 
           | Those days appear to be over.
           | 
           | https://www.theregister.com/2015/07/08/microsoft_donates_to_.
           | ..
        
           | iE4mHBzmoYezwbx wrote:
           | Really? Their biggest donors are large and extraordinarily
           | profitable tech enterprises. (Like Google, Microsoft, and
           | Facebook)
           | 
           | And thus the success of BSD-style licensing is thrown into
           | sharp relief. (Also the fact that you or I can go use it as
           | much as we want for free and do whatever we want to it.)
        
       | alberth wrote:
       | This is beyond my knowledge but is this akin to macOS
       | binary/memory protection for the base system OS?
        
         | landr0id wrote:
         | Different. These are enhanced mitigations to detect when a
         | program is calling into the kernel from a weird state that
         | should never happen in a well-formed program. It basically
         | prevents certain types of exploits from successfully calling
         | into the kernel.
         | 
         | *the new mitigation just makes user-mode memory completely
         | immutable. You can never "upgrade" a page's permissions or
         | change its contents after it's been marked as immutable.
        
         | geraldcombs wrote:
         | As a more general question, is there a resource available that
         | shows which memory protection schemes are available on various
         | OSes? It'd be nice to see what the state of the art is on
         | Linux, macOS, the BSDs, etc. in one place.
        
         | pram wrote:
         | Seems like the second blurb is similar to the Page Protection
         | Layer+Pointer Authentication Codes in XNU.
        
           | saagarjha wrote:
           | Not really, PPL protects page tables and PAC provides CFI.
        
       ___________________________________________________________________
       (page generated 2022-09-02 23:01 UTC)