]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
machine-id: Add cmdline argument to use VM behaviour on bare metal (#32086)
authorMerlin Jehli <merlin@jeh.li>
Sat, 13 Jul 2024 16:00:16 +0000 (18:00 +0200)
committerGitHub <noreply@github.com>
Sat, 13 Jul 2024 16:00:16 +0000 (18:00 +0200)
Closes #30707

man/machine-id.xml
src/core/main.c
src/machine-id-setup/machine-id-setup-main.c
src/shared/machine-id-setup.c
src/shared/machine-id-setup.h

index b142d2f0b5d49a85be6b63935dba96a19daf9761..79e020768d0edd1a7faf17e0577d3fadc88e328f 100644 (file)
     value of the kernel command line option <varname>container_uuid</varname>, the KVM DMI
     <filename>product_uuid</filename> or the devicetree <filename>vm,uuid</filename>
     (on KVM systems), the Xen hypervisor <filename>uuid</filename>, and finally a randomly
-    generated UUID.</para>
+    generated UUID. <varname>systemd.machine_id=firmware</varname> can be set to generate the machine ID
+    from the firmware.</para>
 
     <para>After the machine ID is established,
     <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
index 8dc0245fa0c993d6f0493a240732a8e95fc3ea11..706f1ca41c42745b4ea0f80e002a97ff918acc65 100644 (file)
@@ -148,6 +148,7 @@ static nsec_t arg_timer_slack_nsec;
 static Set* arg_syscall_archs;
 static FILE* arg_serialization;
 static sd_id128_t arg_machine_id;
+static bool arg_machine_id_from_firmware = false;
 static EmergencyAction arg_cad_burst_action;
 static CPUSet arg_cpu_affinity;
 static NUMAPolicy arg_numa_policy;
@@ -381,10 +382,15 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
                 if (proc_cmdline_value_missing(key, value))
                         return 0;
 
-                r = id128_from_string_nonzero(value, &arg_machine_id);
-                if (r < 0)
-                        log_warning_errno(r, "MachineID '%s' is not valid, ignoring: %m", value);
-
+                if (streq(value, "firmware"))
+                        arg_machine_id_from_firmware = true;
+                else {
+                        r = id128_from_string_nonzero(value, &arg_machine_id);
+                        if (r < 0)
+                                log_warning_errno(r, "MachineID '%s' is not valid, ignoring: %m", value);
+                        else
+                                arg_machine_id_from_firmware = false;
+                }
         } else if (proc_cmdline_key_streq(key, "systemd.default_timeout_start_sec")) {
 
                 if (proc_cmdline_value_missing(key, value))
@@ -2366,8 +2372,9 @@ static int initialize_runtime(
 
                         (void) os_release_status();
                         (void) hostname_setup(true);
-                        /* Force transient machine-id on first boot. */
-                        machine_id_setup(/* root= */ NULL, /* force_transient= */ first_boot, arg_machine_id, /* ret_machine_id */ NULL);
+
+                        machine_id_setup(/* root= */ NULL, arg_machine_id, (first_boot ? MACHINE_ID_SETUP_FORCE_TRANSIENT : 0) |
+                                        (arg_machine_id_from_firmware ? MACHINE_ID_SETUP_FORCE_FIRMWARE : 0), /* ret_machine_id = */ NULL);
                         (void) loopback_setup();
                         bump_unix_max_dgram_qlen();
                         bump_file_max_and_nr_open();
index 6f98f74a41d56923e108d4333d1759c3f8ab2c4c..cfb94841b9831f06edc818d94f724e9b5433adcd 100644 (file)
@@ -188,7 +188,7 @@ static int run(int argc, char *argv[]) {
         } else {
                 sd_id128_t id;
 
-                r = machine_id_setup(arg_root, false, SD_ID128_NULL, &id);
+                r = machine_id_setup(arg_root, SD_ID128_NULL, /* flags = */ 0, &id);
                 if (r < 0)
                         return r;
 
index 1a637947564052cb763333d2ac44f5b75f300cc1..f5e1b9ee7231129aaf8f5730dd74aaefadbefd64 100644 (file)
 #include "umask-util.h"
 #include "virt.h"
 
-static int acquire_machine_id_from_credential(sd_id128_t *ret) {
+static int acquire_machine_id_from_credential(sd_id128_t *ret_machine_id) {
         _cleanup_free_ char *buf = NULL;
         int r;
 
+        assert(ret_machine_id);
+
         r = read_credential_with_decryption("system.machine_id", (void**) &buf, /* ret_size= */ NULL);
         if (r < 0)
                 return log_warning_errno(r, "Failed to read system.machine_id credential, ignoring: %m");
-        if (r == 0) /* not found */
-                return -ENXIO;
+        if (r == 0) {
+                /* not found */
+                *ret_machine_id = SD_ID128_NULL;
+                return 0;
+        }
+
+        if (streq(buf, "firmware")) {
+                *ret_machine_id = SD_ID128_NULL;
+                return 1;
+        }
 
-        r = sd_id128_from_string(buf, ret);
+        r = sd_id128_from_string(buf, ret_machine_id);
         if (r < 0)
                 return log_warning_errno(r, "Failed to parse system.machine_id credential, ignoring: %m");
 
         log_info("Initializing machine ID from credential.");
-        return 0;
+        return 1;
 }
 
-static int acquire_machine_id(const char *root, sd_id128_t *ret) {
+static int acquire_machine_id(const char *root, bool machine_id_from_firmware, sd_id128_t *ret) {
         _cleanup_close_ int fd = -EBADF;
         int r;
 
@@ -63,7 +73,7 @@ static int acquire_machine_id(const char *root, sd_id128_t *ret) {
                 return 1; /* Indicate that the machine ID is reused. */
         }
 
-        /* Then, try reading the D-Bus machine id, unless it is a symlink */
+        /* Then, try reading the D-Bus machine ID, unless it is a symlink */
         fd = chase_and_open("/var/lib/dbus/machine-id", root, CHASE_PREFIX_ROOT | CHASE_NOFOLLOW, O_RDONLY|O_CLOEXEC|O_NOCTTY, NULL);
         if (fd >= 0 && id128_read_fd(fd, ID128_FORMAT_PLAIN | ID128_REFUSE_NULL, ret) >= 0) {
                 log_info("Initializing machine ID from D-Bus machine ID.");
@@ -72,8 +82,18 @@ static int acquire_machine_id(const char *root, sd_id128_t *ret) {
 
         if (isempty(root) && running_in_chroot() <= 0) {
                 /* Let's use a system credential for the machine ID if we can */
-                if (acquire_machine_id_from_credential(ret) >= 0)
-                        return 0;
+                sd_id128_t from_credential;
+                r = acquire_machine_id_from_credential(&from_credential);
+                if (r > 0) {
+                        if (!sd_id128_is_null(from_credential)) {
+                                /* got a valid machine id from creds */
+                                *ret = from_credential;
+                                return 0;
+                        }
+
+                        /* We got a credential, and it was set to "firmware", hence definitely try that */
+                        machine_id_from_firmware = true;
+                }
 
                 /* If that didn't work, see if we are running in a container,
                  * and a machine ID was passed in via $container_uuid the way
@@ -88,20 +108,20 @@ static int acquire_machine_id(const char *root, sd_id128_t *ret) {
                                 return 0;
                         }
 
-                } else if (IN_SET(detect_vm(), VIRTUALIZATION_KVM, VIRTUALIZATION_AMAZON, VIRTUALIZATION_QEMU, VIRTUALIZATION_XEN)) {
+                } else if (IN_SET(detect_vm(), VIRTUALIZATION_KVM, VIRTUALIZATION_AMAZON, VIRTUALIZATION_QEMU, VIRTUALIZATION_XEN) || machine_id_from_firmware) {
 
                         /* If we are not running in a container, see if we are running in a VM that provides
                          * a system UUID via the SMBIOS/DMI interfaces.  Such environments include QEMU/KVM
                          * with the -uuid on the qemu command line or the Amazon EC2 Nitro hypervisor. */
 
                         if (id128_get_product(ret) >= 0) {
-                                log_info("Initializing machine ID from VM UUID.");
+                                log_info("Initializing machine ID from SMBIOS/DMI UUID.");
                                 return 0;
                         }
                 }
         }
 
-        /* If that didn't work, generate a random machine id */
+        /* If that didn't work, generate a random machine ID */
         r = sd_id128_randomize(ret);
         if (r < 0)
                 return log_error_errno(r, "Failed to generate randomized machine ID: %m");
@@ -110,7 +130,7 @@ static int acquire_machine_id(const char *root, sd_id128_t *ret) {
         return 0;
 }
 
-int machine_id_setup(const char *root, bool force_transient, sd_id128_t machine_id, sd_id128_t *ret) {
+int machine_id_setup(const char *root, sd_id128_t machine_id, MachineIdSetupFlags flags, sd_id128_t *ret) {
         const char *etc_machine_id, *run_machine_id;
         _cleanup_close_ int fd = -EBADF;
         bool writable, write_run_machine_id = true;
@@ -148,14 +168,14 @@ int machine_id_setup(const char *root, bool force_transient, sd_id128_t machine_
         }
 
         /* A we got a valid machine ID argument, that's what counts */
-        if (sd_id128_is_null(machine_id)) {
+        if (sd_id128_is_null(machine_id) || FLAGS_SET(flags, MACHINE_ID_SETUP_FORCE_FIRMWARE)) {
 
                 /* Try to read any existing machine ID */
                 if (id128_read_fd(fd, ID128_FORMAT_PLAIN, &machine_id) >= 0)
                         goto finish;
 
                 /* Hmm, so, the id currently stored is not useful, then let's acquire one. */
-                r = acquire_machine_id(root, &machine_id);
+                r = acquire_machine_id(root, FLAGS_SET(flags, MACHINE_ID_SETUP_FORCE_FIRMWARE), &machine_id);
                 if (r < 0)
                         return r;
                 write_run_machine_id = !r;
@@ -172,7 +192,7 @@ int machine_id_setup(const char *root, bool force_transient, sd_id128_t machine_
                  * disk and overmount it with a transient file.
                  *
                  * Otherwise write the machine-id directly to disk. */
-                if (force_transient) {
+                if (FLAGS_SET(flags, MACHINE_ID_SETUP_FORCE_TRANSIENT)) {
                         r = loop_write(fd, "uninitialized\n", SIZE_MAX);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to write uninitialized %s: %m", etc_machine_id);
@@ -212,7 +232,7 @@ int machine_id_setup(const char *root, bool force_transient, sd_id128_t machine_
                 return r;
         }
 
-        log_full(force_transient ? LOG_DEBUG : LOG_INFO, "Installed transient %s file.", etc_machine_id);
+        log_full(FLAGS_SET(flags, MACHINE_ID_SETUP_FORCE_TRANSIENT) ? LOG_DEBUG : LOG_INFO, "Installed transient %s file.", etc_machine_id);
 
         /* Mark the mount read-only */
         r = mount_follow_verbose(LOG_WARNING, NULL, etc_machine_id, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, NULL);
index cce58192e526a1654929c25b43b3844ecaf85353..e733471afc9ae05fd8678147879c5d2188aa1173 100644 (file)
@@ -3,5 +3,10 @@
 
 #include <stdbool.h>
 
+typedef enum MachineIdSetupFlags {
+        MACHINE_ID_SETUP_FORCE_TRANSIENT = 1 << 0,
+        MACHINE_ID_SETUP_FORCE_FIRMWARE  = 1 << 1,
+} MachineIdSetupFlags;
+
 int machine_id_commit(const char *root);
-int machine_id_setup(const char *root, bool force_transient, sd_id128_t requested, sd_id128_t *ret);
+int machine_id_setup(const char *root, sd_id128_t machine_id, MachineIdSetupFlags flags, sd_id128_t *ret);