Merge ~juliank/grub/+git/ubuntu:juliank/check-signed-kernels into ~ubuntu-core-dev/grub/+git/ubuntu:ubuntu

Proposed by Julian Andres Klode
Status: Merged
Merged at revision: c42ceff265d3b79295c139e9e795d646c045f05a
Proposed branch: ~juliank/grub/+git/ubuntu:juliank/check-signed-kernels
Merge into: ~ubuntu-core-dev/grub/+git/ubuntu:ubuntu
Diff against target: 166 lines (+123/-0)
5 files modified
debian/changelog (+8/-0)
debian/grub-check-signatures (+94/-0)
debian/grub-common.install.in (+1/-0)
debian/postinst.in (+4/-0)
debian/templates.in (+16/-0)
Reviewer Review Type Date Requested Status
Steve Langasek Needs Fixing
Review via email: mp+345403@code.launchpad.net

Commit message

Check that kernels are signed

To post a comment you must log in.
Revision history for this message
Steve Langasek (vorlon) :
review: Needs Fixing
Revision history for this message
Steve Langasek (vorlon) wrote :

should actually check both /sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c != 0 && /sys/firmware/efi/efivars/MokSBStateRT-605dab50-e046-4300-abb6-3dd810dd8b23 != 1. mokutil unhelpfully gives no information about the latter, so you'll need to directly read the files. See /usr/sbin/update-secureboot-policy for examples.

*Ideally*, we would verify that the kernel is not just signed, but signed with a key that's trusted by the firmware (so: found in db, or in MokListRT). Requires a bit more code, but I believe it's warranted.

Revision history for this message
Julian Andres Klode (juliank) wrote :

It now looks at all kernels in /boot, rather then finding via grub.cfg (so we can run before update-grub), checks the policy in the postinst, and only if we are on secure boot.

I have not found any solution to check if it's signed with the right key, though. What I figured out is that sbverify needs a certificate, and mokutil can give me a list of keys.

Revision history for this message
Steve Langasek (vorlon) wrote :

Comments inline.

One additional concern: the grub maintainer script is not the only place that grub-install might be called. In particular, shim-signed will also call grub-install --target=x86_64-efi from its postinst - as will grub-efi-amd64-signed, which is from a different source package. And with the most recent adjustment of the dependencies (grub-efi-amd64-signed now depends on grub-efi-amd64 | grub-pc; which means some users in 18.04 and newer will actually have grub-pc installed, whose postinst /should not/ fail to configure due to the kernel secureboot question), grub-efi-amd64-signed may actually have its dependencies satisfied even though there are unsigned kernels.

So I think the right place for the grub-check-signatures code to run is as an inlined wrapper of grub-install. Do you agree?

review: Needs Fixing
Revision history for this message
Julian Andres Klode (juliank) wrote :

> Comments inline.
>
> One additional concern: the grub maintainer script is not the only place that
> grub-install might be called. In particular, shim-signed will also call grub-
> install --target=x86_64-efi from its postinst - as will grub-efi-amd64-signed,
> which is from a different source package. And with the most recent adjustment
> of the dependencies (grub-efi-amd64-signed now depends on grub-efi-amd64 |
> grub-pc; which means some users in 18.04 and newer will actually have grub-pc
> installed, whose postinst /should not/ fail to configure due to the kernel
> secureboot question), grub-efi-amd64-signed may actually have its dependencies
> satisfied even though there are unsigned kernels.
>
> So I think the right place for the grub-check-signatures code to run is as an
> inlined wrapper of grub-install. Do you agree?

Your review on the last diff said to only check when we are switching the secure boot policy in grub - the only place we can do this is from the grub maintainer scripts, as we need to have the grub version to check against.

We specifically can't do that in grub-install, since grub-install may be used for a lot of stuff other than installing stuff to the ESP. Hence the previous approach checked it in update-grub.

I don't see why grub-pc should not fail due to secure boot if it's on an EFI system in secure boot mode.

Revision history for this message
Julian Andres Klode (juliank) :
Revision history for this message
Steve Langasek (vorlon) wrote :

A few final comments inline, nothing that should block landing this. Please resolve these comments as you see fit and land this change.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/debian/changelog b/debian/changelog
index e02ed3f..7c43119 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
1grub2 (2.02-2ubuntu11) UNRELEASED; urgency=medium
2
3 [ Julian Andres Klode ]
4 * Verify that the current and newer kernels are signed when grub is updated, to
5 make sure people do not accidentally shutdown without a signed kernel.
6
7 -- Julian Andres Klode <juliank@ubuntu.com> Wed, 20 Jun 2018 13:04:33 +0200
8
1grub2 (2.02-2ubuntu10) cosmic; urgency=medium9grub2 (2.02-2ubuntu10) cosmic; urgency=medium
210
3 * debian/patches/grub-shell-test-helper-disable-seabios-sercon.patch: In the11 * debian/patches/grub-shell-test-helper-disable-seabios-sercon.patch: In the
diff --git a/debian/grub-check-signatures b/debian/grub-check-signatures
4new file mode 10075512new file mode 100755
index 0000000..3a466ec
--- /dev/null
+++ b/debian/grub-check-signatures
@@ -0,0 +1,94 @@
1#!/bin/sh
2
3set -e
4
5. /usr/share/debconf/confmodule
6
7# Check if we are on an EFI system
8efivars=/sys/firmware/efi/efivars
9secureboot_var=SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c
10moksbstatert_var=MokSBStateRT-605dab50-e046-4300-abb6-3dd810dd8b23
11
12on_secure_boot() {
13 # Validate any queued actions before we go try to do them.
14 local moksbstatert=0
15
16 if ! [ -d $efivars ]; then
17 return 1
18 fi
19
20 if ! [ -f $efivars/$secureboot_var ] \
21 || [ "$(od -An -t u1 $efivars/$secureboot_var | awk '{ print $NF }')" -ne 1 ]
22 then
23 return 1
24 fi
25
26 if [ -f /proc/sys/kernel/moksbstate_disabled ]; then
27 moksbstatert=$(cat /proc/sys/kernel/moksbstate_disabled 2>/dev/null || echo 0)
28 elif [ -f $efivars/$moksbstatert_var ]; then
29 # MokSBStateRT set to 1 means validation is disabled
30 moksbstatert=$(od -An -t u1 $efivars/$moksbstatert_var | \
31 awk '{ print $NF; }')
32 fi
33
34 if [ $moksbstatert -eq 1 ]; then
35 return 1
36 fi
37
38 return 0
39}
40
41# Check if a given kernel image is signed
42is_signed() {
43 tmp=$(mktemp)
44 sbattach --detach $tmp $1 >/dev/null # that's ugly...
45 test "$(wc -c < $tmp)" -ge 16 # Just _some_ minimum size
46 result=$?
47 rm $tmp
48 return $result
49}
50
51# Check that our current kernel and every newer one is signed
52find_unsigned() {
53 uname_r="$(uname -r)"
54 for kernel in $(ls -1 /boot/vmlinuz-* | sort -V -r); do
55 # no kernels :(
56 if [ "$kernel" = "/boot/vmlinuz-*" ]; then
57 break
58 fi
59 this_uname_r="$(echo "$kernel" | sed -r 's#^/boot/vmlinuz-(.*)#\1#; s#\.efi\.signed$##')"
60 if dpkg --compare-versions "$this_uname_r" lt "$uname_r"; then
61 continue
62 fi
63 if ! is_signed $kernel; then
64 echo "$this_uname_r"
65 fi
66 done
67}
68
69# Only reached from show_warning
70error() {
71 echo "E: Your kernels are unsigned. This system will fail to boot in a secure boot environment." >&2
72 exit 1
73}
74
75# Either shows a debconf note or prints an error with error() above if
76# that fails
77show_warning() {
78 # kernels should be an indented list of one version per line
79 escaped="$(printf "%s" "$unsigned" | sed "s#^# #" | debconf-escape -e )"
80 db_capb escape
81 db_settitle grub2/unsigned_kernels_title || error
82 db_fset grub2/unsigned_kernels seen 0 || error
83 db_subst grub2/unsigned_kernels unsigned_versions "$escaped" || error
84 db_input critical grub2/unsigned_kernels || error
85 db_go || error
86 error
87}
88
89if on_secure_boot; then
90 unsigned="$(find_unsigned)"
91 if [ -n "$unsigned" ]; then
92 show_warning "$unsigned"
93 fi
94fi
diff --git a/debian/grub-common.install.in b/debian/grub-common.install.in
index f06320d..59d3462 100644
--- a/debian/grub-common.install.in
+++ b/debian/grub-common.install.in
@@ -1,5 +1,6 @@
1../../debian/apport/source_grub2.py usr/share/apport/package-hooks/1../../debian/apport/source_grub2.py usr/share/apport/package-hooks/
2../../debian/grub.d etc2../../debian/grub.d etc
3../../debian/grub-check-signatures usr/share/grub/
34
4etc/bash_completion.d5etc/bash_completion.d
5etc/grub.d6etc/grub.d
diff --git a/debian/postinst.in b/debian/postinst.in
index b1435d3..5c8c93d 100644
--- a/debian/postinst.in
+++ b/debian/postinst.in
@@ -320,6 +320,10 @@ case "$1" in
320320
321 devicemap_regenerated=321 devicemap_regenerated=
322322
323 if [ @PACKAGE@ = "grub-efi-amd64" ] && dpkg --compare-versions "$2" lt-nl 2.02-2ubuntu11; then
324 /usr/share/grub/grub-check-signatures
325 fi
326
323 if egrep -q '^[[:space:]]*post(inst|rm)_hook[[:space:]]*=[[:space:]]*(/sbin/|/usr/sbin/)?update-grub' /etc/kernel-img.conf 2>/dev/null; then327 if egrep -q '^[[:space:]]*post(inst|rm)_hook[[:space:]]*=[[:space:]]*(/sbin/|/usr/sbin/)?update-grub' /etc/kernel-img.conf 2>/dev/null; then
324 echo 'Removing update-grub hooks from /etc/kernel-img.conf in favour of' >&2328 echo 'Removing update-grub hooks from /etc/kernel-img.conf in favour of' >&2
325 echo '/etc/kernel/ hooks.' >&2329 echo '/etc/kernel/ hooks.' >&2
diff --git a/debian/templates.in b/debian/templates.in
index e261bb3..4ae3b6e 100644
--- a/debian/templates.in
+++ b/debian/templates.in
@@ -65,3 +65,19 @@ _Description: /boot/grub/device.map has been regenerated
65 .65 .
66 If you do not understand this message, or if there are no custom66 If you do not understand this message, or if there are no custom
67 boot menu entries, you can ignore this message.67 boot menu entries, you can ignore this message.
68
69Template: grub2/unsigned_kernels_title
70Type: title
71_Description: unsigned kernels
72
73Template: grub2/unsigned_kernels
74Type: note
75_Description: Cannot upgrade Secure Boot enforcement policy due to unsigned kernels
76 Your system has UEFI Secure Boot enabled in firmware, and the following kernels
77 present on your system are unsigned:
78 .
79 ${unsigned_versions}
80 .
81 These kernels cannot be verified under Secure Boot. To ensure your system
82 remains bootable, GRUB will not be upgraded on your disk until these kernels are
83 removed or replaced with signed kernels.

Subscribers

People subscribed via source and target branches