OpenBSD kernel address randomized link
A less than two-month-old project for OpenBSD, kernel address space randomized link (KARL), has turned the kernel into an object that is randomized on every boot. Instead of the code being stored in the same location for every boot of a given kernel, each boot will be unique. Unlike Linux's kernel address space layout randomization (KASLR), which randomizes the base address for all of the kernel code on each boot, KARL individually randomizes the object files that get linked into the binary. That means that a single information leak of a function address from the kernel does not leak information about the location of all other functions.
Theo de Raadt first posted about the idea on the OpenBSD tech mailing list on May 30. He described the current layout of the OpenBSD kernel code, which is effectively the boot code and assembly runtime (in locore.o), followed by the kernel .o files in a fixed order. His post had some changes that would split out the assembly runtime from locore.o and link it and all of the kernel .o files in a random order. The only piece that would be placed at a known address would be locore.o; it would be followed by a randomly sized gap, then by the kernel text that has its .o files arranged in a random order. There would also be random gaps before other sections (i.e. .rodata, .data, and .bss) that are placed after the kernel text.
Once the kernel was booted, locore.o would still contain a reference to the kernel text in the form of the address of main() (at a known offset in locore.o). So, once the kernel is up, locore.o is either unmapped or destroyed depending on the architecture. The idea is to thwart return-oriented programming (ROP) attacks against the kernel, De Raadt said:
That new layout set the stage for KARL, which De Raadt described in a post on June 12. Reworking the layout still means that the execution of a particular kernel version would always have the same addresses. For users of binary kernels provided by OpenBSD, for example, that would mean an attacker simply needs a copy of the kernel to extract the information they need—no real improvement on the current situation.
What KARL does is to ensure that, every time the kernel is booted, it gets a freshly linked version—new addresses for everything, essentially. De Raadt and Robert Peichaer created a "link kit" that contains all of the kernel .o files needed. After each boot, an rc script links a new kernel in the background and installs it. On the next reboot, a different kernel will be run that, in turn, creates the next kernel. De Raadt said that the link process takes less than a second on a fast machine.
There were still some more pieces of the puzzle to solve: kernel relinks were needed at install time, upgrade time, and when users install their own kernels. De Raadt was back with a post on June 30 that solved all of those problems. In particular, unique kernels are automatically built at install, upgrade, and boot time. In addition, if a new kernel is built and installed with "make install" the link kit will be updated with those objects so that the next boot will result in a new kernel. For debugging purposes, though, if someone copies their own kernel to /bsd, the relinks stop happening until they are re-enabled.
De Raadt asked that users test the feature hard, so that it will be ready
for the 6.2 release slated for later this year. Overall, it is an
interesting feature that should provide more security at a fairly low
cost. It also came about quickly—eye-openingly so—though De Raadt said he
has been talking about it with various other OpenBSD developers for five
years or so (it "never got off to a good start, probably because I was
trying to pawn the work off on others
"). It is not inconceivable
that Linux could do something similar some day, though one might guess that
it would
take a fair amount longer than a few months and one release cycle to make
that kind of change.
Index entries for this article | |
---|---|
Security | OpenBSD |
OpenBSD kernel address randomized link
Posted Jul 13, 2017 0:26 UTC (Thu)
by ikm (subscriber, #493)
[Link] (10 responses)
Posted Jul 13, 2017 0:26 UTC (Thu) by ikm (subscriber, #493) [Link] (10 responses)
Sounds scary. That would require the installation to be fully atomic, as otherwise an unfortunate power loss at this moment could leave the system in a permanently unbootable state.
OpenBSD kernel address randomized link
Posted Jul 13, 2017 4:04 UTC (Thu)
by lkurusa (guest, #97704)
[Link]
Posted Jul 13, 2017 4:04 UTC (Thu) by lkurusa (guest, #97704) [Link]
OpenBSD kernel address randomized link
Posted Jul 13, 2017 9:09 UTC (Thu)
by farnz (subscriber, #17727)
[Link] (8 responses)
Posted Jul 13, 2017 9:09 UTC (Thu) by farnz (subscriber, #17727) [Link] (8 responses)
Assuming OpenBSD implements the expected POSIX behaviours (and I'd be surprised if it didn't - this is one of the saner bits of POSIX), this is easy to arrange:
- Boot from kernel.
- Link new kernel into same filesystem, under the name kernel.new.
- Use fsync and/or sync to ensure that all data is written out to disk.
- Use rename to atomically replace kernel with kernel.new.
Throughout this process, the system stays atomically in one of two states:
- kernel is the currently running kernel, not yet replaced by kernel.new. kernel.new may or may not exist, and may or may not be a bootable kernel at this point.
- kernel is the newly built kernel.
You can increase safety by first using link to ensure that kernel.booted is the last kernel to boot as far as running the linker, and teaching the bootloader to try it if kernel fails to boot for any reason - that way, you get a second chance if the new kernel is mislinked due to a bug.
OpenBSD kernel address randomized link
Posted Jul 13, 2017 12:07 UTC (Thu)
by nix (subscriber, #2304)
[Link] (4 responses)
Posted Jul 13, 2017 12:07 UTC (Thu) by nix (subscriber, #2304) [Link] (4 responses)
This is, IMHO, entirely GRUB2's fault, for implementing an XFS filesystem reading driver that doesn't actually read the filesystem in the same way that XFS itself has (and *always* has: this is not a recent optimization).
OpenBSD kernel address randomized link
Posted Jul 13, 2017 13:20 UTC (Thu)
by farnz (subscriber, #17727)
[Link]
Posted Jul 13, 2017 13:20 UTC (Thu) by farnz (subscriber, #17727) [Link]
That sort of buggy behaviour is precisely the sort of bug I was thinking of when I said "Assuming OpenBSD implements the expected POSIX behaviours"; it sounds like the combination of GRUB2 and Linux does not implement the expected POSIX behaviours.
And I'd agree with you on the blame; while I can see why GRUB2 wouldn't want to do a log replay itself, it should at least check the log first, then the backing store if the log has no recent changes - that way, it won't read something unexpected.
OpenBSD kernel address randomized link
Posted Jul 13, 2017 13:22 UTC (Thu)
by tialaramex (subscriber, #21167)
[Link] (2 responses)
Posted Jul 13, 2017 13:22 UTC (Thu) by tialaramex (subscriber, #21167) [Link] (2 responses)
Does XFS have read-only mounts? How do they interact with this... let's call it an optimisation?
Historically it seems like XFS log is not very big, so a correct implementation could read the entire thing into RAM, and consult it throughout all further operations. Obviously that's going to be both slow and error-prone, because it's basically taking a lot of situations where there's a happy path and splitting them into two similar but different happy paths one of which is very difficult to test. Is that really how all bootloaders designed to work with XFS do it?
I presume that the XFS authors focused instead on, as you say, "replaying the log at mount time", converting the mount to read-write on the fly which is cool but obviously there is no promise that's _possible_ let alone a good idea.
OpenBSD kernel address randomized link
Posted Jul 14, 2017 23:55 UTC (Fri)
by rahvin (guest, #16953)
[Link]
Posted Jul 14, 2017 23:55 UTC (Fri) by rahvin (guest, #16953) [Link]
Without knowing anything about Grub's code I would say it shouldn't be that difficult to change the Grub2 behavior to the proper methodology without significant speed impacts because the kernels already got all that sorted out. The problem is likely that the Grub2 project isn't sexy, has limited contributors and it's not a popular issue, the single greatest weakness of getting any problem addressed in open source when you can't fix it yourself. Feel free to correct me if I'm wrong.
OpenBSD kernel address randomized link
Posted Jul 17, 2017 17:32 UTC (Mon)
by ikm (subscriber, #493)
[Link]
Posted Jul 17, 2017 17:32 UTC (Mon) by ikm (subscriber, #493) [Link]
OpenBSD kernel address randomized link
Posted Jul 15, 2017 21:46 UTC (Sat)
by lsl (subscriber, #86508)
[Link] (1 responses)
Posted Jul 15, 2017 21:46 UTC (Sat) by lsl (subscriber, #86508) [Link] (1 responses)
AIUI, the atomicity guarantees are with respect to other processes inspecting the file system concurrently. POSIX guarantees nothing whatsoever about the state of the system following a hard system crash or power loss. Finding your kernel image replaced by a picture of Rick Astley should be perfectly fine as far as POSIX is concerned.
OpenBSD kernel address randomized link
Posted Jul 16, 2017 12:44 UTC (Sun)
by farnz (subscriber, #17727)
[Link]
Posted Jul 16, 2017 12:44 UTC (Sun) by farnz (subscriber, #17727) [Link]
To be completely pedantic, POSIX is fine with your system exploding in a shower of sparks after power loss or a hard crash. However, if you've implemented the concurrent access rules POSIX requires, and you've implemented the data integrity after sync rules that POSIX requires, then assuming that you've implemented any sort of reasonable behaviour after a power loss or hard system crash, and that the hardware does not fail, you'll see atomicity.
OpenBSD kernel address randomized link
Posted Jul 17, 2017 3:32 UTC (Mon)
by Jonno (subscriber, #49613)
[Link]
Posted Jul 17, 2017 3:32 UTC (Mon) by Jonno (subscriber, #49613) [Link]
Actually, that is not true. After step 4 the file will be safely on disk, but the directory will not be. If power fails after you did the rename but before the directory is synced the directory listing can be anything. As far as POISIX is concerned, a directory is a file whose content is an implementation defined mapping from filename to inode. In step 4 you are editing that content in-place. The dangers of doing this is exactly the same as the dangers of editing any other file in-place.
As a practical matter, if the directory is no larger than a single block, writes are going to be atomic (at least at the interface level, what the drive does internally is another matter), but for large directories all bets are of. This race condition can not be entirely avoided, but can be shortened by using fsync on the directory immediately after step 4.
OpenBSD kernel address randomized link
Posted Jul 13, 2017 5:04 UTC (Thu)
by mjthayer (guest, #39183)
[Link]
Posted Jul 13, 2017 5:04 UTC (Thu) by mjthayer (guest, #39183) [Link]
OpenBSD kernel address randomized link
Posted Jul 13, 2017 10:32 UTC (Thu)
by dskoll (subscriber, #1630)
[Link] (3 responses)
Posted Jul 13, 2017 10:32 UTC (Thu) by dskoll (subscriber, #1630) [Link] (3 responses)
OpenBSD kernel address randomized link
Posted Jul 13, 2017 12:03 UTC (Thu)
by matthias (subscriber, #94967)
[Link] (1 responses)
Posted Jul 13, 2017 12:03 UTC (Thu) by matthias (subscriber, #94967) [Link] (1 responses)
For secure boot I would design sth. like a boot loader and linker (opposed to just a boot loader). In this scenario, a kernel is a signed tar.gz (or sth. equivalent) containing a buch of .o files. The boot loader and linker would
- be signed itself (signature verified by secure boot)
- check the signature of the kernel
- untar the kernel
- link the kernel
- execute the kernel
Probably this can be achieved with some initramfs and the kexec mechanism. To avoid some overhead (and problems with kexec not always being available), one could implement a grub module. Actually, this is roughly what I was thinking of when starting to read the article.
There could be one additional problem: Where to get good random data in very early boot? Apart from this problem, my solution should be cleaner. E.g., it would also work for embedded systems, without writeable permanent storage. However, it will be more work to implement.
OpenBSD kernel address randomized link
Posted Jul 13, 2017 17:34 UTC (Thu)
by Nahor (subscriber, #51583)
[Link]
Posted Jul 13, 2017 17:34 UTC (Thu) by Nahor (subscriber, #51583) [Link]
I think the kernel already has a linker (for modules).
And this also works for IoT devices, where the filesystem is likely RO.
DAX would be an issue though.
All that said, the solution seems so obvious that I'm sure I'm missing something critical...
OpenBSD kernel address randomized link
Posted Jul 15, 2017 0:08 UTC (Sat)
by rahvin (guest, #16953)
[Link]
Posted Jul 15, 2017 0:08 UTC (Sat) by rahvin (guest, #16953) [Link]
The shim loads the microsoft signed key, has the bios validate and loads the bootloader, but to retain a secure boot codepath then the bootloader needs to be signed by a key the shim knows, then the bootloader loads the kernel which is signed by a key the bootloader knows, etc, etc, etc. Secure boot arguably isn't much use if you don't sign all the way down the chain to the boot kernel at least. Then if you want to be really secure you have to sign modules, programs and everything after the kernel with a key the kernel can validate. Fully implemented you shouldn't be able to get anything executed during boot that isn't cryptographicly signed and presumably unmodified.
The problem's always been that everything's got to be signed (and presumably the private key isn't available on the disk for someone to start signing stuff) so you can verify nothing's been tampered with. This signing is a non-trivial task. The cool thing is if you can get something like this working you've got a lot of confidence up to that point that nothing unapproved is loaded (although this doesn't protect you from bugs at all). The hard part is getting this simple enough that it's not a 2 day effort to patch security vulnerabilities. I believe they're working towards this goal with the future of secure boot and TPM.
OpenBSD kernel address randomized link
Posted Jul 19, 2017 14:50 UTC (Wed)
by cesarb (subscriber, #6266)
[Link]
Posted Jul 19, 2017 14:50 UTC (Wed) by cesarb (subscriber, #6266) [Link]