pcrextend: add support for measuring a user record, to be executed on first login of the user
This is supposed to be useful to mark an interactive user login as a "break glass" event in the measurement logs, i.e. as in many typically headless scenerios this indicates debug access or similar.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "sd-device.h"
|
||||
#include "sd-id128.h"
|
||||
#include "sd-json.h"
|
||||
#include "sd-varlink.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
@@ -22,6 +23,7 @@
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "tpm2-pcr.h"
|
||||
#include "user-record.h"
|
||||
|
||||
static int device_get_file_system_word(
|
||||
sd_device *d,
|
||||
@@ -187,6 +189,58 @@ int pcrextend_product_id_word(char **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pcrextend_login_word(UserRecord *ur, char **ret) {
|
||||
int r;
|
||||
|
||||
assert(ur);
|
||||
assert(ret);
|
||||
|
||||
/* Reduce the user record to the sections that make up its stable, host-specific identity, and turn
|
||||
* that into a word to measure into the 'login' NvPCR. We deliberately keep the 'regular',
|
||||
* 'perMachine' and 'binding' sections (the portable identity plus how it is realized on *this*
|
||||
* host), but drop 'privileged' (so password hash churn doesn't perturb the NvPCR), 'secret' and
|
||||
* 'status' (transient) and 'signature' (so the scheme is identical for signed and unsigned records).
|
||||
* Only 'regular' is required, the others are merely allowed, so plain NSS users reduce cleanly. */
|
||||
UserRecordLoadFlags mask =
|
||||
USER_RECORD_REQUIRE_REGULAR |
|
||||
USER_RECORD_ALLOW_PER_MACHINE |
|
||||
USER_RECORD_ALLOW_BINDING |
|
||||
USER_RECORD_STRIP_PRIVILEGED |
|
||||
USER_RECORD_STRIP_SECRET |
|
||||
USER_RECORD_STRIP_STATUS |
|
||||
USER_RECORD_STRIP_SIGNATURE |
|
||||
USER_RECORD_PERMISSIVE;
|
||||
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
||||
r = user_group_record_mangle(ur->json, mask, &v, /* ret_mask= */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to reduce user record of '%s': %m", ur->user_name);
|
||||
|
||||
/* Normalize so the serialization is canonical (stable key order) regardless of how the record was
|
||||
* assembled by the various userdb backends. */
|
||||
r = sd_json_variant_normalize(&v);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to normalize user record of '%s': %m", ur->user_name);
|
||||
|
||||
/* Format to compact, single-line JSON (no SD_JSON_FORMAT_NEWLINE), so the measured word stays on one
|
||||
* line and the colon-separated word structure is unambiguous. */
|
||||
_cleanup_free_ char *text = NULL;
|
||||
r = sd_json_variant_format(v, /* flags= */ 0, &text);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to format user record of '%s': %m", ur->user_name);
|
||||
|
||||
_cleanup_free_ char *name_escaped = xescape(ur->user_name, ":"); /* Avoid ambiguity around ":" */
|
||||
if (!name_escaped)
|
||||
return log_oom();
|
||||
|
||||
_cleanup_free_ char *word = strjoin("login:", name_escaped, ":", text);
|
||||
if (!word)
|
||||
return log_oom();
|
||||
|
||||
*ret = TAKE_PTR(word);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pcrextend_verity_word(
|
||||
const char *name,
|
||||
const struct iovec *root_hash,
|
||||
|
||||
@@ -3,11 +3,14 @@
|
||||
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "shared-forward.h"
|
||||
|
||||
int pcrextend_file_system_word(const char *path, char **ret, char **ret_normalized_path);
|
||||
int pcrextend_machine_id_word(char **ret);
|
||||
int pcrextend_product_id_word(char **ret);
|
||||
int pcrextend_verity_word(const char *name, const struct iovec *root_hash, const struct iovec *root_hash_sig, char **ret);
|
||||
int pcrextend_imds_userdata_word(const struct iovec *data, char **ret);
|
||||
int pcrextend_login_word(UserRecord *ur, char **ret);
|
||||
|
||||
int pcrextend_verity_now(const char *name, const struct iovec *root_hash, const struct iovec *root_hash_sig);
|
||||
int pcrextend_imds_userdata_now(const struct iovec *data);
|
||||
|
||||
@@ -6702,6 +6702,7 @@ static const char* tpm2_userspace_event_type_table[_TPM2_USERSPACE_EVENT_TYPE_MA
|
||||
[TPM2_EVENT_DM_VERITY] = "dm-verity",
|
||||
[TPM2_EVENT_IMDS_USERDATA] = "imds-userdata",
|
||||
[TPM2_EVENT_OS_SEPARATOR] = "os-separator",
|
||||
[TPM2_EVENT_LOGIN] = "login",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(tpm2_userspace_event_type, Tpm2UserspaceEventType);
|
||||
|
||||
@@ -151,6 +151,7 @@ typedef enum Tpm2UserspaceEventType {
|
||||
TPM2_EVENT_DM_VERITY,
|
||||
TPM2_EVENT_IMDS_USERDATA,
|
||||
TPM2_EVENT_OS_SEPARATOR,
|
||||
TPM2_EVENT_LOGIN,
|
||||
_TPM2_USERSPACE_EVENT_TYPE_MAX,
|
||||
_TPM2_USERSPACE_EVENT_TYPE_INVALID = -EINVAL,
|
||||
} Tpm2UserspaceEventType;
|
||||
|
||||
Reference in New Issue
Block a user