]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
efi: Cache contents of EFI variable SystemdOptions
authorFilipe Brandenburger <filbranden@gmail.com>
Wed, 10 Jun 2020 22:11:32 +0000 (15:11 -0700)
committerLennart Poettering <lennart@poettering.net>
Sat, 13 Jun 2020 12:46:57 +0000 (14:46 +0200)
Cache it early in startup of the system manager, right after `/run/systemd` is
created, so that further access to it can be done without accessing the EFI
filesystem at all.

src/basic/efivars.c
src/basic/efivars.h
src/core/main.c

index 3954bd62f5cb3056227a4423adaca9311e398cd8..e7edd17d0b0bd7482270e5174580664c2dbc30d3 100644 (file)
@@ -14,6 +14,7 @@
 #include "chattr-util.h"
 #include "efivars.h"
 #include "fd-util.h"
+#include "fileio.h"
 #include "io-util.h"
 #include "macro.h"
 #include "stdio-util.h"
@@ -40,6 +41,17 @@ char* efi_variable_path(sd_id128_t vendor, const char *name) {
         return p;
 }
 
+static char* efi_variable_cache_path(sd_id128_t vendor, const char *name) {
+        char *p;
+
+        if (asprintf(&p,
+                     "/run/systemd/efivars/%s-" SD_ID128_UUID_FORMAT_STR,
+                     name, SD_ID128_FORMAT_VAL(vendor)) < 0)
+                return NULL;
+
+        return p;
+}
+
 int efi_get_variable(
                 sd_id128_t vendor,
                 const char *name,
@@ -323,32 +335,17 @@ bool is_efi_secure_boot_setup_mode(void) {
         return cache > 0;
 }
 
-int systemd_efi_options_variable(char **line) {
-        const char *e;
+int cache_efi_options_variable(void) {
+        _cleanup_free_ char *line = NULL, *cachepath = NULL;
         int r;
 
-        assert(line);
-
-        /* For testing purposes it is sometimes useful to be able to override this */
-        e = secure_getenv("SYSTEMD_EFI_OPTIONS");
-        if (e) {
-                char *m;
-
-                m = strdup(e);
-                if (!m)
-                        return -ENOMEM;
-
-                *line = m;
-                return 0;
-        }
-
         /* In SecureBoot mode this is probably not what you want. As your cmdline is cryptographically signed
          * like when using Type #2 EFI Unified Kernel Images (https://systemd.io/BOOT_LOADER_SPECIFICATION/)
          * The user's intention is then that the cmdline should not be modified. You want to make sure that
          * the system starts up as exactly specified in the signed artifact.
          *
-         * (NB: to make testing purposes we still check the $SYSTEMD_EFI_OPTIONS env var above, even when in
-         * SecureBoot mode.) */
+         * (NB: For testing purposes, we still check the $SYSTEMD_EFI_OPTIONS env var before accessing this
+         * cache, even when in SecureBoot mode.) */
         if (is_efi_secure_boot()) {
                 _cleanup_free_ char *k;
 
@@ -365,10 +362,46 @@ int systemd_efi_options_variable(char **line) {
                 return -EPERM;
         }
 
-        r = efi_get_variable_string(EFI_VENDOR_SYSTEMD, "SystemdOptions", line);
+        r = efi_get_variable_string(EFI_VENDOR_SYSTEMD, "SystemdOptions", &line);
         if (r == -ENOENT)
                 return -ENODATA;
+        if (r < 0)
+                return r;
 
+        cachepath = efi_variable_cache_path(EFI_VENDOR_SYSTEMD, "SystemdOptions");
+        if (!cachepath)
+                return -ENOMEM;
+
+        return write_string_file(cachepath, line, WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755);
+}
+
+int systemd_efi_options_variable(char **line) {
+        const char *e;
+        _cleanup_free_ char *cachepath = NULL;
+        int r;
+
+        assert(line);
+
+        /* For testing purposes it is sometimes useful to be able to override this */
+        e = secure_getenv("SYSTEMD_EFI_OPTIONS");
+        if (e) {
+                char *m;
+
+                m = strdup(e);
+                if (!m)
+                        return -ENOMEM;
+
+                *line = m;
+                return 0;
+        }
+
+        cachepath = efi_variable_cache_path(EFI_VENDOR_SYSTEMD, "SystemdOptions");
+        if (!cachepath)
+                return -ENOMEM;
+
+        r = read_one_line_file(cachepath, line);
+        if (r == -ENOENT)
+                return -ENODATA;
         return r;
 }
 #endif
index 13a33c66053de6c5446598b38b9761d32e9dd201..80854677f4c3fa92d81942554fc40a8138ba6807 100644 (file)
@@ -32,6 +32,7 @@ bool is_efi_boot(void);
 bool is_efi_secure_boot(void);
 bool is_efi_secure_boot_setup_mode(void);
 
+int cache_efi_options_variable(void);
 int systemd_efi_options_variable(char **line);
 
 #else
index a88d779448b2189e7732c87d56fd778f05c96c19..6e606d412af07b8e13aa223b0c400f5ec8abdd85 100644 (file)
@@ -33,6 +33,7 @@
 #include "dbus.h"
 #include "def.h"
 #include "efi-random.h"
+#include "efivars.h"
 #include "emergency-action.h"
 #include "env-util.h"
 #include "exit-status.h"
@@ -2630,6 +2631,10 @@ int main(int argc, char *argv[]) {
 
                 /* The efivarfs is now mounted, let's read the random seed off it */
                 (void) efi_take_random_seed();
+
+                /* Cache command-line options passed from EFI variables */
+                if (!skip_setup)
+                        (void) cache_efi_options_variable();
         }
 
         /* Save the original RLIMIT_NOFILE/RLIMIT_MEMLOCK so that we can reset it later when