['systemd-report-sign-plain',
'systemd-report-sign-plain.socket'],
'HAVE_OPENSSL'],
+ ['systemd-report-sign-tsm@.service',
+ '8',
+ ['systemd-report-sign-tsm',
+ 'systemd-report-sign-tsm.socket'],
+ ''],
['systemd-resolved.service', '8', ['systemd-resolved'], 'ENABLE_RESOLVE'],
['systemd-rfkill.service',
'8',
--- /dev/null
+<?xml version="1.0"?> <!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
+
+<refentry id="systemd-report-sign-tsm_.service"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+
+ <refentryinfo>
+ <title>systemd-report-sign-tsm@.service</title>
+ <productname>systemd</productname>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>systemd-report-sign-tsm@.service</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>systemd-report-sign-tsm@.service</refname>
+ <refname>systemd-report-sign-tsm.socket</refname>
+ <refname>systemd-report-sign-tsm</refname>
+ <refpurpose>Sign system reports with a confidential-computing attestation report</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <para><filename>systemd-report-sign-tsm@.service</filename></para>
+ <para><filename>systemd-report-sign-tsm.socket</filename></para>
+ <para><filename>/usr/lib/systemd/systemd-report-sign-tsm</filename></para>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para><command>systemd-report-sign-tsm@.service</command> is a system service that signs system reports
+ generated by
+ <citerefentry><refentrytitle>systemd-report</refentrytitle><manvolnum>1</manvolnum></citerefentry>. It is
+ a signing backend for the <option>--sign=</option> logic of that tool: it implements the
+ <function>io.systemd.Report.Signer.Sign()</function> Varlink method and is reached via a socket linked into
+ the <filename>/run/systemd/report.sign/</filename> directory, named <filename>tsm</filename>.</para>
+
+ <para>The service is socket-activated (one instance per connection) via
+ <filename>systemd-report-sign-tsm.socket</filename>. Rather than signing with a local key, it obtains a
+ hardware-backed attestation report from the platform's Trusted Security Module (TSM) through the kernel's
+ configfs-TSM interface at <filename>/sys/kernel/config/tsm/report/</filename>. The digest passed to it is
+ embedded into the report as its run-time provided data (<literal>inblob</literal>), cryptographically
+ binding the attestation report to the system report being signed.</para>
+
+ <para>The returned signature carries the binary attestation report (the <literal>outblob</literal>), the
+ name of the TSM provider that generated it (for example <literal>sev_guest</literal> for AMD SEV-SNP or
+ <literal>tdx_guest</literal> for Intel TDX), and, where the provider supplies them, supplemental
+ certificate (<literal>auxblob</literal>) and manifest (<literal>manifestblob</literal>) data. A verifier
+ selects the appropriate validation logic based on the provider field.</para>
+
+ <para>This backend is only functional inside a confidential virtual machine whose kernel exposes the
+ configfs-TSM interface (such as AMD SEV-SNP or Intel TDX guests). On systems where the interface is
+ unavailable the signing operation is reported as unsupported and the mechanism is skipped. The service
+ keeps no persistent state.</para>
+ </refsect1>
+
+ <!-- Note: we do not document the command line switches here. The systemd-report-sign-tsm binary itself
+ should not be invoked by users, but only as a service. Use systemd-report(1) to generate signed
+ reports. -->
+
+ <refsect1>
+ <title>See Also</title>
+ <para><simplelist type="inline">
+ <member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
+ <member><citerefentry><refentrytitle>systemd-report</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
+ </simplelist></para>
+ </refsect1>
+
+</refentry>
enable systemd-report-cgroup.socket
enable systemd-report-files.socket
enable systemd-report-sign-plain.socket
+enable systemd-report-sign-tsm.socket
enable systemd-report.socket
enable systemd-resolved.service
enable systemd-sysext.service
),
'dependencies' : libopenssl_cflags,
},
+ libexec_template + {
+ 'name' : 'systemd-report-sign-tsm',
+ 'sources' : files(
+ 'report-sign-tsm.c',
+ ),
+ },
]
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "sd-json.h"
+#include "sd-varlink.h"
+
+#include "build.h"
+#include "format-table.h"
+#include "help-util.h"
+#include "iovec-util.h"
+#include "json-util.h"
+#include "log.h"
+#include "main-func.h"
+#include "options.h"
+#include "sha256.h"
+#include "string-util.h"
+#include "tsm-report.h"
+#include "varlink-io.systemd.Report.Signer.h"
+#include "varlink-util.h"
+
+typedef struct SignParameters {
+ struct iovec digest;
+ const char *algorithm;
+} SignParameters;
+
+static void sign_parameters_done(SignParameters *p) {
+ iovec_done(&p->digest);
+}
+
+static int vl_method_sign(
+ sd_varlink *link,
+ sd_json_variant *parameters,
+ sd_varlink_method_flags_t flags,
+ void *userdata) {
+
+ static const sd_json_dispatch_field dispatch_table[] = {
+ { "digest", SD_JSON_VARIANT_STRING, json_dispatch_unhex_iovec, offsetof(SignParameters, digest), SD_JSON_MANDATORY },
+ { "algorithm", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(SignParameters, algorithm), SD_JSON_MANDATORY },
+ {}
+ };
+
+ _cleanup_(sign_parameters_done) SignParameters sp = {};
+ _cleanup_(tsm_report_freep) TsmReport *report = NULL;
+ int r;
+
+ assert(link);
+ assert(parameters);
+
+ r = sd_varlink_dispatch(link, parameters, dispatch_table, &sp);
+ if (r != 0)
+ return r;
+
+ if (!streq(sp.algorithm, "SHA256"))
+ return sd_varlink_error_invalid_parameter_name(link, "algorithm");
+ if (sp.digest.iov_len != SHA256_DIGEST_SIZE)
+ return sd_varlink_error_invalid_parameter_name(link, "digest");
+
+ uint8_t report_data[TSM_REPORT_DATA_SIZE] = {};
+ memcpy(report_data, sp.digest.iov_base, sp.digest.iov_len);
+
+ r = tsm_report_acquire(&IOVEC_MAKE(report_data, sizeof report_data), /* options= */ NULL, &report);
+ if (IN_SET(r, -EOPNOTSUPP, -ENXIO))
+ /* Returning an error will fail the whole report signing, so we return
+ * no signature instead which will be ignored by the aggregator. */
+ return sd_varlink_replybo(link, SD_JSON_BUILD_PAIR_EMPTY_ARRAY("data"));
+ if (r < 0)
+ return log_error_errno(r, "Failed to acquire TSM report: %m");
+
+ return sd_varlink_replybo(
+ link,
+ SD_JSON_BUILD_PAIR("data",
+ SD_JSON_BUILD_ARRAY(
+ SD_JSON_BUILD_OBJECT(
+ SD_JSON_BUILD_PAIR_STRING("provider", report->provider),
+ JSON_BUILD_PAIR_IOVEC_BASE64("outblob", &report->outblob),
+ SD_JSON_BUILD_PAIR_CONDITION(iovec_is_set(&report->auxblob),
+ "auxblob", JSON_BUILD_IOVEC_BASE64(&report->auxblob)),
+ SD_JSON_BUILD_PAIR_CONDITION(iovec_is_set(&report->manifestblob),
+ "manifestblob", JSON_BUILD_IOVEC_BASE64(&report->manifestblob))))));
+}
+
+static int vl_server(void) {
+ _cleanup_(sd_varlink_server_unrefp) sd_varlink_server *vs = NULL;
+ int r;
+
+ r = varlink_server_new(&vs, SD_VARLINK_SERVER_ROOT_ONLY|SD_VARLINK_SERVER_MYSELF_ONLY, /* userdata= */ NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate Varlink server: %m");
+
+ r = sd_varlink_server_add_interface(vs, &vl_interface_io_systemd_Report_Signer);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add Varlink interface: %m");
+
+ r = sd_varlink_server_bind_method(vs, "io.systemd.Report.Signer.Sign", vl_method_sign);
+ if (r < 0)
+ return log_error_errno(r, "Failed to bind Varlink methods: %m");
+
+ r = sd_varlink_server_loop_auto(vs);
+ if (r < 0)
+ return log_error_errno(r, "Failed to run Varlink event loop: %m");
+
+ return 0;
+}
+
+static int help(void) {
+ _cleanup_(table_unrefp) Table *options = NULL;
+ int r;
+
+ r = option_parser_get_help_table(&options);
+ if (r < 0)
+ return r;
+
+ help_cmdline("[OPTIONS...]");
+ help_abstract("Get an attestation report via configfs Trusted Security Module (TSM) "
+ "that includes the hash of the system report.");
+ help_section("Options");
+
+ r = table_print_or_warn(options);
+ if (r < 0)
+ return r;
+
+ help_man_page_reference("systemd-report-sign-tsm@.service", "8");
+ return 0;
+}
+
+static int parse_argv(int argc, char *argv[]) {
+ int r;
+
+ assert(argc >= 0);
+ assert(argv);
+
+ OptionParser opts = { argc, argv };
+
+ FOREACH_OPTION_OR_RETURN(c, &opts)
+ switch (c) {
+ OPTION_COMMON_HELP:
+ return help();
+ OPTION_COMMON_VERSION:
+ return version();
+ }
+
+ if (option_parser_get_n_args(&opts) > 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "This program takes no arguments.");
+
+ r = sd_varlink_invocation(SD_VARLINK_ALLOW_ACCEPT);
+ if (r < 0)
+ return log_error_errno(r, "Failed to check if invoked in Varlink mode: %m");
+ if (r == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "This program can only run as a Varlink service.");
+
+ return 1;
+}
+
+static int run(int argc, char *argv[]) {
+ int r;
+
+ log_setup();
+
+ r = parse_argv(argc, argv);
+ if (r <= 0)
+ return r;
+
+ return vl_server();
+}
+
+DEFINE_MAIN_FUNCTION(run);
'file' : 'systemd-report-sign-plain@.service.in',
'conditions' : ['HAVE_OPENSSL'],
},
+ { 'file' : 'systemd-report-sign-tsm.socket' },
+ { 'file' : 'systemd-report-sign-tsm@.service.in' },
{
'file' : 'systemd-resolved.service.in',
'conditions' : ['ENABLE_RESOLVE'],
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+
+[Unit]
+Description=Report Signing Socket (configfs-tsm)
+Documentation=man:systemd-report-sign-tsm@.service(8)
+DefaultDependencies=no
+Before=sockets.target shutdown.target
+Conflicts=shutdown.target
+ConditionSecurity=cvm
+
+[Socket]
+ListenStream=/run/systemd/report.sign/tsm
+FileDescriptorName=varlink
+SocketMode=0600
+Accept=yes
+MaxConnectionsPerSource=16
+RemoveOnStop=yes
+
+[Install]
+WantedBy=sockets.target
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+
+[Unit]
+Description=Report Signing Service (configfs-tsm)
+Documentation=man:systemd-report-sign-tsm@.service(8)
+DefaultDependencies=no
+Before=shutdown.target
+Conflicts=shutdown.target
+Wants=sys-kernel-config.mount
+After=sys-kernel-config.mount
+
+[Service]
+ExecStart={{LIBEXECDIR}}/systemd-report-sign-tsm
+CapabilityBoundingSet=
+DeviceAllow=
+IPAddressDeny=any
+LockPersonality=yes
+MemoryDenyWriteExecute=yes
+NoNewPrivileges=yes
+PrivateDevices=yes
+PrivateIPC=yes
+PrivateNetwork=yes
+PrivateTmp=disconnected
+ProtectControlGroups=yes
+ProtectHome=yes
+ProtectHostname=yes
+ProtectKernelLogs=yes
+ProtectKernelModules=yes
+ProtectKernelTunables=yes
+ProtectSystem=strict
+ReadWritePaths=-/sys/kernel/config/tsm/report
+RestrictAddressFamilies=AF_UNIX
+RestrictNamespaces=yes
+RestrictRealtime=yes
+RestrictSUIDSGID=yes
+RuntimeMaxSec=5min
+SystemCallArchitectures=native
+SystemCallErrorNumber=EPERM
+SystemCallFilter=@system-service