diff --git a/doc/guix.texi b/doc/guix.texi index 2cf5595329..e14c69a5c3 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -42327,6 +42327,24 @@ It requires a @code{'disk} target providing either a @code{device}, @item @code{extlinux-gpt-bootloader} This is the same as above, but for systems with a GPT partition table. +@cindex Secure Boot, UEFI +@vindex uki-efi-bootloader +@item @code{uki-efi-bootloader} +Makes and installs UKI images for UEFI systems. Requires an @code{'esp} +target providing a @code{path} to the mount point of the EFI System +Partition. Not all system generations may be available with this +option, as UKI images contain the entire kernel and initramfs, and ESPs +tend to be small. + +Full disk encryption with @code{uki-efi-bootloader} only requires a +single password entry with fast decryption, in contrast to GRUB2 +requiring a second password entry with slow, LUKS1-only decryption. + +This is the only bootloader to currently support UEFI Secure Boot, when +configured as below. + +[THE CONFIGURATION BELOW] + @cindex ARM, bootloaders @cindex AArch64, bootloaders @vindex u-boot-a20-olinuxino-lime-bootloader @@ -42695,8 +42713,11 @@ The list of commands for loading Multiboot modules. For example: @end lisp @item @code{chain-loader} (default: @code{#f}) -Varies slightly depending on bootloader. For @code{grub}, this is anything that -the @code{chainloader} directive can accept +Varies slightly depending on bootloader. For @code{grub}, this is +anything that the @code{chainloader} directive can accept +(@pxref{Chain-loading,,, grub, GNU GRUB manual}). For @code{uki-efi}, +this is any efi binary to be installed alongside the system. The +following is an example of chainloading a different GNU/Linux system. @lisp (bootloader diff --git a/gnu/bootloader.scm b/gnu/bootloader.scm index 812193feb8..2e0a297e30 100644 --- a/gnu/bootloader.scm +++ b/gnu/bootloader.scm @@ -105,6 +105,7 @@ (define-module (gnu bootloader) bootloader-configuration-default-entry bootloader-configuration-efi-removable? bootloader-configuration-32bit? + bootloader-configuration-keypair bootloader-configuration-timeout bootloader-configuration-keyboard-layout bootloader-configuration-theme @@ -613,6 +614,8 @@ (define-record-type* (default #f)) ;bool (32bit? bootloader-configuration-32bit? (default #f)) ;bool + (keypair bootloader-configuration-keypair + (default #f)) ;(cert . priv) pair (timeout bootloader-configuration-timeout (default 5)) ;seconds as integer (keyboard-layout bootloader-configuration-keyboard-layout diff --git a/gnu/bootloader/uki.scm b/gnu/bootloader/uki.scm new file mode 100644 index 0000000000..848b7618e9 --- /dev/null +++ b/gnu/bootloader/uki.scm @@ -0,0 +1,106 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2024 Lilah Tascheter +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see . + +(define-module (gnu bootloader uki) + #:use-module (gnu bootloader) + #:use-module (gnu packages bootloaders) + #:use-module (gnu packages efi) + #:use-module (gnu packages linux) + #:use-module (gnu system boot) + #:use-module (guix gexp) + #:use-module (guix diagnostics) + #:use-module (guix i18n) + #:use-module (guix records) + #:use-module (ice-9 match) + #:export (uki-efi-bootloader)) + +;; TODO: Support 32bit/mixed-mode UEFI. May be relevant: +;; https://github.com/systemd/systemd/issues/17056 +(define (menu-entry+bootcfg->builder entry bootcfg) + (match-menu-entry entry + (label linux linux-arguments initrd chain-loader) + (match-bootloader-configuration bootcfg (32bit? theme keypair) + (cond + ;; Support chainloader in order to allow arbitrary signed EFI + ;; binaries. + (chain-loader + (match keypair + ((cert key) + #~(lambda (dest) + (invoke/quiet #+(sbsigntools "/bin/sbsign") + "--cert" #$cert "--key" #$key + "--output" dest #$chain-loader) + (invoke/quiet #+(sbsigntools "/bin/sbverify") + "--cert" #$(car keypair) dest))) + (#f #~(lambda (dest) (copy-file #$chain-loader dest))))) + (linux + (let* ((arch (efi-arch #:32? 32bit?)) + (stub (file-append systemd-stub "/libexec/linux" arch + ".efi.stub"))) + #~(lambda (dest) + (invoke/quiet + #+(file-append ukify "/bin/ukify") "build" + "--output" dest "--linux" #$linux "--initrd" #$initrd + "--cmdline" (string-join (list #$@linux-arguments)) + "--os-release" #$label "--stub" #$stub + "--efi-arch" #$arch + #$@(if theme #~("--splash" #$theme) '()) + #$@(match keypair + ((cert key) + #~("--secureboot-certificate" #$cert + "--secureboot-private-key" #$key)) + (#f '())))))) + (else + (leave + (G_ "uki-efi-bootloader doesn't support multiboot"))))))) + +;; We cannot use Guix's build system to make UKI images for two reasons: +;; 1. signing is necessarily non-reproducable, especially since keys +;; should not be in the store, or else risk being publically accessible. +;; 2. Menu-entries may reference files which do not exist in the store. +(define* (install-uki #:key + bootloader-config + current-boot-alternative + old-boot-alternatives + #:allow-other-keys) + (define* (menu-entry->plan entry num #:optional (prefix "menu-entry")) + #~(cons* #$(menu-entry+bootcfg->builder entry bootloader-config) + #$(string-append prefix "-" (number->string num) ".efi") + #$(menu-entry-label entry))) + + (define (boot-alternative->plan alt) + (menu-entry->plan (boot-alternative->menu-entry alt) + (boot-alternative-generation alt) + "generation")) + + (install-efi + bootloader-config + (let ((entries + (bootloader-configuration-menu-entries bootloader-config))) + #~(list #$(boot-alternative->plan current-boot-alternative) + #$@(map menu-entry->plan entries (iota (length entries))) + #$@(map boot-alternative->plan old-boot-alternatives))))) + +(define uki-efi-bootloader + (bootloader + (name 'uki-efi) + (default-targets (list (bootloader-target + (type 'vendir) + (offset 'esp) + (path "EFI/Guix")))) + (installer install-uki))) diff --git a/gnu/local.mk b/gnu/local.mk index 5ecbf0f615..78235340c5 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -94,6 +94,7 @@ GNU_SYSTEM_MODULES = \ %D%/bootloader/extlinux.scm \ %D%/bootloader/u-boot.scm \ %D%/bootloader/depthcharge.scm \ + %D%/bootloader/uki.scm \ %D%/ci.scm \ %D%/compression.scm \ %D%/home.scm \