Merge "Merge branch 'upstream' into tizen" into tizen
[platform/upstream/cryptsetup.git] / src / veritysetup.c
index e29b75d..fc32cca 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * 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)
@@ -52,16 +62,16 @@ static int _prepare_format(struct crypt_params_verity *params,
        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;
@@ -73,12 +83,12 @@ static int _prepare_format(struct crypt_params_verity *params,
                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;
@@ -101,13 +111,13 @@ static int action_format(int arg)
                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);
                }
        }
@@ -115,7 +125,7 @@ static int action_format(int arg)
        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(&params, action_argv[0], flags);
@@ -153,17 +163,19 @@ static int _activate(const char *dm_device,
                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, &params);
        } else {
                r = _prepare_format(&params, data_device, flags | CRYPT_VERITY_NO_HEADER);
@@ -326,7 +338,7 @@ static int action_status(int arg)
 
                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);
                        }
@@ -349,11 +361,13 @@ static int action_status(int arg)
 
                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" : "");
        }
@@ -426,10 +440,12 @@ static void help(poptContext popt_context,
                        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
@@ -450,7 +466,6 @@ static int run_action(struct action_type *action)
 
 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 },
@@ -463,20 +478,21 @@ int main(int argc, const char **argv)
                { 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 },
@@ -500,15 +516,17 @@ int main(int argc, const char **argv)
 
        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;
@@ -571,7 +589,7 @@ int main(int argc, const char **argv)
                      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));
@@ -592,6 +610,11 @@ int main(int argc, const char **argv)
                _("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);
@@ -599,6 +622,7 @@ int main(int argc, const char **argv)
        }
 
        r = run_action(action);
+       tools_cleanup();
        poptFreeContext(popt_context);
        return r;
 }