Merge pull request #31889 from aplanas/fix_pcrlock_stdin

pcrlock: support measurement of big files
This commit is contained in:
Lennart Poettering 2024-04-19 23:57:28 +02:00 committed by GitHub
commit 6e10417ff6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -2679,7 +2679,7 @@ static int make_pcrlock_record(
assert_se(a = tpm2_hash_alg_to_string(*pa));
assert_se(md = EVP_get_digestbyname(a));
hash_ssize = EVP_MD_size(md);
assert_se(hash_ssize > 0);
assert(hash_ssize > 0);
hash_usize = hash_ssize;
hash = malloc(hash_usize);
@ -2708,6 +2708,101 @@ static int make_pcrlock_record(
return 0;
}
static void evp_md_ctx_free_all(EVP_MD_CTX *(*md)[TPM2_N_HASH_ALGORITHMS]) {
assert(md);
FOREACH_ARRAY(alg, *md, TPM2_N_HASH_ALGORITHMS)
if (*alg)
EVP_MD_CTX_free(*alg);
}
static int make_pcrlock_record_from_stream(
uint32_t pcr_mask,
FILE *f,
JsonVariant **ret_records) {
_cleanup_(json_variant_unrefp) JsonVariant *digests = NULL;
_cleanup_(evp_md_ctx_free_all) EVP_MD_CTX *mdctx[TPM2_N_HASH_ALGORITHMS] = {};
int r;
assert(f);
assert(ret_records);
for (size_t i = 0; i < TPM2_N_HASH_ALGORITHMS; i++) {
const char *a;
const EVP_MD *md;
assert_se(a = tpm2_hash_alg_to_string(tpm2_hash_algorithms[i]));
assert_se(md = EVP_get_digestbyname(a));
mdctx[i] = EVP_MD_CTX_new();
if (!mdctx[i])
return log_oom();
if (EVP_DigestInit_ex(mdctx[i], md, NULL) != 1)
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
"Failed to initialize message digest for %s.", a);
}
for (;;) {
uint8_t buffer[64*1024];
size_t n;
n = fread(buffer, 1, sizeof(buffer), f);
if (ferror(f))
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to read file: %m");
if (n == 0 && feof(f))
break;
for (size_t i = 0; i < TPM2_N_HASH_ALGORITHMS; i++)
if (EVP_DigestUpdate(mdctx[i], buffer, n) != 1)
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Unable to hash data.");
}
for (size_t i = 0; i < TPM2_N_HASH_ALGORITHMS; i++) {
const char *a;
int hash_ssize;
unsigned hash_usize;
assert_se(a = tpm2_hash_alg_to_string(tpm2_hash_algorithms[i]));
hash_ssize = EVP_MD_CTX_size(mdctx[i]);
assert(hash_ssize > 0 && hash_ssize <= EVP_MAX_MD_SIZE);
hash_usize = hash_ssize;
unsigned char hash[hash_usize];
if (EVP_DigestFinal_ex(mdctx[i], hash, &hash_usize) != 1)
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
"Failed to finalize hash context for algorithn '%s'.", a);
r = json_variant_append_arrayb(
&digests,
JSON_BUILD_OBJECT(
JSON_BUILD_PAIR("hashAlg", JSON_BUILD_STRING(a)),
JSON_BUILD_PAIR("digest", JSON_BUILD_HEX(hash, hash_usize))));
if (r < 0)
return log_error_errno(r, "Failed to build JSON digest object: %m");
}
for (uint32_t i = 0; i < TPM2_PCRS_MAX; i++) {
_cleanup_(json_variant_unrefp) JsonVariant *record = NULL;
if (!FLAGS_SET(pcr_mask, UINT32_C(1) << i))
continue;
r = json_build(&record,
JSON_BUILD_OBJECT(
JSON_BUILD_PAIR("pcr", JSON_BUILD_UNSIGNED(i)),
JSON_BUILD_PAIR("digests", JSON_BUILD_VARIANT(digests))));
if (r < 0)
return log_error_errno(r, "Failed to build record object: %m");
r = json_variant_append_array(ret_records, record);
if (r < 0)
return log_error_errno(r, "Failed to append to JSON array: %m");
}
return 0;
}
static const char *pcrlock_path(const char *default_pcrlock_path) {
return arg_pcrlock_path ?: arg_pcrlock_auto ? default_pcrlock_path : NULL;
}
@ -2771,10 +2866,8 @@ static int unlink_pcrlock(const char *default_pcrlock_path) {
}
static int verb_lock_raw(int argc, char *argv[], void *userdata) {
_cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
_cleanup_free_ char *data = NULL;
_cleanup_(json_variant_unrefp) JsonVariant *records = NULL;
_cleanup_fclose_ FILE *f = NULL;
size_t size;
int r;
if (arg_pcr_mask == 0)
@ -2786,26 +2879,11 @@ static int verb_lock_raw(int argc, char *argv[], void *userdata) {
return log_error_errno(errno, "Failed to open '%s': %m", argv[1]);
}
r = read_full_stream(f ?: stdin, &data, &size);
r = make_pcrlock_record_from_stream(arg_pcr_mask, f ?: stdin, &records);
if (r < 0)
return log_error_errno(r, "Failed to read data from stdin: %m");
return r;
for (uint32_t i = 0; i < TPM2_PCRS_MAX; i++) {
_cleanup_(json_variant_unrefp) JsonVariant *record = NULL;
if (!FLAGS_SET(arg_pcr_mask, UINT32_C(1) << i))
continue;
r = make_pcrlock_record(i, data, size, &record);
if (r < 0)
return r;
r = json_variant_append_array(&array, record);
if (r < 0)
return log_error_errno(r, "Failed to append to JSON array: %m");
}
return write_pcrlock(array, NULL);
return write_pcrlock(records, NULL);
}
static int verb_unlock_simple(int argc, char *argv[], void *userdata) {
@ -3813,10 +3891,9 @@ static int verb_unlock_kernel_cmdline(int argc, char *argv[], void *userdata) {
}
static int verb_lock_kernel_initrd(int argc, char *argv[], void *userdata) {
_cleanup_(json_variant_unrefp) JsonVariant *record = NULL, *array = NULL;
_cleanup_free_ void *data = NULL;
_cleanup_(json_variant_unrefp) JsonVariant *records = NULL;
_cleanup_fclose_ FILE *f = NULL;
size_t size;
uint32_t pcr_mask = UINT32_C(1) << TPM2_PCR_KERNEL_INITRD;
int r;
if (argc >= 2) {
@ -3825,19 +3902,11 @@ static int verb_lock_kernel_initrd(int argc, char *argv[], void *userdata) {
return log_error_errno(errno, "Failed to open '%s': %m", argv[1]);
}
r = read_full_stream(f ?: stdin, (char**) &data, &size);
if (r < 0)
return log_error_errno(r, "Failed to read data from stdin: %m");
r = make_pcrlock_record(TPM2_PCR_KERNEL_INITRD /* = 9 */, data, size, &record);
r = make_pcrlock_record_from_stream(pcr_mask, f ?: stdin, &records);
if (r < 0)
return r;
r = json_variant_new_array(&array, &record, 1);
if (r < 0)
return log_error_errno(r, "Failed to create record array: %m");
r = write_pcrlock(array, PCRLOCK_KERNEL_INITRD_PATH);
r = write_pcrlock(records, PCRLOCK_KERNEL_INITRD_PATH);
if (r < 0)
return r;