vmspawn: add swtpm feature
This commit is contained in:
@@ -132,6 +132,21 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--tpm=</option><replaceable>BOOL</replaceable></term>
|
||||
|
||||
<listitem>
|
||||
<para>Configure whether to use qemu with a virtual TPM or not.</para>
|
||||
<para>If the option is not specified vmspawn will detect the presence of <citerefentry project='man-pages'>
|
||||
<refentrytitle>swtpm</refentrytitle><manvolnum>8</manvolnum></citerefentry> and use it if available.
|
||||
If yes is specified <citerefentry project='man-pages'><refentrytitle>swtpm</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
is always used, and vice versa if no is set <citerefentry project='man-pages'><refentrytitle>swtpm</refentrytitle>
|
||||
<manvolnum>8</manvolnum></citerefentry> is never used.</para>
|
||||
<para>Note: the virtual TPM used may change in future.</para>
|
||||
<xi:include href="version-info.xml" xpointer="v256"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--qemu-gui</option></term>
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
libvmspawn_core_sources = files(
|
||||
'vmspawn-settings.c',
|
||||
'vmspawn-util.c',
|
||||
'vmspawn-scope.c',
|
||||
)
|
||||
libvmspawn_core = static_library(
|
||||
'vmspawn-core',
|
||||
|
||||
@@ -0,0 +1,302 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "sd-bus.h"
|
||||
|
||||
#include "bus-error.h"
|
||||
#include "bus-locator.h"
|
||||
#include "bus-unit-util.h"
|
||||
#include "bus-util.h"
|
||||
#include "bus-wait-for-jobs.h"
|
||||
#include "escape.h"
|
||||
#include "macro.h"
|
||||
#include "process-util.h"
|
||||
#include "random-util.h"
|
||||
#include "socket-util.h"
|
||||
#include "strv.h"
|
||||
#include "unit-def.h"
|
||||
#include "unit-name.h"
|
||||
#include "vmspawn-scope.h"
|
||||
|
||||
int start_transient_scope(sd_bus *bus, const char *machine_name, bool allow_pidfd, char **ret_scope) {
|
||||
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
|
||||
_cleanup_free_ char *scope = NULL, *description = NULL;
|
||||
const char *object;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(machine_name);
|
||||
|
||||
/* Creates a transient scope unit which tracks the lifetime of the current process */
|
||||
|
||||
r = bus_wait_for_jobs_new(bus, &w);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not watch job: %m");
|
||||
|
||||
if (asprintf(&scope, "machine-%"PRIu64"-%s.scope", random_u64(), machine_name) < 0)
|
||||
return log_oom();
|
||||
|
||||
description = strjoin("Virtual Machine ", machine_name);
|
||||
if (!description)
|
||||
return log_oom();
|
||||
|
||||
r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(m, "ss", /* name */ scope, /* mode */ "fail");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
/* Properties */
|
||||
r = sd_bus_message_open_container(m, 'a', "(sv)");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(m, "(sa)(sa)(sa)",
|
||||
"Description", "s", description,
|
||||
"AddRef", "b", 1,
|
||||
"CollectMode", "s", "inactive-or-failed");
|
||||
|
||||
if (allow_pidfd) {
|
||||
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
|
||||
r = pidref_set_pid(&pidref, getpid_cached());
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate PID reference: %m");
|
||||
|
||||
r = bus_append_scope_pidref(m, &pidref);
|
||||
} else
|
||||
r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, getpid_cached());
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
/* No auxiliary units */
|
||||
r = sd_bus_message_append(
|
||||
m,
|
||||
"a(sa(sv))",
|
||||
0);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_call(bus, m, 0, &error, &reply);
|
||||
if (r < 0) {
|
||||
/* If this failed with a property we couldn't write, this is quite likely because the server
|
||||
* doesn't support PIDFDs yet, let's try without. */
|
||||
if (allow_pidfd &&
|
||||
sd_bus_error_has_names(&error, SD_BUS_ERROR_UNKNOWN_PROPERTY, SD_BUS_ERROR_PROPERTY_READ_ONLY))
|
||||
return start_transient_scope(bus, machine_name, false, ret_scope);
|
||||
|
||||
return log_error_errno(r, "Failed to start transient scope unit: %s", bus_error_message(&error, r));
|
||||
}
|
||||
|
||||
r = sd_bus_message_read(reply, "o", &object);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
r = bus_wait_for_jobs_one(w, object, /* quiet */ false, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret_scope)
|
||||
*ret_scope = TAKE_PTR(scope);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int message_add_commands(sd_bus_message *m, const char *exec_type, char ***commands, size_t n_commands) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(exec_type);
|
||||
assert(commands || n_commands == 0);
|
||||
|
||||
/* A small helper for adding an ExecStart / ExecStopPost / etc.. property to an sd_bus_message */
|
||||
|
||||
r = sd_bus_message_open_container(m, 'r', "sv");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(m, "s", exec_type);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_open_container(m, 'v', "a(sasb)");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_open_container(m, 'a', "(sasb)");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
FOREACH_ARRAY(cmd, commands, n_commands) {
|
||||
char **cmdline = *cmd;
|
||||
|
||||
r = sd_bus_message_open_container(m, 'r', "sasb");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(m, "s", cmdline[0]);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append_strv(m, cmdline);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(m, "b", 0);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void socket_service_pair_done(SocketServicePair *p) {
|
||||
p->exec_start = strv_free(p->exec_start);
|
||||
p->exec_stop_post = strv_free(p->exec_stop_post);
|
||||
p->unit_name_prefix = mfree(p->unit_name_prefix);
|
||||
p->runtime_directory = mfree(p->runtime_directory);
|
||||
p->listen_address = mfree(p->listen_address);
|
||||
p->socket_type = 0;
|
||||
}
|
||||
|
||||
int start_socket_service_pair(sd_bus *bus, const char *scope, SocketServicePair *p) {
|
||||
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
|
||||
_cleanup_free_ char *service_desc = NULL, *service_name = NULL, *socket_name = NULL;
|
||||
const char *object, *socket_type_str;
|
||||
int r;
|
||||
|
||||
/* Starts a socket/service unit pair bound to the given scope. */
|
||||
|
||||
assert(bus);
|
||||
assert(scope);
|
||||
assert(p);
|
||||
assert(p->unit_name_prefix);
|
||||
assert(p->exec_start);
|
||||
assert(p->listen_address);
|
||||
|
||||
r = bus_wait_for_jobs_new(bus, &w);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not watch job: %m");
|
||||
|
||||
socket_name = strjoin(p->unit_name_prefix, ".socket");
|
||||
if (!socket_name)
|
||||
return log_oom();
|
||||
|
||||
service_name = strjoin(p->unit_name_prefix, ".service");
|
||||
if (!service_name)
|
||||
return log_oom();
|
||||
|
||||
service_desc = quote_command_line(p->exec_start, SHELL_ESCAPE_EMPTY);
|
||||
if (!service_desc)
|
||||
return log_oom();
|
||||
|
||||
socket_type_str = socket_address_type_to_string(p->socket_type);
|
||||
if (!socket_type_str)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Invalid socket type: %d", p->socket_type);
|
||||
|
||||
r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(m, "ssa(sv)",
|
||||
/* ss - name, mode */
|
||||
socket_name, "fail",
|
||||
/* a(sv) - Properties */
|
||||
5,
|
||||
"Description", "s", p->listen_address,
|
||||
"AddRef", "b", 1,
|
||||
"BindsTo", "as", 1, scope,
|
||||
"Listen", "a(ss)", 1, socket_type_str, p->listen_address,
|
||||
"CollectMode", "s", "inactive-or-failed");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
/* aux */
|
||||
r = sd_bus_message_open_container(m, 'a', "(sa(sv))");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_open_container(m, 'r', "sa(sv)");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(m, "s", service_name);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_open_container(m, 'a', "(sv)");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(m, "(sv)(sv)(sv)(sv)",
|
||||
"Description", "s", service_desc,
|
||||
"AddRef", "b", 1,
|
||||
"BindsTo", "as", 1, scope,
|
||||
"CollectMode", "s", "inactive-or-failed");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
if (p->runtime_directory) {
|
||||
r = sd_bus_message_append(m, "(sv)", "RuntimeDirectory", "as", 1, p->runtime_directory);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
}
|
||||
|
||||
r = message_add_commands(m, "ExecStart", &p->exec_start, 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (p->exec_stop_post) {
|
||||
r = message_add_commands(m, "ExecStopPost", &p->exec_stop_post, 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_call(bus, m, 0, &error, &reply);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to start %s as transient unit: %s", p->exec_start[0], bus_error_message(&error, r));
|
||||
|
||||
r = sd_bus_message_read(reply, "o", &object);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
return bus_wait_for_jobs_one(w, object, /* quiet */ false, NULL);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "sd-bus.h"
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
typedef struct SocketServicePair {
|
||||
char **exec_start;
|
||||
char **exec_stop_post;
|
||||
char *unit_name_prefix;
|
||||
char *runtime_directory;
|
||||
char *listen_address;
|
||||
int socket_type;
|
||||
} SocketServicePair;
|
||||
|
||||
void socket_service_pair_done(SocketServicePair *p);
|
||||
|
||||
int start_transient_scope(sd_bus *bus, const char *machine_name, bool allow_pidfd, char **ret_scope);
|
||||
int start_socket_service_pair(sd_bus *bus, const char *scope, SocketServicePair *p);
|
||||
@@ -10,6 +10,12 @@
|
||||
#define ARCHITECTURE_SUPPORTS_SMBIOS 0
|
||||
#endif
|
||||
|
||||
#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
|
||||
#define ARCHITECTURE_SUPPORTS_TPM 1
|
||||
#else
|
||||
#define ARCHITECTURE_SUPPORTS_TPM 0
|
||||
#endif
|
||||
|
||||
#if defined(__arm__) || defined(__aarch64__)
|
||||
#define DEFAULT_SERIAL_TTY "ttyAMA0"
|
||||
#elif defined(__s390__) || defined(__s390x__)
|
||||
|
||||
+158
-4
@@ -3,7 +3,6 @@
|
||||
#include <getopt.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
@@ -22,17 +21,22 @@
|
||||
#include "log.h"
|
||||
#include "machine-credential.h"
|
||||
#include "main-func.h"
|
||||
#include "mkdir.h"
|
||||
#include "pager.h"
|
||||
#include "parse-argument.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-lookup.h"
|
||||
#include "path-util.h"
|
||||
#include "pretty-print.h"
|
||||
#include "process-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "sd-event.h"
|
||||
#include "signal-util.h"
|
||||
#include "socket-util.h"
|
||||
#include "strv.h"
|
||||
#include "tmpfile-util.h"
|
||||
#include "unit-name.h"
|
||||
#include "vmspawn-scope.h"
|
||||
#include "vmspawn-settings.h"
|
||||
#include "vmspawn-util.h"
|
||||
|
||||
@@ -45,16 +49,21 @@ static uint64_t arg_qemu_mem = UINT64_C(2) * U64_GB;
|
||||
static int arg_qemu_kvm = -1;
|
||||
static int arg_qemu_vsock = -1;
|
||||
static unsigned arg_vsock_cid = VMADDR_CID_ANY;
|
||||
static int arg_tpm = -1;
|
||||
static bool arg_qemu_gui = false;
|
||||
static int arg_secure_boot = -1;
|
||||
static MachineCredentialContext arg_credentials = {};
|
||||
static SettingsMask arg_settings_mask = 0;
|
||||
static char **arg_parameters = NULL;
|
||||
static char *arg_firmware = NULL;
|
||||
static char *arg_runtime_directory = NULL;
|
||||
static bool arg_runtime_directory_created = false;
|
||||
static bool arg_privileged = false;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_machine, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_qemu_smp, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_runtime_directory, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_parameters, strv_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_credentials, machine_credential_context_done);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_firmware, freep);
|
||||
@@ -84,6 +93,7 @@ static int help(void) {
|
||||
" --qemu-kvm=BOOL Configure whether to use KVM or not\n"
|
||||
" --qemu-vsock=BOOL Configure whether to use qemu with a vsock or not\n"
|
||||
" --vsock-cid= Specify the CID to use for the qemu guest's vsock\n"
|
||||
" --tpm=BOOL Configure whether to use a virtual TPM or not\n"
|
||||
" --qemu-gui Start QEMU in graphical mode\n"
|
||||
" --secure-boot=BOOL Configure whether to search for firmware which\n"
|
||||
" supports Secure Boot\n"
|
||||
@@ -117,6 +127,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_QEMU_KVM,
|
||||
ARG_QEMU_VSOCK,
|
||||
ARG_VSOCK_CID,
|
||||
ARG_TPM,
|
||||
ARG_QEMU_GUI,
|
||||
ARG_SECURE_BOOT,
|
||||
ARG_SET_CREDENTIAL,
|
||||
@@ -136,6 +147,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "qemu-kvm", required_argument, NULL, ARG_QEMU_KVM },
|
||||
{ "qemu-vsock", required_argument, NULL, ARG_QEMU_VSOCK },
|
||||
{ "vsock-cid", required_argument, NULL, ARG_VSOCK_CID },
|
||||
{ "tpm", required_argument, NULL, ARG_TPM },
|
||||
{ "qemu-gui", no_argument, NULL, ARG_QEMU_GUI },
|
||||
{ "secure-boot", required_argument, NULL, ARG_SECURE_BOOT },
|
||||
{ "set-credential", required_argument, NULL, ARG_SET_CREDENTIAL },
|
||||
@@ -228,6 +240,12 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
}
|
||||
break;
|
||||
|
||||
case ARG_TPM:
|
||||
r = parse_tristate(optarg, &arg_tpm);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse --tpm=%s: %m", optarg);
|
||||
break;
|
||||
|
||||
case ARG_QEMU_GUI:
|
||||
arg_qemu_gui = true;
|
||||
break;
|
||||
@@ -482,12 +500,80 @@ static int cmdline_add_vsock(char ***cmdline, int vsock_fd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int start_tpm(sd_bus *bus, const char *scope, const char *tpm, const char **ret_state_tempdir) {
|
||||
_cleanup_(rm_rf_physical_and_freep) char *state_dir = NULL;
|
||||
_cleanup_free_ char *scope_prefix = NULL;
|
||||
_cleanup_(socket_service_pair_done) SocketServicePair ssp = {
|
||||
.socket_type = SOCK_STREAM,
|
||||
};
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(scope);
|
||||
assert(tpm);
|
||||
assert(ret_state_tempdir);
|
||||
|
||||
r = unit_name_to_prefix(scope, &scope_prefix);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to strip .scope suffix from scope: %m");
|
||||
|
||||
ssp.unit_name_prefix = strjoin(scope_prefix, "-tpm");
|
||||
if (!ssp.unit_name_prefix)
|
||||
return log_oom();
|
||||
|
||||
state_dir = path_join(arg_runtime_directory, ssp.unit_name_prefix);
|
||||
if (!state_dir)
|
||||
return log_oom();
|
||||
|
||||
if (arg_runtime_directory_created) {
|
||||
ssp.runtime_directory = path_join("systemd/vmspawn", ssp.unit_name_prefix);
|
||||
if (!ssp.runtime_directory)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
ssp.listen_address = path_join(state_dir, "sock");
|
||||
if (!ssp.listen_address)
|
||||
return log_oom();
|
||||
|
||||
ssp.exec_start = strv_new(tpm, "socket", "--tpm2", "--tpmstate");
|
||||
if (!ssp.exec_start)
|
||||
return log_oom();
|
||||
|
||||
r = strv_extendf(&ssp.exec_start, "dir=%s", state_dir);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = strv_extend_many(&ssp.exec_start, "--ctrl", "type=unixio,fd=3");
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = start_socket_service_pair(bus, scope, &ssp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret_state_tempdir = TAKE_PTR(state_dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run_virtual_machine(void) {
|
||||
_cleanup_(ovmf_config_freep) OvmfConfig *ovmf_config = NULL;
|
||||
_cleanup_strv_free_ char **cmdline = NULL;
|
||||
_cleanup_free_ char *machine = NULL, *qemu_binary = NULL, *mem = NULL;
|
||||
int r;
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
_cleanup_close_ int vsock_fd = -EBADF;
|
||||
_cleanup_free_ char *machine = NULL, *qemu_binary = NULL, *mem = NULL, *trans_scope = NULL;
|
||||
_cleanup_strv_free_ char **cmdline = NULL;
|
||||
int r;
|
||||
|
||||
if (arg_privileged)
|
||||
r = sd_bus_default_system(&bus);
|
||||
else
|
||||
r = sd_bus_default_user(&bus);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to connect to systemd bus: %m");
|
||||
|
||||
r = start_transient_scope(bus, arg_machine, /* allow_pidfd= */ true, &trans_scope);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
bool use_kvm = arg_qemu_kvm > 0;
|
||||
if (arg_qemu_kvm < 0) {
|
||||
@@ -538,6 +624,20 @@ static int run_virtual_machine(void) {
|
||||
if (!cmdline)
|
||||
return log_oom();
|
||||
|
||||
/* if we are going to be starting any units with state then create our runtime dir */
|
||||
if (arg_tpm != 0) {
|
||||
r = runtime_directory(&arg_runtime_directory, arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER, "systemd/vmspawn");
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to lookup runtime directory: %m");
|
||||
if (r) {
|
||||
/* r > 0 means we need to create our own runtime dir */
|
||||
r = mkdir_p(arg_runtime_directory, 0755);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create runtime directory: %m");
|
||||
arg_runtime_directory_created = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool use_vsock = arg_qemu_vsock > 0 && ARCHITECTURE_SUPPORTS_SMBIOS;
|
||||
if (arg_qemu_vsock < 0) {
|
||||
r = qemu_check_vsock_support();
|
||||
@@ -685,6 +785,58 @@ static int run_virtual_machine(void) {
|
||||
} else
|
||||
log_warning("Cannot append extra args to kernel cmdline, native architecture doesn't support SMBIOS");
|
||||
|
||||
/* disable TPM autodetection if the user's hardware doesn't support it */
|
||||
if (!ARCHITECTURE_SUPPORTS_TPM) {
|
||||
if (arg_tpm < 0) {
|
||||
arg_tpm = 0;
|
||||
log_debug("TPM not support on %s, disabling tpm autodetection and continuing", architecture_to_string(native_architecture()));
|
||||
} else if (arg_tpm > 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "TPM not supported on %s, refusing", architecture_to_string(native_architecture()));
|
||||
}
|
||||
|
||||
_cleanup_free_ char *swtpm = NULL;
|
||||
if (arg_tpm != 0) {
|
||||
r = find_executable("swtpm", &swtpm);
|
||||
if (r < 0) {
|
||||
/* log if the user asked for swtpm and we cannot find it */
|
||||
if (arg_tpm > 0)
|
||||
return log_error_errno(r, "Failed to find swtpm binary: %m");
|
||||
/* also log if we got an error other than ENOENT from find_executable */
|
||||
if (r != -ENOENT && arg_tpm < 0)
|
||||
return log_error_errno(r, "Error detecting swtpm: %m");
|
||||
}
|
||||
}
|
||||
|
||||
_cleanup_free_ const char *tpm_state_tempdir = NULL;
|
||||
if (swtpm) {
|
||||
r = start_tpm(bus, trans_scope, swtpm, &tpm_state_tempdir);
|
||||
if (r < 0) {
|
||||
/* only bail if the user asked for a tpm */
|
||||
if (arg_tpm > 0)
|
||||
return log_error_errno(r, "Failed to start tpm: %m");
|
||||
log_debug_errno(r, "Failed to start tpm, ignoring: %m");
|
||||
}
|
||||
|
||||
r = strv_extend(&cmdline, "-chardev");
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = strv_extendf(&cmdline, "socket,id=chrtpm,path=%s/sock", tpm_state_tempdir);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = strv_extend_many(&cmdline, "-tpmdev", "emulator,id=tpm0,chardev=chrtpm");
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
if (native_architecture() == ARCHITECTURE_X86_64)
|
||||
r = strv_extend_many(&cmdline, "-device", "tpm-tis,tpmdev=tpm0");
|
||||
else if (IN_SET(native_architecture(), ARCHITECTURE_ARM64, ARCHITECTURE_ARM64_BE))
|
||||
r = strv_extend_many(&cmdline, "-device", "tpm-tis-device,tpmdev=tpm0");
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
if (use_vsock) {
|
||||
vsock_fd = open_vsock();
|
||||
if (vsock_fd < 0)
|
||||
@@ -803,6 +955,8 @@ static int run(int argc, char *argv[]) {
|
||||
|
||||
log_setup();
|
||||
|
||||
arg_privileged = getuid() == 0;
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
Reference in New Issue
Block a user