b141171
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
b141171
From: Rashmica Gupta <rashmica.g@gmail.com>
b141171
Date: Thu, 11 Jun 2020 11:26:23 +1000
b141171
Subject: [PATCH] Add suport for signing grub with an appended signature
b141171
b141171
Add infrastructure to allow firmware to verify the integrity of grub
b141171
by use of a Linux-kernel-module-style appended signature. We initially
b141171
target powerpc-ieee1275, but the code should be extensible to other
b141171
platforms.
b141171
b141171
Usually these signatures are appended to a file without modifying the
b141171
ELF file itself. (This is what the 'sign-file' tool does, for example.)
b141171
The verifier loads the signed file from the file system and looks at the
b141171
end of the file for the appended signature. However, on powerpc-ieee1275
b141171
platforms, the bootloader is often stored directly in the PReP partition
b141171
as raw bytes without a file-system. This makes determining the location
b141171
of an appended signature more difficult.
b141171
b141171
To address this, we add a new ELF note.
b141171
b141171
The name field of shall be the string "Appended-Signature", zero-padded
b141171
to 4 byte alignment. The type field shall be 0x41536967 (the ASCII values
b141171
for the string "ASig"). It must be the final section in the ELF binary.
b141171
b141171
The description shall contain the appended signature structure as defined
b141171
by the Linux kernel. The description will also be padded to be a multiple
b141171
of 4 bytes. The padding shall be added before the appended signature
b141171
structure (not at the end) so that the final bytes of a signed ELF file
b141171
are the appended signature magic.
b141171
b141171
A subsequent patch documents how to create a grub core.img validly signed
b141171
under this scheme.
b141171
b141171
Signed-off-by: Daniel Axtens <dja@axtens.net>
b141171
Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>
b141171
b141171
---
b141171
b141171
You can experiment with this code with a patched version of SLOF
b141171
that verifies these signatures. You can find one at:
b141171
   https://github.com/daxtens/SLOF
b141171
b141171
I will be proposing this for inclusion in a future Power Architecture
b141171
Platform Reference (PAPR).
b141171
---
46968b6
 util/grub-install-common.c  | 18 ++++++++++++++++--
46968b6
 util/grub-mkimage.c         | 16 ++++++++++++++--
b141171
 util/grub-mkimagexx.c       | 39 ++++++++++++++++++++++++++++++++++++++-
46968b6
 util/mkimage.c              | 13 +++++++------
b141171
 include/grub/util/install.h |  8 ++++++--
b141171
 include/grub/util/mkimage.h |  4 ++--
46968b6
 6 files changed, 83 insertions(+), 15 deletions(-)
b141171
b141171
diff --git a/util/grub-install-common.c b/util/grub-install-common.c
13985b0
index 4e212e690c5..aab2a941f85 100644
b141171
--- a/util/grub-install-common.c
b141171
+++ b/util/grub-install-common.c
13985b0
@@ -461,10 +461,12 @@ static size_t npubkeys;
46968b6
 static char *sbat;
46968b6
 static int disable_shim_lock;
b141171
 static grub_compression_t compression;
b141171
+static size_t appsig_size;
b141171
 
b141171
 int
b141171
 grub_install_parse (int key, char *arg)
b141171
 {
b141171
+  const char *end;
b141171
   switch (key)
b141171
     {
b141171
     case 'C':
13985b0
@@ -562,6 +564,12 @@ grub_install_parse (int key, char *arg)
b141171
       grub_util_error (_("Unrecognized compression `%s'"), arg);
b141171
     case GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE:
b141171
       return 1;
b141171
+    case GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE:
b141171
+      grub_errno = 0;
b141171
+      appsig_size = grub_strtol(arg, &end, 10);
b141171
+      if (grub_errno)
b141171
+        return 0;
b141171
+      return 1;
b141171
     default:
b141171
       return 0;
b141171
     }
13985b0
@@ -665,7 +673,13 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
46968b6
 		  dir, prefix,
46968b6
 		  outname, dtb ? : "", sbat ? : "", mkimage_target,
46968b6
 		  compnames[compression], note ? "--note" : "",
46968b6
-		  disable_shim_lock ? "--disable-shim-lock" : "", s);
46968b6
+		  disable_shim_lock ? "--disable-shim-lock" : "",
b141171
+		  "--format '%s' --compression '%s' "
b141171
+		  "--appended-signature-size %zu %s %s\n",
46968b6
+		  dir, prefix,
46968b6
+		  outname, dtb ? : "", mkimage_target,
b141171
+		  compnames[compression], appsig_size,
b141171
+		  note ? "--note" : "", s);
b141171
   free (s);
b141171
 
b141171
   tgt = grub_install_get_image_target (mkimage_target);
13985b0
@@ -675,7 +689,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
b141171
   grub_install_generate_image (dir, prefix, fp, outname,
b141171
 			       modules.entries, memdisk_path,
b141171
 			       pubkeys, npubkeys, config_path, tgt,
46968b6
-			       note, compression, dtb, sbat,
46968b6
+			       note, appsig_size, compression, dtb, sbat,
46968b6
 			       disable_shim_lock);
b141171
   while (dc--)
b141171
     grub_install_pop_module ();
b141171
diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
46968b6
index c0d55993702..26d1ecbf74e 100644
b141171
--- a/util/grub-mkimage.c
b141171
+++ b/util/grub-mkimage.c
46968b6
@@ -84,6 +84,7 @@ static struct argp_option options[] = {
46968b6
   {"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0},
46968b6
   {"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, N_("disable shim_lock verifier"), 0},
b141171
   {"verbose",     'v', 0,      0, N_("print verbose messages."), 0},
b141171
+  {"appended-signature-size", 's', N_("SIZE"), 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 0},
b141171
   { 0, 0, 0, 0, 0, 0 }
b141171
 };
b141171
 
46968b6
@@ -128,6 +129,7 @@ struct arguments
46968b6
   char *sbat;
b141171
   int note;
46968b6
   int disable_shim_lock;
b141171
+  size_t appsig_size;
b141171
   const struct grub_install_image_target_desc *image_target;
b141171
   grub_compression_t comp;
b141171
 };
46968b6
@@ -138,6 +140,7 @@ argp_parser (int key, char *arg, struct argp_state *state)
b141171
   /* Get the input argument from argp_parse, which we
b141171
      know is a pointer to our arguments structure. */
b141171
   struct arguments *arguments = state->input;
b141171
+  const char* end;
b141171
 
b141171
   switch (key)
b141171
     {
46968b6
@@ -170,6 +173,13 @@ argp_parser (int key, char *arg, struct argp_state *state)
b141171
       arguments->note = 1;
b141171
       break;
b141171
 
46968b6
+    case 'S':
b141171
+      grub_errno = 0;
b141171
+      arguments->appsig_size = grub_strtol(arg, &end, 10);
b141171
+      if (grub_errno)
b141171
+        return 0;
b141171
+      break;
b141171
+
b141171
     case 'm':
b141171
       if (arguments->memdisk)
b141171
 	free (arguments->memdisk);
46968b6
@@ -324,8 +334,10 @@ main (int argc, char *argv[])
b141171
 			       arguments.memdisk, arguments.pubkeys,
b141171
 			       arguments.npubkeys, arguments.config,
b141171
 			       arguments.image_target, arguments.note,
46968b6
-			       arguments.comp, arguments.dtb,
46968b6
-			       arguments.sbat, arguments.disable_shim_lock);
46968b6
+
46968b6
+			       arguments.comp, arguments.appsig_size,
46968b6
+			       arguments.dtb, arguments.sbat,
46968b6
+			       arguments.disable_shim_lock);
b141171
 
b141171
   if (grub_util_file_sync (fp) < 0)
46968b6
     grub_util_error (_("cannot sync `%s': %s"), arguments.output ? : "stdout",
b141171
diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
13985b0
index d78fa3e5330..393119486d3 100644
b141171
--- a/util/grub-mkimagexx.c
b141171
+++ b/util/grub-mkimagexx.c
b141171
@@ -84,6 +84,15 @@ struct grub_ieee1275_note
b141171
   struct grub_ieee1275_note_desc descriptor;
b141171
 };
b141171
 
b141171
+#define GRUB_APPENDED_SIGNATURE_NOTE_NAME "Appended-Signature"
b141171
+#define GRUB_APPENDED_SIGNATURE_NOTE_TYPE 0x41536967 /* "ASig" */
b141171
+
b141171
+struct grub_appended_signature_note
b141171
+{
b141171
+  Elf32_Nhdr header;
b141171
+  char name[ALIGN_UP(sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME), 4)];
b141171
+};
b141171
+
b141171
 #define GRUB_XEN_NOTE_NAME "Xen"
b141171
 
b141171
 struct fixup_block_list
b141171
@@ -207,7 +216,7 @@ grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr)
b141171
 
b141171
 void
b141171
 SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target,
b141171
-				    int note, char **core_img, size_t *core_size,
b141171
+				    int note, size_t appsig_size, char **core_img, size_t *core_size,
b141171
 				    Elf_Addr target_addr,
b141171
 				    struct grub_mkimage_layout *layout)
b141171
 {
b141171
@@ -221,6 +230,12 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
b141171
   int shnum = 4;
b141171
   int string_size = sizeof (".text") + sizeof ("mods") + 1;
b141171
 
b141171
+  if (appsig_size)
b141171
+    {
b141171
+      phnum++;
b141171
+      footer_size += ALIGN_UP(sizeof (struct grub_appended_signature_note) + appsig_size, 4);
b141171
+    }
b141171
+
b141171
   if (image_target->id != IMAGE_LOONGSON_ELF)
b141171
     phnum += 2;
b141171
 
b141171
@@ -484,6 +499,28 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
b141171
       phdr->p_offset = grub_host_to_target32 (header_size + program_size);
b141171
     }
b141171
 
b141171
+  if (appsig_size) {
b141171
+    int note_size = ALIGN_UP(sizeof (struct grub_appended_signature_note) + appsig_size, 4);
b141171
+    struct grub_appended_signature_note *note_ptr = (struct grub_appended_signature_note *)
b141171
+      (elf_img + program_size + header_size + (note ? sizeof (struct grub_ieee1275_note) : 0));
b141171
+
b141171
+    note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME));
b141171
+    /* needs to sit at the end, so we round this up and sign some zero padding */
b141171
+    note_ptr->header.n_descsz = grub_host_to_target32 (ALIGN_UP(appsig_size, 4));
b141171
+    note_ptr->header.n_type = grub_host_to_target32 (GRUB_APPENDED_SIGNATURE_NOTE_TYPE);
b141171
+    strcpy (note_ptr->name, GRUB_APPENDED_SIGNATURE_NOTE_NAME);
b141171
+
b141171
+    phdr++;
b141171
+    phdr->p_type = grub_host_to_target32 (PT_NOTE);
b141171
+    phdr->p_flags = grub_host_to_target32 (PF_R);
b141171
+    phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
b141171
+    phdr->p_vaddr = 0;
b141171
+    phdr->p_paddr = 0;
b141171
+    phdr->p_filesz = grub_host_to_target32 (note_size);
b141171
+    phdr->p_memsz = 0;
b141171
+    phdr->p_offset = grub_host_to_target32 (header_size + program_size + (note ? sizeof (struct grub_ieee1275_note) : 0));
b141171
+  }
b141171
+
b141171
   {
b141171
     char *str_start = (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr)
b141171
 		       + shnum * sizeof (*shdr));
b141171
diff --git a/util/mkimage.c b/util/mkimage.c
46968b6
index a26cf76f72f..bab12276010 100644
b141171
--- a/util/mkimage.c
b141171
+++ b/util/mkimage.c
46968b6
@@ -869,8 +869,9 @@ grub_install_generate_image (const char *dir, const char *prefix,
b141171
 			     char *memdisk_path, char **pubkey_paths,
b141171
 			     size_t npubkeys, char *config_path,
b141171
 			     const struct grub_install_image_target_desc *image_target,
46968b6
-			     int note, grub_compression_t comp, const char *dtb_path,
46968b6
-			     const char *sbat_path, int disable_shim_lock)
46968b6
+			     int note, size_t appsig_size, grub_compression_t comp,
46968b6
+			     const char *dtb_path, const char *sbat_path,
46968b6
+			     int disable_shim_lock)
b141171
 {
b141171
   char *kernel_img, *core_img;
b141171
   size_t total_module_size, core_size;
46968b6
@@ -1773,11 +1774,11 @@ grub_install_generate_image (const char *dir, const char *prefix,
b141171
 	else
b141171
 	  target_addr = image_target->link_addr;
b141171
 	if (image_target->voidp_sizeof == 4)
b141171
-	  grub_mkimage_generate_elf32 (image_target, note, &core_img, &core_size,
b141171
-				       target_addr, &layout);
b141171
+	  grub_mkimage_generate_elf32 (image_target, note, appsig_size, &core_img,
b141171
+				       &core_size, target_addr, &layout);
b141171
 	else
b141171
-	  grub_mkimage_generate_elf64 (image_target, note, &core_img, &core_size,
b141171
-				       target_addr, &layout);
b141171
+	  grub_mkimage_generate_elf64 (image_target, note, appsig_size, &core_img,
b141171
+				       &core_size, target_addr, &layout);
b141171
       }
b141171
       break;
b141171
     }
b141171
diff --git a/include/grub/util/install.h b/include/grub/util/install.h
13985b0
index 7df3191f47e..cf4531e02b6 100644
b141171
--- a/include/grub/util/install.h
b141171
+++ b/include/grub/util/install.h
46968b6
@@ -67,6 +67,9 @@
46968b6
       N_("SBAT metadata"), 0 },						\
46968b6
   { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0,	\
46968b6
       N_("disable shim_lock verifier"), 0 },				\
b141171
+  { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\
b141171
+    "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \
b141171
+    1},                                                                 \
b141171
   { "verbose", 'v', 0, 0,						\
b141171
     N_("print verbose messages."), 1 }
b141171
 
46968b6
@@ -128,7 +131,8 @@ enum grub_install_options {
b141171
   GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS,
46968b6
   GRUB_INSTALL_OPTIONS_DTB,
46968b6
   GRUB_INSTALL_OPTIONS_SBAT,
46968b6
-  GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK
46968b6
+  GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK,
b141171
+  GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE
b141171
 };
b141171
 
b141171
 extern char *grub_install_source_directory;
46968b6
@@ -188,7 +192,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
b141171
 			     size_t npubkeys,
b141171
 			     char *config_path,
b141171
 			     const struct grub_install_image_target_desc *image_target,
b141171
-			     int note,
b141171
+			     int note, size_t appsig_size,
46968b6
 			     grub_compression_t comp, const char *dtb_file,
46968b6
 			     const char *sbat_path, const int disable_shim_lock);
b141171
 
b141171
diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h
46968b6
index 3819a67441c..6f1da89b9b6 100644
b141171
--- a/include/grub/util/mkimage.h
b141171
+++ b/include/grub/util/mkimage.h
46968b6
@@ -51,12 +51,12 @@ grub_mkimage_load_image64 (const char *kernel_path,
b141171
 			   const struct grub_install_image_target_desc *image_target);
b141171
 void
b141171
 grub_mkimage_generate_elf32 (const struct grub_install_image_target_desc *image_target,
b141171
-			     int note, char **core_img, size_t *core_size,
b141171
+			     int note, size_t appsig_size, char **core_img, size_t *core_size,
b141171
 			     Elf32_Addr target_addr,
b141171
 			     struct grub_mkimage_layout *layout);
b141171
 void
b141171
 grub_mkimage_generate_elf64 (const struct grub_install_image_target_desc *image_target,
b141171
-			     int note, char **core_img, size_t *core_size,
b141171
+			     int note, size_t appsig_size, char **core_img, size_t *core_size,
b141171
 			     Elf64_Addr target_addr,
b141171
 			     struct grub_mkimage_layout *layout);
b141171