Kexec/Kdump on Secureboot Machines ================================== Problem Description =================== Secureboot wants wants to make sure all the code running at priviliged level is signed by appropriate keys. Kexec allows loading and booting a new kernel without going through firmware. So we need to find a way that on a secureboot kexec does not allow booting something which violates secureboot. What are the components to worry about ===================================== Kexec loads a new kernel, initramfs and purgatory (a binary blob of code which runs at ring 0). Somebody needs to verify signature of kernel being loaded and also one needs to find a way how to trust purgatory code. purgatory code is generated at run time so it can't be signed during build. Solution being worked on ======================== Overview -------- Extend the trust chain to user space. That is sign /sbin/kexec, verify its signature using one of secureboot keys and then make sure nobody is able to modify address space of /sbin/kexec. Once /sbin/kexec is trusted, one can trust purgatory code too. This code is part of /sbin/kexec which is modified by kexec utility. And /sbin/kexec needs to verify signature of vmlinuz before it loads new kernel in memory. /sbin/kexec will take kernel services to verify signature of vmlinuz. keyctl() ioctl has been extended with a new option to allow that. One can pass a user buffer, and signature and specify a keyring so that kernel can verify signature of buffer against specified keyring. In this case /sbin/kexec will signature against .system_keyring. Currently keyctl(KEYCTL_VERIFY_SIGNATURE) can verify only digital signatures as created by Integrity/IMA subsystem. That means we will to sign vmlinuz one more time. And this time use IMA signature and store it in security.ima attr. IMA digital signature --------------------- Integrity management system in kernel already has facility to digitally sign files and verify their signatures. Version 2 of such signatures are basically RSA signature (pkcs1) with some IMA metadata attached. It is very similar to kernel module signatures. Following is digital signature process/format. file.txt --hash--> digest ---(prefix OID)--> hash_algo_oid + digsest hash_algo_oid + digsest --(rsa encryption)--> file.txt.sig IMA puts some metadata before signature. Following is IMA specific meta data. struct signature_v2_hdr { uint8_t version; /* signature format version */ uint8_t hash_algo; /* Digest algorithm [enum pkey_hash_algo] */ uint32_t keyid; /* IMA key identifier - not X509/PGP specific*/ uint16_t sig_size; /* signature size */ uint8_t sig[0]; /* signature payload */ } __attribute__ ((packed)); Above sig[] contains the RSA signature and everything before that is IMA specific signature metadata. These signatures are stored in security.ima xattr of the file being signed. /sbin/kexec Signing ------------------- IMA has a user space utility evmctl which can be used to sign files. It uses openssl API for signing files. We can enhance this utility so that actual RSA signing signatures are generated by signing server and evmctl can later attach its own metadata (as shown above) and generate final signatures. These detached signatures will be generated at build time and these will be installed in security.ima xattr of /sbin/kexec at target during installation time. vmlinuz Signing --------------- We also need to sign vmlinuz in IMA format so that /sbin/kexec can verify its signature. Current kernel does not have infrastructure to verify PE/COFF signature hence we can't make use of vmlinuz signature as signed by pesign. So this additional signing of vmlinuz will take place in same way as /sbin/kexec. Detached signatures will be generated during install time and needs to be installed during rpm installation time. Static Linking of /sbin/kexec ----------------------------- kexec links with other libraries like libc. None of these is signed. So there is no point in verifying the signature of a binary if it can link to unsigned code (dynamically/statically). So we will need to build /sbin/kexec statically. We know that /sbin/kexec does not do any dlopen() calls so there should not be any possibility of running unsigned code after signature verification. Memory Locking of /sbin/kexec ----------------------------- We need to run /sbin/kexec locked in memory. Otherwise it could be swapped out and be open to attack by root and modified/code data could be swapped back in and now we are running unsigned code. So we need to make sure that no part of /sbin/kexec gets swapped out. That means we need a way to tell kernel that a particular executable needs to run memory locked. I have enhanced evmctl to put additional metadata in security.ima which tels kernel to memlock the eecutable. Kernel elf loader checks for this. Following is the header I place after IMA signature I put in security.ima attr. /* memlocking info header */ #define MEMLOCK_MAGIC_STR "MEMLOCK" struct memlock_hdr { uint8_t magic_str[8]; /* magic to detect memlock hdr presence */ uint8_t version; /* memlock info hdr version */ uint8_t memlock_file; /* If set, run executable locked in memory */ } __attribute__ ((packed)); Disable ptrace to /sbin/kexec ----------------------------- I have disabled ptrace() to a signed eecutable by an unsigned process. If parent was already being ptraced before one did exec() on /sbin/kexec, then this executable is not trusted by kernel sys_kexec() system call and kernel loading will fail. So nobody should be ptracing /sbin/kexec for it to succeed. Kernel ELF loader Changes ------------------------- Kernel ELF loader cheks whether an executable is signed and if it should be run memlocked. If that's the case, it maps executable, locks it down in memory does signature verification, makes sure nobody is ptracing it and if everything is fine, it sets a flag (proc_signed) in task credential structure. Kernel kexec system call changes -------------------------------- This system call checks if secureboot is enabled or not. If secureboot is enabled, then it allows loading kernel only if proc_signed flag is set in task credential structure. And ELF loader will set this flag if all conditions of being signed are met. Signing Key management ---------------------- I think it is a good idea to embed fedora certificate in kernel and then use it to sign /sbin/kexec signing key. This chaining will allow us to revoke kexec key and send out updated kexec signed with new key. This key chaining will mean that new key will need to be loaded everytime kernel boots. kdump is a service. we can probably ship this key with kexec-tools package, drop in some dir and everytime kdump service runs, it can first try to load the keys in kernel. David Howells already has written functionality to load keys in .system_keyring as long as they have been signed by any other key in the keyring. Right now it seems to support PE/COFF keys. But we might want to go for more standard way. That is generate x509 cert for signing and have this certificate signed by fedora cert which is embedded in kernel. And then let add_key() add this 509 cert to .system_keyring. Last I talked to David Howells, looks like loading x509 certs to trusted keyrings is still not supported and we might have to work on it. Note: Code for not trusting /sbin/kexec if it has been blacklisted has not been written yet. Importing MOK and firmware keys in second kernel ------------------------------------------------ Currently kernel makes EFI runtime calls to import firmware and MOK keys in system_keyring in kernel. Currently kexec/kdump is implemented in such a way that it does not allow making EFI run time calls. This is an historical issue of kexec/kdump with UEFI irrespective of secureboot. So we can't import keys from firmware/MOK. That means only keys embedded in kernel at build time will show up in system_keyring. That also means that 3rd party drivers will not be loaded in second kernel. Once all the basic stuff starts working, I think one can look into what is required to make kexec/kdump work with UEFI so that one can make EFI run time calls in second kernel.