diff options
author | Gaël PORTAY <gael.portay@collabora.com> | 2020-12-23 16:10:15 +0100 |
---|---|---|
committer | Gaël PORTAY <gael.portay@rtone.fr> | 2023-04-13 05:15:20 +0200 |
commit | 0bbf7a842a3feb4952415d82d2b469f5c5d91836 (patch) | |
tree | cecb4cac208b48239f5bd24cf8b6b1bc5ac6112e /src/veritysetup | |
parent | veritysetup: add support for hash-offset option (diff) | |
download | systemd-0bbf7a842a3feb4952415d82d2b469f5c5d91836.tar.xz systemd-0bbf7a842a3feb4952415d82d2b469f5c5d91836.zip |
veritysetup: add support for superblock and underlying options
The verity parameter no_superblock allows to format/open an hash device
without the superblock. However, the superblock data must be set to open
the data-device.
This adds the option superblocks (sixth argument) and all the underlying
options which are implied to set the superblock manually if hash device
has no superblock:
- superblock=BOOL
- format=NUMBER (hash version type, 0 for original ChromeOS, 1 for
modern)
- data-block-size=BYTES (max page-size, multiple of 512)
- hash-block-size=BYTES (max page-size, multiple of 512)
- data-blocks=BLOCKS (size of data-device in blocks)
- salt=HEXSTR (salt used at format, max 256 bytes)
- uuid=UUID
- hash=STR (algorithm name for dm-verity used at format, default is
sha256)
See `veritysetup(8)` for more details.
Diffstat (limited to 'src/veritysetup')
-rw-r--r-- | src/veritysetup/veritysetup.c | 138 |
1 files changed, 132 insertions, 6 deletions
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) |