Signing ELF binaries
As part of the effort to support UEFI secure boot on Linux, Matthew Garrett proposed a number of restrictions on kernel features so that signed kernels could not be used to circumvent secure boot. Many of those restrictions were fairly uncontroversial, but disabling kexec() was not one of them, so it was dropped in a later patch set. At the time, there was discussion of how to support kexec() in a secure boot world; Vivek Goyal recently posted an RFC patch set to start down that path.
The kexec() system call is used to replace the running kernel with a different program. It can be used to boot a new kernel without going through the BIOS or other firmware, which is exactly what gets it into trouble for secure boot. A running kernel that has been verified by the secure boot mechanism (and thus is trusted) could boot any unsigned, unverified kernel by way of kexec(). The concern is that it would be used to boot Windows in an insecure environment while making it believe it was running under secure boot—exactly what secure boot is meant to prevent. That, in turn, could lead to Linux bootloaders getting blacklisted, which would make it more difficult to boot Linux on hardware certified for Windows 8.
Goyal's patches add the ability to cryptographically sign ELF executables, then have the kernel verify those signatures. If the binary is signed and the signature verifies, it will be executed. While the patch does not yet implement this, the idea is that a signed binary could be given additional capabilities if it verifies—capabilities that would enable kexec(), for example. If the binary is unsigned, it will always be executed. Only if a signed binary fails to verify does it get blocked from execution.
The patches contain a signelf utility that puts a signature based on the private key argument into a .signature ELF section. The signature is calculated by hashing the contents of the PT_LOAD ELF segments, then cryptographically signing the result. It is based on the module signing code that was recently added to the kernel, but instead of just tacking the signature on at the end of the binary, it puts it into the .signature section.
Since any shared libraries used by an executable cannot be trusted (so far, at least, there is no mechanism to verify those libraries), only statically linked executables can be signed and verified. The patches do not stop binaries from using dlopen() directly, however, so Goyal said binaries that do so should not be signed. He is targeting the /sbin/kexec binary that is used to launch kdump, so that users can still get crash dumps, even in a secure-boot-enabled system, but there are other possible uses as well.
When the binfmt_elf loader in the kernel detects a binary with the .signature section, it locks the pages of the executable into memory and verifies the signature. Goyal is trying to avoid situations where the binary is modified after the verification has been done, which is why the executable is locked into memory. If the signature does not verify, the process is killed; unsigned binaries are simply executed as usual.
Beyond just adding the capability for kexec(), there are some other pieces of the puzzle that aren't addressed in the patches. The biggest is the need to disable ptrace() on signed binaries. Otherwise, the signed binary could be subverted in various ways—changing the binary passed to kexec(), for example. In addition, the "to do" list has some key and keyring related issues that need to be sorted out.
There is already a mechanism in the kernel to verify the signature of various kinds of files, though. The Integrity Measurement Architecture (IMA) appraisal extension that was added in Linux 3.7 does much of what Goyal needs, as was pointed out by IMA maintainer Mimi Zohar. While the integrity subsystem targets measuring and verifying the whole system, it already does most of the kinds of signature operations Goyal is looking to add. On the other hand, features like disabling ptrace(), locking the binary into memory, and setting capabilities based on signature verification are well beyond the scope of the integrity subsystem. Goyal is currently looking into using the integrity features and adding secure-boot-specific features on top.
Losing the ability to use kexec() on secure boot systems would be
rather painful. While Garrett's patches do not actually make that change
(because of the outcry from other kernel developers), any distribution that
is trying to enable secure boot is likely to do so. Finding a way to
support that use case, without unduly risking the blacklist wrath of
Microsoft, would be good.
| Index entries for this article | |
|---|---|
| Kernel | Security/UEFI secure boot |
