]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: take random seed from boot loader and credit it to kernel entropy pool
authorLennart Poettering <lennart@poettering.net>
Fri, 19 Jul 2019 17:39:15 +0000 (19:39 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 25 Jul 2019 16:16:46 +0000 (18:16 +0200)
src/core/efi-random.c [new file with mode: 0644]
src/core/efi-random.h [new file with mode: 0644]
src/core/main.c
src/core/meson.build

diff --git a/src/core/efi-random.c b/src/core/efi-random.c
new file mode 100644 (file)
index 0000000..c4d25d6
--- /dev/null
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <fcntl.h>
+#include <linux/random.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include "alloc-util.h"
+#include "chattr-util.h"
+#include "efi-random.h"
+#include "efivars.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "strv.h"
+
+/* If a random seed was passed by the boot loader in the LoaderRandomSeed EFI variable, let's credit it to
+ * the kernel's random pool, but only once per boot. If this is run very early during initialization we can
+ * instantly boot up with a filled random pool.
+ *
+ * This makes no judgement on the entropy passed, it's the job of the boot loader to only pass us a seed that
+ * is suitably validated. */
+
+static void lock_down_efi_variables(void) {
+        const char *p;
+        int r;
+
+        /* Paranoia: let's restrict access modes of these a bit, so that unprivileged users can't use them to
+         * identify the system or gain too much insight into what we might have credited to the entropy
+         * pool. */
+        FOREACH_STRING(p,
+                       "/sys/firmware/efi/efivars/LoaderRandomSeed-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f",
+                       "/sys/firmware/efi/efivars/LoaderSystemToken-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f") {
+
+                r = chattr_path(p, 0, FS_IMMUTABLE_FL, NULL);
+                if (r == -ENOENT)
+                        continue;
+                if (r < 0)
+                        log_warning_errno(r, "Failed to drop FS_IMMUTABLE_FL from %s, ignoring: %m", p);
+
+                if (chmod(p, 0600) < 0)
+                        log_warning_errno(errno, "Failed to reduce access mode of %s, ignoring: %m", p);
+        }
+}
+
+int efi_take_random_seed(void) {
+        _cleanup_free_ struct rand_pool_info *info = NULL;
+        _cleanup_free_ void *value = NULL;
+        _cleanup_close_ int random_fd = -1;
+        size_t size;
+        int r;
+
+        /* Paranoia comes first. */
+        lock_down_efi_variables();
+
+        if (access("/run/systemd/efi-random-seed-taken", F_OK) < 0) {
+                if (errno != ENOENT) {
+                        log_warning_errno(errno, "Failed to determine whether we already used the random seed token, not using it.");
+                        return 0;
+                }
+
+                /* ENOENT means we haven't used it yet. */
+        } else {
+                log_debug("EFI random seed already used, not using again.");
+                return 0;
+        }
+
+        r = efi_get_variable(EFI_VENDOR_LOADER, "LoaderRandomSeed", NULL, &value, &size);
+        if (r == -EOPNOTSUPP) {
+                log_debug_errno(r, "System lacks EFI support, not initializing random seed from EFI variable.");
+                return 0;
+        }
+        if (r == -ENOENT) {
+                log_debug_errno(r, "Boot loader did not pass LoaderRandomSeed EFI variable, not crediting any entropy.");
+                return 0;
+        }
+        if (r < 0)
+                return log_warning_errno(r, "Failed to read LoaderRandomSeed EFI variable, ignoring: %m");
+
+        if (size == 0)
+                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Random seed passed from boot loader has zero size? Ignoring.");
+
+        /* The kernel API only accepts "int" as entropy count (which is in bits), let's avoid any chance for
+         * confusion here. */
+        if (size > INT_MAX / 8)
+                size = INT_MAX / 8;
+
+        random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY);
+        if (random_fd < 0)
+                return log_warning_errno(errno, "Failed to open /dev/urandom for writing, ignoring: %m");
+
+        /* Before we use the seed, let's mark it as used, so that we never credit it twice. Also, it's a nice
+         * way to let users known that we successfully acquired entropy from the boot laoder. */
+        r = touch("/run/systemd/efi-random-seed-taken");
+        if (r < 0)
+                return log_warning_errno(r, "Unable to mark EFI random seed as used, not using it: %m");
+
+        info = malloc(offsetof(struct rand_pool_info, buf) + size);
+        if (!info)
+                return log_oom();
+
+        info->entropy_count = size * 8;
+        info->buf_size = size;
+        memcpy(info->buf, value, size);
+
+        if (ioctl(random_fd, RNDADDENTROPY, info) < 0)
+                return log_warning_errno(errno, "Failed to credit entropy, ignoring: %m");
+
+        log_info("Successfully credited entropy passed from boot loader.");
+        return 1;
+}
diff --git a/src/core/efi-random.h b/src/core/efi-random.h
new file mode 100644 (file)
index 0000000..c1de867
--- /dev/null
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+int efi_take_random_seed(void);
index ef17e71e119598c1a4eb07f7eefc21b92f5db834..0674e00ab01f849af4130155e26c33ed5351d830 100644 (file)
 #include "clock-util.h"
 #include "conf-parser.h"
 #include "cpu-set-util.h"
-#include "dbus.h"
 #include "dbus-manager.h"
+#include "dbus.h"
 #include "def.h"
+#include "efi-random.h"
 #include "emergency-action.h"
 #include "env-util.h"
 #include "exit-status.h"
@@ -2511,6 +2512,9 @@ int main(int argc, char *argv[]) {
                         error_message = "Failed to mount API filesystems";
                         goto finish;
                 }
+
+                /* The efivarfs is now mounted, let's read the random seed off it */
+                (void) efi_take_random_seed();
         }
 
         /* Save the original RLIMIT_NOFILE/RLIMIT_MEMLOCK so that we can reset it later when
index 34762dbc21a88bef1626d617442162a25d13bac1..267d65a3b229d66134d9a0948a60169b304c0a01 100644 (file)
@@ -66,6 +66,8 @@ libcore_sources = '''
         device.h
         dynamic-user.c
         dynamic-user.h
+        efi-random.c
+        efi-random.h
         emergency-action.c
         emergency-action.h
         execute.c