EFI GELI support ready for testers

Eric McCorkle eric at metricspace.net
Sat May 28 20:02:46 UTC 2016


> On May 28, 2016, at 13:26, Konstantin Belousov <kostikbel at gmail.com> wrote:
> 
>> On Sat, May 28, 2016 at 10:27:40AM -0400, Allan Jude wrote:
>>> On 2016-05-28 04:36, Konstantin Belousov wrote:
>>>> On Fri, May 27, 2016 at 07:39:57PM -0400, Eric McCorkle wrote:
>>>> I am pleased to announce that my work to add support for GELI in the EFI boot loader (as well as perform more general refactoring) is now ready for testing.  I am able to successfully detect multiple GELI partitions in boot1 and pass the keys into the kernel.
>>> 
>>> Can somebody explain in which way this is useful ?
>>> Same question for the GELI code for non-EFI loader.
>>> 
>>> BIOS cannot read raw data from the encrypted partition, so you need
>>> either old boot or the loader and some additional data on EFI boot
>>> partition anyway.
>>> 
>>> Features adds significant amount of code, which must be maintained in
>>> parallel with the kernel code.
>>> _______________________________________________
>>> freebsd-hackers at freebsd.org mailing list
>>> https://lists.freebsd.org/mailman/listinfo/freebsd-hackers
>>> To unsubscribe, send any mail to "freebsd-hackers-unsubscribe at freebsd.org"
>> 
>> The motivation for my work (GELI in boot2 and loader for non-EFI boot)
>> was supporting ZFS boot environments. Previously, when you use GELI you
>> needed to have two ZFS pools, one for an unencrypted /boot and one for
>> the encrypted /
>> 
>> This breaks ZFS boot environments, since a snapshot of the root file
>> system won't include the correct kernel etc.
> Why cannot /boot included into the boot environment ?
> When I last saw Solaris, somewhere in its 10-th, any amount of
> filesystems could be added to the bootenv.  But whatever the definition
> of bootenv is used, it exists at a level of the shell scripts and selecting
> the actual partition for loader.  Throw thousand lines of code into
> the unstable and very hard to debug environment of loader looks somewhat
> unproductive.

You misunderstand.  Alan was talking about pure ZFS systems, where there is one big ZFS pool holding everything.  You need to be able to access /boot obviously, but ZFS does not allow you to assign separate out data on to a single device.  It creates a pool, which combines all devices.

To have /boot unencrypted, you have to have a separate partition for just /boot, which is undesirable.

>> 
>> The final version of my geliboot took an extra effort to reuse the AES
>> code from sys/crypto/rijndael and sys/opencrypto and GELI directly from
>> sys/geom/eli to avoid maintaining a separate copy of that code in sys/boot
> Which means that kernel code must be also runnable in the strange and
> incompatible environment of the loader. I cannot see how this reduces
> code maintanability even a bit. I am already rather unhappy about ZFS
> kernel code being compiled as the userspace library, which hurt me
> and other people more than once. Now (?) the kernel code must be also
> verified for the loader.

I mean, the loader has to be able to access the filesystems, there's no way around it (barring crazy coreboot stuff).

Also, it should be possible to create a synthetic EFI test-harness that runs in *userland*. EFI is basically just a bunch of tables of function pointers, no bios interrupts or anything.  As long as you implement the interfaces, any loader should also run in your synthetic environment.  I had plans to look into this after this work is done.

>> 
>> Hopefully the work I did to make sys/opencrypto and sys/geom/eli more
>> reusable outside of the kernel will make it easier for Eric to do the
>> same for the EFI version.
>> 
>> The motivation for the EFI version is the same, ZFS boot environments,
>> plus the obvious security advantages of having the kernel stored
>> encrypted rather than not.
> 
> Obvious security advantages ?  Seriously ?
> What is a single 'security' advantage of hiding the kernel ?
> 

There are plenty.

Right up at the top, an attacker able to access /boot is free to tamper with anything, and can insert back-doors into the kernel, loader, or any module.  If you assume that the attacker can't write, then they can still scan the kernel and modules for signatures for known vulnerabilities (since the kernel itself has a commit id and detailed version info, they can compare this against a CVE database).  Even if they can't do that for some reason, they could still potentially exfilt a kernel address map for use in rootkit attacks against your system.  Lastly, general security principles say to minimize the attack surface, which would definitely mean you should protect the core of the system.

> Since you noted a 'security', I realized that your changes decrypt the
> keys in the pre-kernel environment. In other words, very sensitive
> material becoming accessible to strange and unknown code which is
> managed by firmware.

The likelihood of such an attack, while something I considered, is very low.  A key should look like random binary data (much like the GUIDs prevalent in EFI code).  I seriously doubt someone could write a firmware module that could dig through the memory state of an arbitrary OS's boot loader and find keys.  You'd basically have to put a full online binary analysis framework in the firmware, and have it run fast enough to not be noticed.  That would be some serious Turing award-worthy work kept secret from the world solely to build firmware backdoors.  I don't think even Lenovo would go that far.

(I know I mentioned scanning the kernel as a threat above; that's an offline attack that can be done on a copy.  Online undetectable analysis of a running program is WAY harder.)

Besides, if someone wants to do evil things in firmware, I think it's far more likely they'd just backdoor the network or USB controllers to let someone send an override packet and execute bundled code in kernel mode.  That works every time for every OS and doesn't require surreptitiously picking apart arbitrary programs' data structures in real time.

For what it's worth, I have considered possible hardening measures: using alias GUIDs to disguise interfaces and adding per-build padding or XOR masks to structures with keys to throw off scanners.  However, I don't think the threat is realistic enough to warrant such measures.

> Putting aside ineradicable evil of Intel ME or its
> AMD twin, and SMM handler, you are exposing keys to whatever code happen
> to inhabit the preboot env, not neccessary originating from the firmware
> vendor.  Secure Boot would not help there, since when the measurement
> indicate that untrusted component was there, it is too late.  I.e.,
> you making much easier for malice hacker to steal the keys.

I mean, the same argument holds for the kernel, if not moreso.  You have ACPI bytecode, SMM, device blobs, anything that the boot environment chose to keep around for runtime by marking that memory as "unavailable", and of course, the evil that is Intel ME.  This is an unavoidable risk of having keys in main memory ever.

If you really want any kind of safety from this, you need to use a hardware crypto device that stores keys in a separate memory (which, I specifically designed things to make it easy to add support for one).  Of course, you then have to trust the device...

> _______________________________________________
> freebsd-hackers at freebsd.org mailing list
> https://lists.freebsd.org/mailman/listinfo/freebsd-hackers
> To unsubscribe, send any mail to "freebsd-hackers-unsubscribe at freebsd.org"


More information about the freebsd-hackers mailing list