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:
commit
796da645a0
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user