repart: Add verity configuration section and options

This commit is contained in:
Michael A Cassaniti 2023-08-11 19:30:11 +10:00 committed by Luca Boccassi
parent f19659b91f
commit c380047bf4
4 changed files with 165 additions and 40 deletions

View file

@ -576,6 +576,24 @@
<varname>Verity=</varname>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>VerityDataBlockSizeBytes=</varname></term>
<listitem><para>Configures the data block size of the generated verity hash partition. Must be between 512 and
4096 bytes and must be a power of 2. Defaults to the sector size if configured explicitly, or the underlying
block device sector size, or 4K if systemd-repart is not operating on a block device.
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>VerityHashBlockSizeBytes=</varname></term>
<listitem><para>Configures the hash block size of the generated verity hash partition. Must be between 512 and
4096 bytes and must be a power of 2. Defaults to the sector size if configured explicitly, or the underlying
block device sector size, or 4K if systemd-repart is not operating on a block device.
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>FactoryReset=</varname></term>
@ -831,6 +849,9 @@ VerityMatchKey=root
Type=root-verity
Verity=hash
VerityMatchKey=root
# Explicitly set the hash and data block size to 4K
VerityDataBlockSizeBytes=4096
VerityHashBlockSizeBytes=4096
</programlisting></para>
</example>

View file

@ -252,6 +252,8 @@ typedef struct Partition {
VerityMode verity;
char *verity_match_key;
MinimizeMode minimize;
uint64_t verity_data_block_size;
uint64_t verity_hash_block_size;
uint64_t gpt_flags;
int no_auto;
@ -363,6 +365,8 @@ static Partition *partition_new(void) {
.no_auto = -1,
.read_only = -1,
.growfs = -1,
.verity_data_block_size = UINT64_MAX,
.verity_hash_block_size = UINT64_MAX,
};
return p;
@ -1322,6 +1326,40 @@ static int config_parse_size4096(
return 0;
}
static int config_parse_block_size(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
uint64_t *blksz = ASSERT_PTR(data), parsed;
int r;
assert(rvalue);
r = parse_size(rvalue, 1024, &parsed);
if (r < 0)
return log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to parse size value: %s", rvalue);
if (parsed < 512 || parsed > 4096)
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
"Value not between 512 and 4096: %s", rvalue);
if (!ISPOWEROF2(parsed))
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
"Value not a power of 2: %s", rvalue);
*blksz = parsed;
return 0;
}
static int config_parse_fstype(
const char *unit,
const char *filename,
@ -1616,33 +1654,35 @@ static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_minimize, minimize_mod
static int partition_read_definition(Partition *p, const char *path, const char *const *conf_file_dirs) {
ConfigTableItem table[] = {
{ "Partition", "Type", config_parse_type, 0, &p->type },
{ "Partition", "Label", config_parse_label, 0, &p->new_label },
{ "Partition", "UUID", config_parse_uuid, 0, p },
{ "Partition", "Priority", config_parse_int32, 0, &p->priority },
{ "Partition", "Weight", config_parse_weight, 0, &p->weight },
{ "Partition", "PaddingWeight", config_parse_weight, 0, &p->padding_weight },
{ "Partition", "SizeMinBytes", config_parse_size4096, 1, &p->size_min },
{ "Partition", "SizeMaxBytes", config_parse_size4096, -1, &p->size_max },
{ "Partition", "PaddingMinBytes", config_parse_size4096, 1, &p->padding_min },
{ "Partition", "PaddingMaxBytes", config_parse_size4096, -1, &p->padding_max },
{ "Partition", "FactoryReset", config_parse_bool, 0, &p->factory_reset },
{ "Partition", "CopyBlocks", config_parse_copy_blocks, 0, p },
{ "Partition", "Format", config_parse_fstype, 0, &p->format },
{ "Partition", "CopyFiles", config_parse_copy_files, 0, &p->copy_files },
{ "Partition", "ExcludeFiles", config_parse_exclude_files, 0, &p->exclude_files_source },
{ "Partition", "ExcludeFilesTarget", config_parse_exclude_files, 0, &p->exclude_files_target },
{ "Partition", "MakeDirectories", config_parse_make_dirs, 0, &p->make_directories },
{ "Partition", "Encrypt", config_parse_encrypt, 0, &p->encrypt },
{ "Partition", "Verity", config_parse_verity, 0, &p->verity },
{ "Partition", "VerityMatchKey", config_parse_string, 0, &p->verity_match_key },
{ "Partition", "Flags", config_parse_gpt_flags, 0, &p->gpt_flags },
{ "Partition", "ReadOnly", config_parse_tristate, 0, &p->read_only },
{ "Partition", "NoAuto", config_parse_tristate, 0, &p->no_auto },
{ "Partition", "GrowFileSystem", config_parse_tristate, 0, &p->growfs },
{ "Partition", "SplitName", config_parse_string, 0, &p->split_name_format },
{ "Partition", "Minimize", config_parse_minimize, 0, &p->minimize },
{ "Partition", "Subvolumes", config_parse_make_dirs, 0, &p->subvolumes },
{ "Partition", "Type", config_parse_type, 0, &p->type },
{ "Partition", "Label", config_parse_label, 0, &p->new_label },
{ "Partition", "UUID", config_parse_uuid, 0, p },
{ "Partition", "Priority", config_parse_int32, 0, &p->priority },
{ "Partition", "Weight", config_parse_weight, 0, &p->weight },
{ "Partition", "PaddingWeight", config_parse_weight, 0, &p->padding_weight },
{ "Partition", "SizeMinBytes", config_parse_size4096, 1, &p->size_min },
{ "Partition", "SizeMaxBytes", config_parse_size4096, -1, &p->size_max },
{ "Partition", "PaddingMinBytes", config_parse_size4096, 1, &p->padding_min },
{ "Partition", "PaddingMaxBytes", config_parse_size4096, -1, &p->padding_max },
{ "Partition", "FactoryReset", config_parse_bool, 0, &p->factory_reset },
{ "Partition", "CopyBlocks", config_parse_copy_blocks, 0, p },
{ "Partition", "Format", config_parse_fstype, 0, &p->format },
{ "Partition", "CopyFiles", config_parse_copy_files, 0, &p->copy_files },
{ "Partition", "ExcludeFiles", config_parse_exclude_files, 0, &p->exclude_files_source },
{ "Partition", "ExcludeFilesTarget", config_parse_exclude_files, 0, &p->exclude_files_target },
{ "Partition", "MakeDirectories", config_parse_make_dirs, 0, &p->make_directories },
{ "Partition", "Encrypt", config_parse_encrypt, 0, &p->encrypt },
{ "Partition", "Verity", config_parse_verity, 0, &p->verity },
{ "Partition", "VerityMatchKey", config_parse_string, 0, &p->verity_match_key },
{ "Partition", "Flags", config_parse_gpt_flags, 0, &p->gpt_flags },
{ "Partition", "ReadOnly", config_parse_tristate, 0, &p->read_only },
{ "Partition", "NoAuto", config_parse_tristate, 0, &p->no_auto },
{ "Partition", "GrowFileSystem", config_parse_tristate, 0, &p->growfs },
{ "Partition", "SplitName", config_parse_string, 0, &p->split_name_format },
{ "Partition", "Minimize", config_parse_minimize, 0, &p->minimize },
{ "Partition", "Subvolumes", config_parse_make_dirs, 0, &p->subvolumes },
{ "Partition", "VerityDataBlockSizeBytes", config_parse_block_size, 0, &p->verity_data_block_size },
{ "Partition", "VerityHashBlockSizeBytes", config_parse_block_size, 0, &p->verity_hash_block_size },
{}
};
int r;
@ -3938,6 +3978,11 @@ static int partition_format_verity_hash(
node = partition_target_path(t);
}
if (p->verity_data_block_size == UINT64_MAX)
p->verity_data_block_size = context->fs_sector_size;
if (p->verity_hash_block_size == UINT64_MAX)
p->verity_hash_block_size = context->fs_sector_size;
r = sym_crypt_init(&cd, node);
if (r < 0)
return log_error_errno(r, "Failed to allocate libcryptsetup context for %s: %m", node);
@ -3951,8 +3996,8 @@ static int partition_format_verity_hash(
.flags = CRYPT_VERITY_CREATE_HASH,
.hash_name = "sha256",
.hash_type = 1,
.data_block_size = context->fs_sector_size,
.hash_block_size = context->fs_sector_size,
.data_block_size = p->verity_data_block_size,
.hash_block_size = p->verity_hash_block_size,
.salt_size = sizeof(p->verity_salt),
.salt = (const char*)p->verity_salt,
});

View file

@ -16,6 +16,7 @@ test_append_files() {
instmods dm_verity =md
instmods erofs
generate_module_dependencies
image_install veritysetup
image_install -o mksquashfs
image_install -o mkfs.erofs
fi

View file

@ -99,7 +99,7 @@ testcase_basic() {
imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
chmod a+rx "$defs"
chmod 0755 "$defs"
echo "*** 1. create an empty image ***"
@ -395,7 +395,7 @@ testcase_dropin() {
imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
chmod a+rx "$defs"
chmod 0755 "$defs"
tee "$defs/root.conf" <<EOF
[Partition]
@ -455,7 +455,7 @@ testcase_multiple_definitions() {
imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
chmod a+rx "$defs"
chmod 0755 "$defs"
mkdir -p "$defs/1"
tee "$defs/1/root1.conf" <<EOF
@ -526,7 +526,7 @@ testcase_copy_blocks() {
imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
chmod a+rx "$defs"
chmod 0755 "$defs"
echo "*** First, create a disk image and verify its in order ***"
@ -610,7 +610,7 @@ testcase_unaligned_partition() {
imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
chmod a+rx "$defs"
chmod 0755 "$defs"
echo "*** Operate on an image with unaligned partition ***"
@ -647,7 +647,7 @@ testcase_issue_21817() {
imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
chmod a+rx "$defs"
chmod 0755 "$defs"
echo "*** testcase for #21817 ***"
@ -685,7 +685,7 @@ testcase_issue_24553() {
imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
chmod a+rx "$defs"
chmod 0755 "$defs"
echo "*** testcase for #24553 ***"
@ -790,7 +790,7 @@ testcase_zero_uuid() {
imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
chmod a+rx "$defs"
chmod 0755 "$defs"
echo "*** Test image with zero UUID ***"
@ -820,7 +820,7 @@ testcase_verity() {
imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
chmod a+rx "$defs"
chmod 0755 "$defs"
echo "*** dm-verity ***"
@ -907,6 +907,64 @@ EOF
systemd-dissect -U "$imgs/mnt"
}
testcase_verity_explicit_block_size() {
local defs imgs loop
if systemd-detect-virt --quiet --container; then
echo "Skipping verity block size tests in container."
return
fi
defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
chmod 0755 "$defs"
echo "*** varying-dm-verity-block-sizes ***"
tee "$defs/verity-data.conf" <<EOF
[Partition]
Type=root-${architecture}
CopyFiles=${defs}
Verity=data
VerityMatchKey=root
Minimize=guess
EOF
tee "$defs/verity-hash.conf" <<EOF
[Partition]
Type=root-${architecture}-verity
Verity=hash
VerityMatchKey=root
VerityHashBlockSizeBytes=1024
VerityDataBlockSizeBytes=4096
Minimize=yes
EOF
systemd-repart --offline="$OFFLINE" \
--definitions="$defs" \
--seed="$seed" \
--dry-run=no \
--empty=create \
--size=auto \
--json=pretty \
"$imgs/verity"
loop="$(losetup --partscan --show --find "$imgs/verity")"
# Make sure the loopback device gets cleaned up
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs' ; losetup -d '$loop'" RETURN ERR
udevadm wait --timeout 60 --settle "${loop:?}"
# Check that the verity block sizes are as expected
veritysetup dump "${loop}p2" | grep 'Data block size:' | grep -q '4096'
veritysetup dump "${loop}p2" | grep 'Hash block size:' | grep -q '1024'
}
testcase_exclude_files() {
local defs imgs root output
@ -915,7 +973,7 @@ testcase_exclude_files() {
root="$(mktemp --directory "/var/tmp/test-repart.root.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs' '$root'" RETURN
chmod a+rx "$defs"
chmod 0755 "$defs"
echo "*** file exclusion ***"
@ -1070,7 +1128,7 @@ testcase_free_area_calculation() {
imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
# shellcheck disable=SC2064
trap "rm -rf '$defs' '$imgs'" RETURN
chmod a+rx "$defs"
chmod 0755 "$defs"
# https://github.com/systemd/systemd/issues/28225
echo "*** free area calculation ***"