/*
* veritysetup - setup cryptographic volumes for dm-verity
*
- * Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved.
- * Copyright (C) 2012-2020 Milan Broz
+ * Copyright (C) 2012-2021 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2012-2021 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
#define PACKAGE_VERITY "veritysetup"
-static int use_superblock = 1;
-
-static const char *fec_device = NULL;
-static int fec_roots = DEFAULT_VERITY_FEC_ROOTS;
-static const char *hash_algorithm = NULL;
-static int hash_type = 1;
-static int data_block_size = DEFAULT_VERITY_DATA_BLOCK;
-static int hash_block_size = DEFAULT_VERITY_HASH_BLOCK;
+static char *opt_fec_device = NULL;
+static char *opt_hash_algorithm = NULL;
+static char *opt_salt = NULL;
+static char *opt_uuid = NULL;
+static char *opt_root_hash_signature = NULL;
+
+static int opt_use_superblock = 1;
+static int opt_fec_roots = DEFAULT_VERITY_FEC_ROOTS;
+static int opt_hash_type = 1;
+static int opt_data_block_size = DEFAULT_VERITY_DATA_BLOCK;
+static int opt_hash_block_size = DEFAULT_VERITY_HASH_BLOCK;
static uint64_t data_blocks = 0;
-static const char *salt_string = NULL;
static uint64_t hash_offset = 0;
static uint64_t fec_offset = 0;
-static const char *opt_uuid = NULL;
static int opt_restart_on_corruption = 0;
+static int opt_panic_on_corruption = 0;
static int opt_ignore_corruption = 0;
static int opt_ignore_zero_blocks = 0;
static int opt_check_at_most_once = 0;
-static const char *opt_root_hash_signature = NULL;
static const char **action_argv;
static int action_argc;
+void tools_cleanup(void)
+{
+ FREE_AND_NULL(opt_fec_device);
+ FREE_AND_NULL(opt_hash_algorithm);
+ FREE_AND_NULL(opt_salt);
+ FREE_AND_NULL(opt_uuid);
+ FREE_AND_NULL(opt_root_hash_signature);
+}
+
static int _prepare_format(struct crypt_params_verity *params,
const char *data_device,
uint32_t flags)
char *salt = NULL;
int len;
- params->hash_name = hash_algorithm ?: DEFAULT_VERITY_HASH;
+ params->hash_name = opt_hash_algorithm ?: DEFAULT_VERITY_HASH;
params->data_device = data_device;
- params->fec_device = fec_device;
- params->fec_roots = fec_roots;
+ params->fec_device = opt_fec_device;
+ params->fec_roots = opt_fec_roots;
- if (salt_string && !strcmp(salt_string, "-")) {
+ if (opt_salt && !strcmp(opt_salt, "-")) {
params->salt_size = 0;
params->salt = NULL;
- } else if (salt_string) {
- len = crypt_hex_to_bytes(salt_string, &salt, 0);
+ } else if (opt_salt) {
+ len = crypt_hex_to_bytes(opt_salt, &salt, 0);
if (len < 0) {
log_err(_("Invalid salt string specified."));
return -EINVAL;
params->salt = NULL;
}
- params->data_block_size = data_block_size;
- params->hash_block_size = hash_block_size;
+ params->data_block_size = opt_data_block_size;
+ params->hash_block_size = opt_hash_block_size;
params->data_size = data_blocks;
params->hash_area_offset = hash_offset;
params->fec_area_offset = fec_offset;
- params->hash_type = hash_type;
+ params->hash_type = opt_hash_type;
params->flags = flags;
return 0;
close(r);
}
/* Try to create FEC image if doesn't exist */
- if (fec_device) {
- r = open(fec_device, O_WRONLY | O_EXCL | O_CREAT, S_IRUSR | S_IWUSR);
+ if (opt_fec_device) {
+ r = open(opt_fec_device, O_WRONLY | O_EXCL | O_CREAT, S_IRUSR | S_IWUSR);
if (r < 0 && errno != EEXIST) {
- log_err(_("Cannot create FEC image %s for writing."), fec_device);
+ log_err(_("Cannot create FEC image %s for writing."), opt_fec_device);
return -EINVAL;
} else if (r >= 0) {
- log_dbg("Created FEC image %s.", fec_device);
+ log_dbg("Created FEC image %s.", opt_fec_device);
close(r);
}
}
if ((r = crypt_init(&cd, action_argv[1])))
goto out;
- if (!use_superblock)
+ if (!opt_use_superblock)
flags |= CRYPT_VERITY_NO_HEADER;
r = _prepare_format(¶ms, action_argv[0], flags);
activate_flags |= CRYPT_ACTIVATE_IGNORE_CORRUPTION;
if (opt_restart_on_corruption)
activate_flags |= CRYPT_ACTIVATE_RESTART_ON_CORRUPTION;
+ if (opt_panic_on_corruption)
+ activate_flags |= CRYPT_ACTIVATE_PANIC_ON_CORRUPTION;
if (opt_ignore_zero_blocks)
activate_flags |= CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS;
if (opt_check_at_most_once)
activate_flags |= CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE;
- if (use_superblock) {
+ if (opt_use_superblock) {
params.flags = flags;
params.hash_area_offset = hash_offset;
params.fec_area_offset = fec_offset;
- params.fec_device = fec_device;
- params.fec_roots = fec_roots;
+ params.fec_device = opt_fec_device;
+ params.fec_roots = opt_fec_roots;
r = crypt_load(cd, CRYPT_VERITY, ¶ms);
} else {
r = _prepare_format(¶ms, data_device, flags | CRYPT_VERITY_NO_HEADER);
if (vp.fec_device) {
log_std(" FEC device: %s\n", vp.fec_device);
- if ((backing_file = crypt_loop_backing_file(vp.fec_device))) {
+ if ((backing_file = crypt_loop_backing_file(opt_fec_device))) {
log_std(" FEC loop: %s\n", backing_file);
free(backing_file);
}
if (cad.flags & (CRYPT_ACTIVATE_IGNORE_CORRUPTION|
CRYPT_ACTIVATE_RESTART_ON_CORRUPTION|
+ CRYPT_ACTIVATE_PANIC_ON_CORRUPTION|
CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS|
CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE))
- log_std(" flags: %s%s%s%s\n",
+ log_std(" flags: %s%s%s%s%s\n",
(cad.flags & CRYPT_ACTIVATE_IGNORE_CORRUPTION) ? "ignore_corruption " : "",
(cad.flags & CRYPT_ACTIVATE_RESTART_ON_CORRUPTION) ? "restart_on_corruption " : "",
+ (cad.flags & CRYPT_ACTIVATE_PANIC_ON_CORRUPTION) ? "panic_on_corruption " : "",
(cad.flags & CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS) ? "ignore_zero_blocks " : "",
(cad.flags & CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE) ? "check_at_most_once" : "");
}
DEFAULT_VERITY_HASH, DEFAULT_VERITY_DATA_BLOCK,
DEFAULT_VERITY_HASH_BLOCK, DEFAULT_VERITY_SALT_SIZE,
1);
+ tools_cleanup();
poptFreeContext(popt_context);
exit(EXIT_SUCCESS);
} else if (key->shortName == 'V') {
log_std("%s %s\n", PACKAGE_VERITY, PACKAGE_VERSION);
+ tools_cleanup();
poptFreeContext(popt_context);
exit(EXIT_SUCCESS);
} else
int main(int argc, const char **argv)
{
- static char *popt_tmp;
static const char *null_action_argv[] = {NULL};
static struct poptOption popt_help_options[] = {
{ NULL, '\0', POPT_ARG_CALLBACK, help, 0, NULL, NULL },
{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, popt_help_options, 0, N_("Help options:"), NULL },
{ "verbose", 'v', POPT_ARG_NONE, &opt_verbose, 0, N_("Shows more detailed error messages"), NULL },
{ "debug", '\0', POPT_ARG_NONE, &opt_debug, 0, N_("Show debug messages"), NULL },
- { "no-superblock", 0, POPT_ARG_VAL, &use_superblock, 0, N_("Do not use verity superblock"), NULL },
- { "format", 0, POPT_ARG_INT, &hash_type, 0, N_("Format type (1 - normal, 0 - original Chrome OS)"), N_("number") },
- { "data-block-size", 0, POPT_ARG_INT, &data_block_size, 0, N_("Block size on the data device"), N_("bytes") },
- { "hash-block-size", 0, POPT_ARG_INT, &hash_block_size, 0, N_("Block size on the hash device"), N_("bytes") },
- { "fec-roots", 0, POPT_ARG_INT, &fec_roots, 0, N_("FEC parity bytes"), N_("bytes") },
- { "data-blocks", 0, POPT_ARG_STRING, &popt_tmp, 1, N_("The number of blocks in the data file"), N_("blocks") },
- { "fec-device", 0, POPT_ARG_STRING, &fec_device, 0, N_("Path to device with error correction data"), N_("path") },
- { "hash-offset", 0, POPT_ARG_STRING, &popt_tmp, 2, N_("Starting offset on the hash device"), N_("bytes") },
- { "fec-offset", 0, POPT_ARG_STRING, &popt_tmp, 3, N_("Starting offset on the FEC device"), N_("bytes") },
- { "hash", 'h', POPT_ARG_STRING, &hash_algorithm, 0, N_("Hash algorithm"), N_("string") },
- { "salt", 's', POPT_ARG_STRING, &salt_string, 0, N_("Salt"), N_("hex string") },
+ { "no-superblock", 0, POPT_ARG_VAL, &opt_use_superblock, 0, N_("Do not use verity superblock"), NULL },
+ { "format", 0, POPT_ARG_INT, &opt_hash_type, 0, N_("Format type (1 - normal, 0 - original Chrome OS)"), N_("number") },
+ { "data-block-size", 0, POPT_ARG_INT, &opt_data_block_size, 0, N_("Block size on the data device"), N_("bytes") },
+ { "hash-block-size", 0, POPT_ARG_INT, &opt_hash_block_size, 0, N_("Block size on the hash device"), N_("bytes") },
+ { "fec-roots", 0, POPT_ARG_INT, &opt_fec_roots, 0, N_("FEC parity bytes"), N_("bytes") },
+ { "data-blocks", 0, POPT_ARG_STRING, NULL, 1, N_("The number of blocks in the data file"), N_("blocks") },
+ { "fec-device", 0, POPT_ARG_STRING, &opt_fec_device, 0, N_("Path to device with error correction data"), N_("path") },
+ { "hash-offset", 0, POPT_ARG_STRING, NULL, 2, N_("Starting offset on the hash device"), N_("bytes") },
+ { "fec-offset", 0, POPT_ARG_STRING, NULL, 3, N_("Starting offset on the FEC device"), N_("bytes") },
+ { "hash", 'h', POPT_ARG_STRING, &opt_hash_algorithm, 0, N_("Hash algorithm"), N_("string") },
+ { "salt", 's', POPT_ARG_STRING, &opt_salt, 0, N_("Salt"), N_("hex string") },
{ "uuid", '\0', POPT_ARG_STRING, &opt_uuid, 0, N_("UUID for device to use"), NULL },
{ "root-hash-signature",'\0', POPT_ARG_STRING, &opt_root_hash_signature, 0, N_("Path to root hash signature file"), NULL },
{ "restart-on-corruption", 0,POPT_ARG_NONE,&opt_restart_on_corruption, 0, N_("Restart kernel if corruption is detected"), NULL },
+ { "panic-on-corruption", 0,POPT_ARG_NONE, &opt_panic_on_corruption, 0, N_("Panic kernel if corruption is detected"), NULL },
{ "ignore-corruption", 0, POPT_ARG_NONE, &opt_ignore_corruption, 0, N_("Ignore corruption, log it only"), NULL },
{ "ignore-zero-blocks", 0, POPT_ARG_NONE, &opt_ignore_zero_blocks, 0, N_("Do not verify zeroed blocks"), NULL },
{ "check-at-most-once", 0, POPT_ARG_NONE, &opt_check_at_most_once, 0, N_("Verify data block only the first time it is read"), NULL },
while((r = poptGetNextOpt(popt_context)) > 0) {
unsigned long long ull_value;
- char *endp;
+ char *endp, *str = poptGetOptArg(popt_context);
errno = 0;
- ull_value = strtoull(popt_tmp, &endp, 10);
- if (*endp || !*popt_tmp || !isdigit(*popt_tmp) ||
+ ull_value = strtoull(str, &endp, 10);
+ if (*endp || !*str || !isdigit(*str) ||
(errno == ERANGE && ull_value == ULLONG_MAX) ||
(errno != 0 && ull_value == 0))
r = POPT_ERROR_BADNUMBER;
+ free(str);
+
switch(r) {
case 1:
data_blocks = ull_value;
poptGetInvocationName(popt_context));
}
- if (data_block_size < 0 || hash_block_size < 0 || hash_type < 0) {
+ if (opt_data_block_size < 0 || opt_hash_block_size < 0 || opt_hash_type < 0) {
usage(popt_context, EXIT_FAILURE,
_("Negative number for option not permitted."),
poptGetInvocationName(popt_context));
_("Option --ignore-corruption and --restart-on-corruption cannot be used together."),
poptGetInvocationName(popt_context));
+ if (opt_panic_on_corruption && opt_restart_on_corruption)
+ usage(popt_context, EXIT_FAILURE,
+ _("Option --panic-on-corruption and --restart-on-corruption cannot be used together."),
+ poptGetInvocationName(popt_context));
+
if (opt_debug) {
opt_verbose = 1;
crypt_set_debug_level(-1);
}
r = run_action(action);
+ tools_cleanup();
poptFreeContext(popt_context);
return r;
}