1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-25 10:04:04 +03:00

Merge pull request #18789 from gportay/veritysetup-add-options-for-parity-with-cryptsetup-verity-utility

veritysetup: Add options for parity support with the cryptsetup's verity utility
This commit is contained in:
Lennart Poettering 2023-04-13 11:32:57 +02:00 committed by GitHub
commit 796da645a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 289 additions and 5 deletions

View File

@ -85,8 +85,17 @@
<term><varname>systemd.verity_root_options=</varname></term>
<listitem><para>Takes a comma-separated list of dm-verity options. Expects the following options
<option>superblock=<replaceable>BOOLEAN</replaceable></option>,
<option>format=<replaceable>NUMBER</replaceable></option>,
<option>data-block-size=<replaceable>BYTES</replaceable></option>,
<option>hash-block-size=<replaceable>BYTES</replaceable></option>,
<option>data-blocks=<replaceable>BLOCKS</replaceable></option>,
<option>hash-offset=<replaceable>BYTES</replaceable></option>,
<option>salt=<replaceable>HEX</replaceable></option>, <option>uuid=<replaceable>UUID</replaceable></option>,
<option>ignore-corruption</option>, <option>restart-on-corruption</option>, <option>ignore-zero-blocks</option>,
<option>check-at-most-once</option>, <option>panic-on-corruption</option> and
<option>check-at-most-once</option>, <option>panic-on-corruption</option>,
<option>hash=<replaceable>HASH</replaceable></option>, <option>fec-device=<replaceable>PATH</replaceable></option>,
<option>fec-offset=<replaceable>BYTES</replaceable></option>, <option>fec-roots=<replaceable>NUM</replaceable></option> and
<option>root-hash-signature=<replaceable>PATH</replaceable>|base64:<replaceable>HEX</replaceable></option>. See
<citerefentry project='die-net'><refentrytitle>veritysetup</refentrytitle><manvolnum>8</manvolnum></citerefentry> for more
details.</para></listitem>

View File

@ -60,6 +60,62 @@ This is based on crypttab(5).
<variablelist class='fstab-options'>
<varlistentry>
<term><option>superblock=<replaceable>BOOL</replaceable></option></term>
<listitem><para>Use dm-verity with or without permanent on-disk superblock.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>format=<replaceable>NUMBER</replaceable></option></term>
<listitem><para>Specifies the hash version type. Format type 0 is original Chrome OS version. Format type 1 is
modern version.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>data-block-size=<replaceable>BYTES</replaceable></option></term>
<listitem><para>Used block size for the data device. (Note kernel supports only page-size as maximum
here; Multiples of 512 bytes.) </para></listitem>
</varlistentry>
<varlistentry>
<term><option>hash-block-size=<replaceable>BYTES</replaceable></option></term>
<listitem><para>Used block size for the hash device. (Note kernel supports only page-size as maximum
here; Multiples of 512 bytes.)</para></listitem>
</varlistentry>
<varlistentry>
<term><option>data-blocks=<replaceable>BLOCKS</replaceable></option></term>
<listitem><para>Number of blocks of data device used in verification. If not specified, the whole device is
used.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>hash-offset=<replaceable>BYTES</replaceable></option></term>
<listitem><para>Offset of hash area/superblock on <literal>hash-device</literal>. (Multiples of 512 bytes.)
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>salt=<replaceable>HEX</replaceable></option></term>
<listitem><para>Salt used for format or verification. Format is a hexadecimal string; 256 bytes long maximum;
<literal>-</literal>is the special value for empty.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>uuid=<replaceable>UUID</replaceable></option></term>
<listitem><para>Use the provided UUID for format command instead of generating new one. The UUID must be
provided in standard UUID format, e.g. 12345678-1234-1234-1234-123456789abc.</para></listitem>
<listitem><para></para></listitem>
</varlistentry>
<varlistentry>
<term><option>ignore-corruption</option></term>
<term><option>restart-on-corruption</option></term>
@ -94,6 +150,37 @@ This is based on crypttab(5).
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>hash=<replaceable>HASH</replaceable></option></term>
<listitem><para>Hash algorithm for dm-verity. This should be the name of the algorithm, like "sha1". For default
see <command>veritysetup --help</command>.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>fec-device=<replaceable>PATH</replaceable></option></term>
<listitem><para>Use forward error correction (FEC) to recover from corruption if hash verification fails. Use
encoding data from the specified device. The fec device argument can be block device or file image. For format,
if fec device path doesn't exist, it will be created as file. Note: block sizes for data and hash devices must
match. Also, if the verity data_device is encrypted the fec_device should be too.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>fec-offset=<replaceable>BYTES</replaceable></option></term>
<listitem><para>This is the offset, in bytes, from the start of the FEC device to the beginning of the encoding
data. (Aligned on 512 bytes.)</para></listitem>
</varlistentry>
<varlistentry>
<term><option>fec-roots=<replaceable>NUM</replaceable></option></term>
<listitem><para>Number of generator roots. This equals to the number of parity bytes in the encoding data. In
RS(M, N) encoding, the number of roots is M-N. M is 255 and M-N is between 2 and 24 (including).</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>root-hash-signature=<replaceable>PATH</replaceable>|base64:<replaceable>HEX</replaceable></option></term>

View File

@ -7,18 +7,37 @@
#include "alloc-util.h"
#include "cryptsetup-util.h"
#include "fileio.h"
#include "fstab-util.h"
#include "hexdecoct.h"
#include "log.h"
#include "main-func.h"
#include "parse-util.h"
#include "path-util.h"
#include "pretty-print.h"
#include "process-util.h"
#include "string-util.h"
#include "terminal-util.h"
static char *arg_hash = NULL;
static bool arg_superblock = true;
static int arg_format = 1;
static uint64_t arg_data_block_size = 4096;
static uint64_t arg_hash_block_size = 4096;
static uint64_t arg_data_blocks = 0;
static uint64_t arg_hash_offset = 0;
static void *arg_salt = NULL;
static uint64_t arg_salt_size = 32;
static char *arg_uuid = NULL;
static uint32_t arg_activate_flags = CRYPT_ACTIVATE_READONLY;
static char *arg_fec_what = NULL;
static uint64_t arg_fec_offset = 0;
static uint64_t arg_fec_roots = 2;
static char *arg_root_hash_signature = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_hash, freep);
STATIC_DESTRUCTOR_REGISTER(arg_salt, freep);
STATIC_DESTRUCTOR_REGISTER(arg_uuid, freep);
STATIC_DESTRUCTOR_REGISTER(arg_fec_what, freep);
STATIC_DESTRUCTOR_REGISTER(arg_root_hash_signature, freep);
static int help(void) {
@ -62,6 +81,25 @@ static int save_roothashsig_option(const char *option, bool strict) {
"base64 string encoding signature prefixed by base64:.");
}
static int parse_block_size(const char *t, uint64_t *size) {
uint64_t u;
int r;
r = parse_size(t, 1024, &u);
if (r < 0)
return r;
if (u < 512 || u > (512 * 1024))
return -ERANGE;
if ((u % 512) != 0 || !ISPOWEROF2(u))
return -EINVAL;
*size = u;
return 0;
}
static int parse_options(const char *options) {
int r;
@ -104,7 +142,127 @@ static int parse_options(const char *options) {
else if (streq(word, "panic-on-corruption"))
arg_activate_flags |= CRYPT_ACTIVATE_PANIC_ON_CORRUPTION;
#endif
else if ((val = startswith(word, "root-hash-signature="))) {
else if ((val = startswith(word, "superblock="))) {
r = parse_boolean(val);
if (r < 0)
return log_error_errno(r, "Failed to parse boolean '%s': %m", word);
arg_superblock = r;
} else if ((val = startswith(word, "format="))) {
if (!STR_IN_SET(val, "0", "1"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "format= expects either 0 (original Chrome OS version) or "
"1 (modern version).");
arg_format = val[0] - '0';
} else if ((val = startswith(word, "data-block-size="))) {
uint64_t sz;
r = parse_block_size(val, &sz);
if (r < 0)
return log_error_errno(r, "Failed to parse size '%s': %m", word);
arg_data_block_size = sz;
} else if ((val = startswith(word, "hash-block-size="))) {
uint64_t sz;
r = parse_block_size(val, &sz);
if (r < 0)
return log_error_errno(r, "Failed to parse size '%s': %m", word);
arg_hash_block_size = sz;
} else if ((val = startswith(word, "data-blocks="))) {
uint64_t u;
r = safe_atou64(val, &u);
if (r < 0)
return log_error_errno(r, "Failed to parse number '%s': %m", word);
arg_data_blocks = u;
} else if ((val = startswith(word, "hash-offset="))) {
uint64_t off;
r = parse_size(val, 1024, &off);
if (r < 0)
return log_error_errno(r, "Failed to parse offset '%s': %m", word);
if (off % 512 != 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "hash-offset= expects a 512-byte aligned value.");
arg_hash_offset = off;
} else if ((val = startswith(word, "salt="))) {
if (!string_is_safe(val))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "salt= is not valid.");
if (isempty(val)) {
arg_salt = mfree(arg_salt);
arg_salt_size = 32;
} else if (streq(val, "-")) {
arg_salt = mfree(arg_salt);
arg_salt_size = 0;
} else {
size_t l;
void *m;
r = unhexmem(val, strlen(val), &m, &l);
if (r < 0)
return log_error_errno(r, "Failed to parse salt '%s': %m", word);
free_and_replace(arg_salt, m);
arg_salt_size = l;
}
} else if ((val = startswith(word, "uuid="))) {
r = sd_id128_from_string(val, NULL);
if (r < 0)
return log_error_errno(r, "Failed to parse UUID '%s': %m", word);
r = free_and_strdup(&arg_uuid, val);
if (r < 0)
return log_oom();
} else if ((val = startswith(word, "hash="))) {
r = free_and_strdup(&arg_hash, val);
if (r < 0)
return log_oom();
} else if ((val = startswith(word, "fec-device="))) {
_cleanup_free_ char *what = NULL;
what = fstab_node_to_udev_node(val);
if (!what)
return log_oom();
if (!path_is_absolute(what))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "fec-device= expects an absolute path.");
if (!path_is_normalized(what))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "fec-device= expects an normalized path.");
r = free_and_strdup(&arg_fec_what, what);
if (r < 0)
return log_oom();
} else if ((val = startswith(word, "fec-offset="))) {
uint64_t off;
r = parse_size(val, 1024, &off);
if (r < 0)
return log_error_errno(r, "Failed to parse offset '%s': %m", word);
if (off % 512 != 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "fec-offset= expects a 512-byte aligned value.");
arg_fec_offset = off;
} else if ((val = startswith(word, "fec-roots="))) {
uint64_t u;
r = safe_atou64(val, &u);
if (r < 0)
return log_error_errno(r, "Failed to parse number '%s', ignoring: %m", word);
if (u < 2 || u > 24)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "fec-rootfs= expects a value between 2 and 24 (including).");
arg_fec_roots = u;
} else if ((val = startswith(word, "root-hash-signature="))) {
r = save_roothashsig_option(val, /* strict= */ true);
if (r < 0)
return r;
@ -138,6 +296,7 @@ static int run(int argc, char *argv[]) {
if (streq(verb, "attach")) {
const char *volume, *data_device, *verity_device, *root_hash, *options;
_cleanup_free_ void *m = NULL;
struct crypt_params_verity p = {};
crypt_status_info status;
size_t l;
@ -175,9 +334,38 @@ static int run(int argc, char *argv[]) {
return log_error_errno(r, "Failed to parse options: %m");
}
r = crypt_load(cd, CRYPT_VERITY, NULL);
if (r < 0)
return log_error_errno(r, "Failed to load verity superblock: %m");
if (arg_superblock) {
p = (struct crypt_params_verity) {
.fec_device = arg_fec_what,
.hash_area_offset = arg_hash_offset,
.fec_area_offset = arg_fec_offset,
.fec_roots = arg_fec_roots,
};
r = crypt_load(cd, CRYPT_VERITY, &p);
if (r < 0)
return log_error_errno(r, "Failed to load verity superblock: %m");
} else {
p = (struct crypt_params_verity) {
.hash_name = arg_hash,
.data_device = data_device,
.fec_device = arg_fec_what,
.salt = arg_salt,
.salt_size = arg_salt_size,
.hash_type = arg_format,
.data_block_size = arg_data_block_size,
.hash_block_size = arg_hash_block_size,
.data_size = arg_data_blocks,
.hash_area_offset = arg_hash_offset,
.fec_area_offset = arg_fec_offset,
.fec_roots = arg_fec_roots,
.flags = CRYPT_VERITY_NO_HEADER,
};
r = crypt_format(cd, CRYPT_VERITY, NULL, NULL, arg_uuid, NULL, 0, &p);
if (r < 0)
return log_error_errno(r, "Failed to format verity superblock: %m");
}
r = crypt_set_data_device(cd, data_device);
if (r < 0)