mirror of
https://github.com/systemd/systemd.git
synced 2025-01-03 05:18:09 +03:00
pcrlock: add basic Varlink interface
This can be used to make or delete a PCR policy via Varlink. It can also be used to query the current event log in CEL format.
This commit is contained in:
parent
9fe15ce84d
commit
15138e7980
@ -48,6 +48,8 @@
|
|||||||
#include "unaligned.h"
|
#include "unaligned.h"
|
||||||
#include "unit-name.h"
|
#include "unit-name.h"
|
||||||
#include "utf8.h"
|
#include "utf8.h"
|
||||||
|
#include "varlink.h"
|
||||||
|
#include "varlink-io.systemd.PCRLock.h"
|
||||||
#include "verbs.h"
|
#include "verbs.h"
|
||||||
|
|
||||||
static PagerFlags arg_pager_flags = 0;
|
static PagerFlags arg_pager_flags = 0;
|
||||||
@ -65,6 +67,7 @@ static char *arg_policy_path = NULL;
|
|||||||
static bool arg_force = false;
|
static bool arg_force = false;
|
||||||
static BootEntryTokenType arg_entry_token_type = BOOT_ENTRY_TOKEN_AUTO;
|
static BootEntryTokenType arg_entry_token_type = BOOT_ENTRY_TOKEN_AUTO;
|
||||||
static char *arg_entry_token = NULL;
|
static char *arg_entry_token = NULL;
|
||||||
|
static bool arg_varlink = false;
|
||||||
|
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_components, strv_freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_components, strv_freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_pcrlock_path, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_pcrlock_path, freep);
|
||||||
@ -4310,7 +4313,7 @@ static int write_boot_policy_file(const char *json_text) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int verb_make_policy(int argc, char *argv[], void *userdata) {
|
static int make_policy(bool force, bool recovery_pin) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
/* Here's how this all works: after predicting all possible PCR values for next boot (with
|
/* Here's how this all works: after predicting all possible PCR values for next boot (with
|
||||||
@ -4385,11 +4388,11 @@ static int verb_make_policy(int argc, char *argv[], void *userdata) {
|
|||||||
if (arg_nv_index != 0 && old_policy.nv_index != arg_nv_index)
|
if (arg_nv_index != 0 && old_policy.nv_index != arg_nv_index)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Stored policy references different NV index (0x%x) than specified (0x%x), refusing.", old_policy.nv_index, arg_nv_index);
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Stored policy references different NV index (0x%x) than specified (0x%x), refusing.", old_policy.nv_index, arg_nv_index);
|
||||||
|
|
||||||
if (!arg_force &&
|
if (!force &&
|
||||||
old_policy.algorithm == el->primary_algorithm &&
|
old_policy.algorithm == el->primary_algorithm &&
|
||||||
tpm2_pcr_prediction_equal(&old_policy.prediction, &new_prediction, el->primary_algorithm)) {
|
tpm2_pcr_prediction_equal(&old_policy.prediction, &new_prediction, el->primary_algorithm)) {
|
||||||
log_info("Prediction is identical to current policy, skipping update.");
|
log_info("Prediction is identical to current policy, skipping update.");
|
||||||
return EXIT_SUCCESS;
|
return 0; /* NOP */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4434,7 +4437,7 @@ static int verb_make_policy(int argc, char *argv[], void *userdata) {
|
|||||||
|
|
||||||
/* Acquire a recovery PIN, either from the user, or create a randomized one */
|
/* Acquire a recovery PIN, either from the user, or create a randomized one */
|
||||||
_cleanup_(erase_and_freep) char *pin = NULL;
|
_cleanup_(erase_and_freep) char *pin = NULL;
|
||||||
if (arg_recovery_pin) {
|
if (recovery_pin) {
|
||||||
r = getenv_steal_erase("PIN", &pin);
|
r = getenv_steal_erase("PIN", &pin);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to acquire PIN from environment: %m");
|
return log_error_errno(r, "Failed to acquire PIN from environment: %m");
|
||||||
@ -4712,7 +4715,11 @@ static int verb_make_policy(int argc, char *argv[], void *userdata) {
|
|||||||
|
|
||||||
log_info("Overall time spent: %s", FORMAT_TIMESPAN(usec_sub_unsigned(now(CLOCK_MONOTONIC), start_usec), 1));
|
log_info("Overall time spent: %s", FORMAT_TIMESPAN(usec_sub_unsigned(now(CLOCK_MONOTONIC), start_usec), 1));
|
||||||
|
|
||||||
return 0;
|
return 1; /* installed new policy */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int verb_make_policy(int argc, char *argv[], void *userdata) {
|
||||||
|
return make_policy(arg_force, arg_recovery_pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int undefine_policy_nv_index(
|
static int undefine_policy_nv_index(
|
||||||
@ -4768,7 +4775,7 @@ static int undefine_policy_nv_index(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int verb_remove_policy(int argc, char *argv[], void *userdata) {
|
static int remove_policy(void) {
|
||||||
int ret = 0, r;
|
int ret = 0, r;
|
||||||
|
|
||||||
_cleanup_(tpm2_pcrlock_policy_done) Tpm2PCRLockPolicy policy = {};
|
_cleanup_(tpm2_pcrlock_policy_done) Tpm2PCRLockPolicy policy = {};
|
||||||
@ -4807,6 +4814,10 @@ static int verb_remove_policy(int argc, char *argv[], void *userdata) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int verb_remove_policy(int argc, char *argv[], void *userdata) {
|
||||||
|
return remove_policy();
|
||||||
|
}
|
||||||
|
|
||||||
static int help(int argc, char *argv[], void *userdata) {
|
static int help(int argc, char *argv[], void *userdata) {
|
||||||
_cleanup_free_ char *link = NULL;
|
_cleanup_free_ char *link = NULL;
|
||||||
int r;
|
int r;
|
||||||
@ -5082,6 +5093,14 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
return log_oom();
|
return log_oom();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = varlink_invocation(VARLINK_ALLOW_ACCEPT);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to check if invoked in Varlink mode: %m");
|
||||||
|
if (r > 0) {
|
||||||
|
arg_varlink = true;
|
||||||
|
arg_pager_flags |= PAGER_DISABLE;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5124,6 +5143,88 @@ static int pcrlock_main(int argc, char *argv[]) {
|
|||||||
return dispatch_verb(argc, argv, verbs, NULL);
|
return dispatch_verb(argc, argv, verbs, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vl_method_read_event_log(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
|
||||||
|
_cleanup_(event_log_freep) EventLog *el = NULL;
|
||||||
|
uint64_t recnum = 0;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(link);
|
||||||
|
|
||||||
|
if (json_variant_elements(parameters) > 0)
|
||||||
|
return varlink_error_invalid_parameter(link, parameters);
|
||||||
|
|
||||||
|
el = event_log_new();
|
||||||
|
if (!el)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
r = event_log_load(el);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
_cleanup_(json_variant_unrefp) JsonVariant *rec_cel = NULL;
|
||||||
|
|
||||||
|
FOREACH_ARRAY(rr, el->records, el->n_records) {
|
||||||
|
|
||||||
|
if (rec_cel) {
|
||||||
|
r = varlink_notifyb(link,
|
||||||
|
JSON_BUILD_OBJECT(JSON_BUILD_PAIR_VARIANT("record", rec_cel)));
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
rec_cel = json_variant_unref(rec_cel);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = event_log_record_to_cel(*rr, &recnum, &rec_cel);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return varlink_replyb(link,
|
||||||
|
JSON_BUILD_OBJECT(JSON_BUILD_PAIR_CONDITION(rec_cel, "record", JSON_BUILD_VARIANT(rec_cel))));
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct MethodMakePolicyParameters {
|
||||||
|
bool force;
|
||||||
|
} MethodMakePolicyParameters;
|
||||||
|
|
||||||
|
static int vl_method_make_policy(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
|
||||||
|
static const JsonDispatch dispatch_table[] = {
|
||||||
|
{ "force", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(MethodMakePolicyParameters, force), 0 },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MethodMakePolicyParameters p = {};
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(link);
|
||||||
|
|
||||||
|
r = varlink_dispatch(link, parameters, dispatch_table, &p);
|
||||||
|
if (r != 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = make_policy(p.force, /* recovery_key= */ false);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
return varlink_error(link, "io.systemd.PCRLock.NoChange", NULL);
|
||||||
|
|
||||||
|
return varlink_reply(link, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vl_method_remove_policy(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(link);
|
||||||
|
|
||||||
|
if (json_variant_elements(parameters) > 0)
|
||||||
|
return varlink_error_invalid_parameter(link, parameters);
|
||||||
|
|
||||||
|
r = remove_policy();
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return varlink_reply(link, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static int run(int argc, char *argv[]) {
|
static int run(int argc, char *argv[]) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -5133,6 +5234,34 @@ static int run(int argc, char *argv[]) {
|
|||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
if (arg_varlink) {
|
||||||
|
_cleanup_(varlink_server_unrefp) VarlinkServer *varlink_server = NULL;
|
||||||
|
|
||||||
|
/* Invocation as Varlink service */
|
||||||
|
|
||||||
|
r = varlink_server_new(&varlink_server, VARLINK_SERVER_ROOT_ONLY);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to allocate Varlink server: %m");
|
||||||
|
|
||||||
|
r = varlink_server_add_interface(varlink_server, &vl_interface_io_systemd_PCRLock);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to add Varlink interface: %m");
|
||||||
|
|
||||||
|
r = varlink_server_bind_method_many(
|
||||||
|
varlink_server,
|
||||||
|
"io.systemd.PCRLock.ReadEventLog", vl_method_read_event_log,
|
||||||
|
"io.systemd.PCRLock.MakePolicy", vl_method_make_policy,
|
||||||
|
"io.systemd.PCRLock.RemovePolicy", vl_method_remove_policy);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to bind Varlink methods: %m");
|
||||||
|
|
||||||
|
r = varlink_server_loop_auto(varlink_server);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to run Varlink event loop: %m");
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
return pcrlock_main(argc, argv);
|
return pcrlock_main(argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,6 +180,7 @@ shared_sources = files(
|
|||||||
'varlink-io.systemd.ManagedOOM.c',
|
'varlink-io.systemd.ManagedOOM.c',
|
||||||
'varlink-io.systemd.Network.c',
|
'varlink-io.systemd.Network.c',
|
||||||
'varlink-io.systemd.PCRExtend.c',
|
'varlink-io.systemd.PCRExtend.c',
|
||||||
|
'varlink-io.systemd.PCRLock.c',
|
||||||
'varlink-io.systemd.Resolve.c',
|
'varlink-io.systemd.Resolve.c',
|
||||||
'varlink-io.systemd.Resolve.Monitor.c',
|
'varlink-io.systemd.Resolve.Monitor.c',
|
||||||
'varlink-io.systemd.UserDatabase.c',
|
'varlink-io.systemd.UserDatabase.c',
|
||||||
|
24
src/shared/varlink-io.systemd.PCRLock.c
Normal file
24
src/shared/varlink-io.systemd.PCRLock.c
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include "varlink-io.systemd.PCRLock.h"
|
||||||
|
|
||||||
|
static VARLINK_DEFINE_METHOD(
|
||||||
|
ReadEventLog);
|
||||||
|
|
||||||
|
static VARLINK_DEFINE_METHOD(
|
||||||
|
MakePolicy,
|
||||||
|
VARLINK_DEFINE_INPUT(force, VARLINK_BOOL, VARLINK_NULLABLE));
|
||||||
|
|
||||||
|
static VARLINK_DEFINE_METHOD(
|
||||||
|
RemovePolicy);
|
||||||
|
|
||||||
|
VARLINK_DEFINE_ERROR(
|
||||||
|
NoChange);
|
||||||
|
|
||||||
|
VARLINK_DEFINE_INTERFACE(
|
||||||
|
io_systemd_PCRLock,
|
||||||
|
"io.systemd.PCRLock",
|
||||||
|
&vl_method_ReadEventLog,
|
||||||
|
&vl_method_MakePolicy,
|
||||||
|
&vl_method_RemovePolicy,
|
||||||
|
&vl_error_NoChange);
|
6
src/shared/varlink-io.systemd.PCRLock.h
Normal file
6
src/shared/varlink-io.systemd.PCRLock.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "varlink-idl.h"
|
||||||
|
|
||||||
|
extern const VarlinkInterface vl_interface_io_systemd_PCRLock;
|
@ -13,6 +13,7 @@
|
|||||||
#include "varlink-io.systemd.ManagedOOM.h"
|
#include "varlink-io.systemd.ManagedOOM.h"
|
||||||
#include "varlink-io.systemd.Network.h"
|
#include "varlink-io.systemd.Network.h"
|
||||||
#include "varlink-io.systemd.PCRExtend.h"
|
#include "varlink-io.systemd.PCRExtend.h"
|
||||||
|
#include "varlink-io.systemd.PCRLock.h"
|
||||||
#include "varlink-io.systemd.Resolve.Monitor.h"
|
#include "varlink-io.systemd.Resolve.Monitor.h"
|
||||||
#include "varlink-io.systemd.Resolve.h"
|
#include "varlink-io.systemd.Resolve.h"
|
||||||
#include "varlink-io.systemd.UserDatabase.h"
|
#include "varlink-io.systemd.UserDatabase.h"
|
||||||
@ -143,6 +144,8 @@ TEST(parse_format) {
|
|||||||
print_separator();
|
print_separator();
|
||||||
test_parse_format_one(&vl_interface_io_systemd_PCRExtend);
|
test_parse_format_one(&vl_interface_io_systemd_PCRExtend);
|
||||||
print_separator();
|
print_separator();
|
||||||
|
test_parse_format_one(&vl_interface_io_systemd_PCRLock);
|
||||||
|
print_separator();
|
||||||
test_parse_format_one(&vl_interface_io_systemd_service);
|
test_parse_format_one(&vl_interface_io_systemd_service);
|
||||||
print_separator();
|
print_separator();
|
||||||
test_parse_format_one(&vl_interface_io_systemd_sysext);
|
test_parse_format_one(&vl_interface_io_systemd_sysext);
|
||||||
|
@ -519,6 +519,15 @@ units = [
|
|||||||
'file' : 'systemd-pcrlock-firmware-config.service.in',
|
'file' : 'systemd-pcrlock-firmware-config.service.in',
|
||||||
'conditions' : ['ENABLE_BOOTLOADER', 'HAVE_OPENSSL', 'HAVE_TPM2'],
|
'conditions' : ['ENABLE_BOOTLOADER', 'HAVE_OPENSSL', 'HAVE_TPM2'],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'file' : 'systemd-pcrlock@.service.in',
|
||||||
|
'conditions' : ['ENABLE_BOOTLOADER', 'HAVE_OPENSSL', 'HAVE_TPM2'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'file' : 'systemd-pcrlock.socket',
|
||||||
|
'conditions' : ['ENABLE_BOOTLOADER', 'HAVE_OPENSSL', 'HAVE_TPM2'],
|
||||||
|
'symlinks' : ['sockets.target.wants/'],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
'file' : 'systemd-portabled.service.in',
|
'file' : 'systemd-portabled.service.in',
|
||||||
'conditions' : ['ENABLE_PORTABLED'],
|
'conditions' : ['ENABLE_PORTABLED'],
|
||||||
|
25
units/systemd-pcrlock.socket
Normal file
25
units/systemd-pcrlock.socket
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# 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=Make TPM2 PCR Policy (Varlink)
|
||||||
|
Documentation=man:systemd-pcrlock(8)
|
||||||
|
DefaultDependencies=no
|
||||||
|
After=tpm2.target
|
||||||
|
Before=sockets.target
|
||||||
|
ConditionSecurity=measured-uki
|
||||||
|
|
||||||
|
[Socket]
|
||||||
|
ListenStream=/run/systemd/io.systemd.PCRLock
|
||||||
|
FileDescriptorName=varlink
|
||||||
|
SocketMode=0600
|
||||||
|
Accept=yes
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=sockets.target
|
21
units/systemd-pcrlock@.service.in
Normal file
21
units/systemd-pcrlock@.service.in
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# 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=Make TPM2 PCR Policy (Varlink)
|
||||||
|
Documentation=man:systemd-pcrlock(8)
|
||||||
|
DefaultDependencies=no
|
||||||
|
Conflicts=shutdown.target
|
||||||
|
After=systemd-tpm2-setup.service
|
||||||
|
Before=sysinit.target shutdown.target
|
||||||
|
After=systemd-remount-fs.service var.mount
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Environment=LISTEN_FDNAMES=varlink
|
||||||
|
ExecStart={{LIBEXECDIR}}/systemd-pcrlock --location=770
|
Loading…
Reference in New Issue
Block a user