diff --git a/man/systemd-veritysetup-generator.xml b/man/systemd-veritysetup-generator.xml
index 6098895f55..c591fcb24f 100644
--- a/man/systemd-veritysetup-generator.xml
+++ b/man/systemd-veritysetup-generator.xml
@@ -85,9 +85,16 @@
systemd.verity_root_options=
Takes a comma-separated list of dm-verity options. Expects the following options
- , ,
- , ,
- , and
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ , ,
+ , , ,
+ , ,
+ and
. See
veritysetup8 for more
details.
diff --git a/man/veritytab.xml b/man/veritytab.xml
index ec5d0f45a1..b4f2be3e30 100644
--- a/man/veritytab.xml
+++ b/man/veritytab.xml
@@ -60,6 +60,40 @@ This is based on crypttab(5).
+
+
+
+ Use dm-verity with or without permanent on-disk superblock.
+
+
+
+
+
+ Specifies the hash version type. Format type 0 is original Chrome OS version. Format type 1 is
+ modern version.
+
+
+
+
+
+ Used block size for the data device. (Note kernel supports only page-size as maximum
+ here; Multiples of 512 bytes.)
+
+
+
+
+
+ Used block size for the hash device. (Note kernel supports only page-size as maximum
+ here; Multiples of 512 bytes.)
+
+
+
+
+
+ Number of blocks of data device used in verification. If not specified, the whole device is
+ used.
+
+
@@ -67,6 +101,21 @@ This is based on crypttab(5).
+
+
+
+ Salt used for format or verification. Format is a hexadecimal string; 256 bytes long maximum;
+ -is the special value for empty.
+
+
+
+
+
+ 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.
+
+
+
@@ -101,6 +150,13 @@ This is based on crypttab(5).
+
+
+
+ Hash algorithm for dm-verity. This should be the name of the algorithm, like "sha1". For default
+ see veritysetup --help.
+
+
diff --git a/src/veritysetup/veritysetup.c b/src/veritysetup/veritysetup.c
index e1b0e00e42..120d8b619a 100644
--- a/src/veritysetup/veritysetup.c
+++ b/src/veritysetup/veritysetup.c
@@ -17,10 +17,22 @@
#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_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_root_hash_signature, freep);
static int help(void) {
@@ -64,6 +76,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;
@@ -106,7 +137,45 @@ 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, "hash-offset="))) {
+ 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);
@@ -116,6 +185,42 @@ static int parse_options(const char *options) {
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, "root-hash-signature="))) {
r = save_roothashsig_option(val, /* strict= */ true);
if (r < 0)
@@ -186,13 +291,34 @@ static int run(int argc, char *argv[]) {
r = parse_options(options);
if (r < 0)
return log_error_errno(r, "Failed to parse options: %m");
-
- p.hash_area_offset = arg_hash_offset;
}
- r = crypt_load(cd, CRYPT_VERITY, &p);
- if (r < 0)
- return log_error_errno(r, "Failed to load verity superblock: %m");
+ if (arg_superblock) {
+ p = (struct crypt_params_verity) {
+ .hash_area_offset = arg_hash_offset,
+ };
+
+ 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,
+ .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,
+ .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)