From 6c9890730063ff759040cb570d0e620f855f83ef Mon Sep 17 00:00:00 2001
From: Jan Setje-Eilers <jan.setjeeilers@oracle.com>
Date: Thu, 21 Apr 2022 17:28:07 -0700
Subject: [PATCH] SBAT revocation update support

Control how shim will apply SBAT revocations:

 mokutil --set-sbat-policy latest

	applies the latest SBAT revocations
	(default behavior)

 mokutil --set-sbat-policy previous

	applies previous SBAT revocations to
	allow falling back to an older release

 In both of the above cases shim will only apply SBAT revocations that
are newer than the ones currently installed.

 mokutil --set-sbat-policy delete

	resets SBAT revocations only if Secure
	Boot is disabled. This setting does not
	persist.

Signed-off-by: Jan Setje-Eilers <Jan.SetjeEilers@oracle.com>
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
 man/mokutil.1 | 14 ++++++++++++--
 src/mokutil.c | 42 +++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 53 insertions(+), 3 deletions(-)

Index: mokutil-0.2.0/man/mokutil.1
===================================================================
--- mokutil-0.2.0.orig/man/mokutil.1
+++ mokutil-0.2.0/man/mokutil.1
@@ -69,7 +69,9 @@ mokutil \- utility to manipulate machine
 .br
 \fBmokutil\fR [--dbx]
 .br
-\fBmokutil\fR [--sbat]
+\fBmokutil\fR [--list-sbat-revocations]
+.br
+\fBmokutil\fR [--set-sbat-policy (\fIlatest\fR | \fIprevious\fR | \fIdelete\fR)]
 .br
 
 .SH DESCRIPTION
@@ -169,9 +171,17 @@ List the keys in the secure boot signatu
 \fB--dbx\fR
 List the keys in the secure boot blacklist signature store (dbx)
 .TP
-\fB--sbat\fR
+\fB--list-sbat-revocations\fR
 List the entries in the Secure Boot Advanced Targeting store (SBAT)
 .TP
+\fB--set-sbat-policy (\fIlatest\fR | \fIprevious\fR | \fIdelete\fR)\fR
+Set the SbatPolicy UEFI Variable to have shim apply either the latest
+or the previous SBAT revocations.  If UEFI Secure Boot is disabled, then
+delete will reset the SBAT revocations to an empty revocation list.
+While latest and previous are persistent configuration, delete will be
+cleared by shim on the next boot whether or not it succeeds. The default
+behavior is for shim to apply the previous revocations.
++.TP
 \fB--ca-check\fR
 Check if the CA of the given key is already enrolled or blocked in the key
 databases.
Index: mokutil-0.2.0/src/mokutil.c
===================================================================
--- mokutil-0.2.0.orig/src/mokutil.c
+++ mokutil-0.2.0/src/mokutil.c
@@ -86,6 +86,7 @@ EFI_GUID (0x605dab50, 0xe046, 0x4300, 0x
 #define LIST_SBAT          (1 << 24)
 #define FB_VERBOSITY       (1 << 25)
 #define FB_NOREBOOT        (1 << 26)
+#define SET_SBAT           (1 << 27)
 
 #define DEFAULT_CRYPT_METHOD SHA512_BASED
 #define DEFAULT_SALT_SIZE    SHA512_SALT_MAX
@@ -154,11 +155,12 @@ print_help ()
 	printf ("  --set-verbosity <true/false>\t\tSet the verbosity bit for shim\n");
 	printf ("  --set-fallback-verbosity <true/false>\t\tSet the verbosity bit for fallback\n");
 	printf ("  --set-fallback-noreboot <true/false>\t\tPrevent fallback from automatically rebooting\n");
+	printf ("  --set-sbat-policy <latest/previous/delete>\t\tApply Latest, Previous, or Blank SBAT revocations\n");
 	printf ("  --pk\t\t\t\t\tList the keys in PK\n");
 	printf ("  --kek\t\t\t\t\tList the keys in KEK\n");
 	printf ("  --db\t\t\t\t\tList the keys in db\n");
 	printf ("  --dbx\t\t\t\t\tList the keys in dbx\n");
-	printf ("  --sbat\t\t\t\tList the entries in SBAT\n");
+	printf ("  --list-sbat-revocations\t\t\t\tList the entries in SBAT\n");
 	printf ("\n");
 	printf ("Supplimentary Options:\n");
 	printf ("  --hash-file <hash file>\t\tUse the specific password hash\n");
@@ -2265,6 +2267,32 @@ list_db (DBName db_name)
 	return -1;
 }
 
+static int
+manage_sbat (const uint8_t sbat_policy)
+{
+	efi_variable_t var;
+
+	if (sbat_policy) {
+		var.Data = (uint8_t *)&sbat_policy;
+		var.DataSize = sizeof (sbat_policy);
+		var.VariableName = "SbatPolicy";
+
+		var.VendorGuid = SHIM_LOCK_GUID;
+		var.Attributes = EFI_VARIABLE_NON_VOLATILE
+				| EFI_VARIABLE_BOOTSERVICE_ACCESS
+				| EFI_VARIABLE_RUNTIME_ACCESS;
+
+		if (edit_variable (&var) != EFI_SUCCESS) {
+			fprintf (stderr, "Failed to set SbatPolicy\n");
+			return -1;
+		}
+	} else {
+		return test_and_delete_var ("SbatPolicy");
+	}
+
+	return 0;
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -2280,6 +2308,7 @@ main (int argc, char *argv[])
 	uint8_t verbosity = 0;
 	uint8_t fb_verbosity = 0;
 	uint8_t fb_noreboot = 0;
+	uint8_t sbat_policy = 0;
 	DBName db_name = MOK_LIST_RT;
 	int ret = -1;
 
@@ -2316,10 +2345,12 @@ main (int argc, char *argv[])
 			{"set-verbosity",      required_argument, 0, 0  },
 			{"set-fallback-verbosity", required_argument, 0, 0  },
 			{"set-fallback-noreboot", required_argument, 0, 0  },
+			{"set-sbat-policy",    required_argument, 0, 0  },
 			{"pk",                 no_argument,       0, 0  },
 			{"kek",                no_argument,       0, 0  },
 			{"db",                 no_argument,       0, 0  },
 			{"dbx",                no_argument,       0, 0  },
+			{"list-sbat-revocations", no_argument,       0, 0  },
 			{"sbat",               no_argument,       0, 0  },
 			{"ca-check",           no_argument,       0, 0  },
 			{0, 0, 0, 0}
@@ -2397,6 +2428,16 @@ main (int argc, char *argv[])
 					fb_noreboot = 0;
 				else
 					command |= HELP;
+			} else if (strcmp (option, "set-sbat-policy") == 0) {
+				command |= SET_SBAT;
+				if (strcmp (optarg, "latest") == 0)
+					sbat_policy = 1;
+				else if (strcmp (optarg, "previous") == 0)
+					sbat_policy = 2;
+				else if (strcmp (optarg, "delete") == 0)
+					sbat_policy = 3;
+				else
+					command |= HELP;
 			} else if (strcmp (option, "pk") == 0) {
 				if (db_name != MOK_LIST_RT) {
 					command |= HELP;
@@ -2425,6 +2466,8 @@ main (int argc, char *argv[])
 					command |= LIST_ENROLLED;
 					db_name = DBX;
 				}
+			}  else if (strcmp (option, "list-sbat-revocations") == 0) {
+				command |= LIST_SBAT;
 			}  else if (strcmp (option, "sbat") == 0) {
 				command |= LIST_SBAT;
 			} else if (strcmp (option, "ca-check") == 0) {
@@ -2697,6 +2740,9 @@ main (int argc, char *argv[])
 		case LIST_SBAT:
 			ret = print_var_content ("SbatLevelRT", SHIM_LOCK_GUID);
 			break;
+		case SET_SBAT:
+			ret = manage_sbat(sbat_policy);
+			break;
 		default:
 			print_help ();
 			break;
