diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h index 912cf2d5..2197f2a0 100644 --- a/lib/libcryptsetup.h +++ b/lib/libcryptsetup.h @@ -1103,6 +1103,8 @@ int crypt_keyslot_destroy(struct crypt_device *cd, int keyslot); #define CRYPT_ACTIVATE_SUSPENDED (1 << 21) /** use IV sector counted in sector_size instead of default 512 bytes sectors */ #define CRYPT_ACTIVATE_IV_LARGE_SECTORS (1 << 22) +/** dm-verity: panic_on_corruption flag - panic kernel on corruption */ +#define CRYPT_ACTIVATE_PANIC_ON_CORRUPTION (1 << 23) /** * Active device runtime attributes diff --git a/lib/libdevmapper.c b/lib/libdevmapper.c index 0906bd72..9c943ffc 100644 --- a/lib/libdevmapper.c +++ b/lib/libdevmapper.c @@ -205,6 +205,9 @@ static void _dm_set_verity_compat(struct crypt_device *cd, if (_dm_satisfies_version(1, 5, 0, verity_maj, verity_min, verity_patch)) _dm_flags |= DM_VERITY_SIGNATURE_SUPPORTED; + if (_dm_satisfies_version(1, 7, 0, verity_maj, verity_min, verity_patch)) + _dm_flags |= DM_VERITY_PANIC_CORRUPTION_SUPPORTED; + _dm_verity_checked = true; } @@ -693,14 +696,19 @@ static char *get_dm_verity_params(const struct dm_target *tgt, uint32_t flags) vp = tgt->u.verity.vp; /* These flags are not compatible */ + if ((flags & CRYPT_ACTIVATE_RESTART_ON_CORRUPTION) && + (flags & CRYPT_ACTIVATE_PANIC_ON_CORRUPTION)) + flags &= ~CRYPT_ACTIVATE_RESTART_ON_CORRUPTION; if ((flags & CRYPT_ACTIVATE_IGNORE_CORRUPTION) && - (flags & CRYPT_ACTIVATE_RESTART_ON_CORRUPTION)) + (flags & (CRYPT_ACTIVATE_RESTART_ON_CORRUPTION|CRYPT_ACTIVATE_PANIC_ON_CORRUPTION))) flags &= ~CRYPT_ACTIVATE_IGNORE_CORRUPTION; if (flags & CRYPT_ACTIVATE_IGNORE_CORRUPTION) num_options++; if (flags & CRYPT_ACTIVATE_RESTART_ON_CORRUPTION) num_options++; + if (flags & CRYPT_ACTIVATE_PANIC_ON_CORRUPTION) + num_options++; if (flags & CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS) num_options++; if (flags & CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE) @@ -723,9 +731,10 @@ static char *get_dm_verity_params(const struct dm_target *tgt, uint32_t flags) *verity_verify_args = '\0'; if (num_options) - snprintf(features, sizeof(features)-1, " %d%s%s%s%s", num_options, + snprintf(features, sizeof(features)-1, " %d%s%s%s%s%s", num_options, (flags & CRYPT_ACTIVATE_IGNORE_CORRUPTION) ? " ignore_corruption" : "", (flags & CRYPT_ACTIVATE_RESTART_ON_CORRUPTION) ? " restart_on_corruption" : "", + (flags & CRYPT_ACTIVATE_PANIC_ON_CORRUPTION) ? " panic_on_corruption" : "", (flags & CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS) ? " ignore_zero_blocks" : "", (flags & CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE) ? " check_at_most_once" : ""); else @@ -1638,6 +1647,10 @@ int dm_create_device(struct crypt_device *cd, const char *name, !(dmt_flags & DM_VERITY_ON_CORRUPTION_SUPPORTED)) log_err(cd, _("Requested dm-verity data corruption handling options are not supported.")); + if (r == -EINVAL && dmd->flags & CRYPT_ACTIVATE_PANIC_ON_CORRUPTION && + !(dmt_flags & DM_VERITY_PANIC_CORRUPTION_SUPPORTED)) + log_err(cd, _("Requested dm-verity data corruption handling options are not supported.")); + if (r == -EINVAL && dmd->segment.type == DM_VERITY && dmd->segment.u.verity.fec_device && !(dmt_flags & DM_VERITY_FEC_SUPPORTED)) log_err(cd, _("Requested dm-verity FEC options are not supported.")); @@ -2178,6 +2191,8 @@ static int _dm_target_query_verity(struct crypt_device *cd, *act_flags |= CRYPT_ACTIVATE_IGNORE_CORRUPTION; else if (!strcasecmp(arg, "restart_on_corruption")) *act_flags |= CRYPT_ACTIVATE_RESTART_ON_CORRUPTION; + else if (!strcasecmp(arg, "panic_on_corruption")) + *act_flags |= CRYPT_ACTIVATE_PANIC_ON_CORRUPTION; else if (!strcasecmp(arg, "ignore_zero_blocks")) *act_flags |= CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS; else if (!strcasecmp(arg, "check_at_most_once")) diff --git a/lib/utils_dm.h b/lib/utils_dm.h index 1501eb59..d384f350 100644 --- a/lib/utils_dm.h +++ b/lib/utils_dm.h @@ -69,6 +69,7 @@ static inline uint32_t act2dmflags(uint32_t act_flags) #define DM_BITLK_ELEPHANT_SUPPORTED (1 << 21) /* Elephant diffuser for BITLK supported */ #define DM_VERITY_SIGNATURE_SUPPORTED (1 << 22) /* Verity option root_hash_sig_key_desc supported */ #define DM_INTEGRITY_DISCARDS_SUPPORTED (1 << 23) /* dm-integrity discards/TRIM option is supported */ +#define DM_VERITY_PANIC_CORRUPTION_SUPPORTED (1 << 24) /* dm-verity panic on corruption */ typedef enum { DM_CRYPT = 0, DM_VERITY, DM_INTEGRITY, DM_LINEAR, DM_ERROR, DM_ZERO, DM_UNKNOWN } dm_target_type; enum tdirection { TARGET_SET = 1, TARGET_QUERY }; diff --git a/man/veritysetup.8 b/man/veritysetup.8 index d907e1b6..d4d7aa42 100644 --- a/man/veritysetup.8 +++ b/man/veritysetup.8 @@ -40,8 +40,8 @@ Creates a mapping with backed by device and using The is a hexadecimal string. \fB\fR can be [\-\-hash-offset, \-\-no-superblock, -\-\-ignore-corruption or \-\-restart-on-corruption, \-\-ignore-zero-blocks, -\-\-check-at-most-once, \-\-root-hash-signature] +\-\-ignore-corruption or \-\-restart-on-corruption, \-\-panic-on-corruption, +\-\-ignore-zero-blocks, \-\-check-at-most-once, \-\-root-hash-signature] If option \-\-no-superblock is used, you have to use as the same options as in initial format operation. @@ -117,12 +117,13 @@ 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. .TP -.B "\-\-ignore-corruption", "\-\-restart-on-corruption" +.B "\-\-ignore-corruption", "\-\-restart-on-corruption", "\-\-panic-on-corruption" Defines what to do if data integrity problem is detected (data corruption). Without these options kernel fails the IO operation with I/O error. With \-\-ignore-corruption option the corruption is only logged. -With \-\-restart-on-corruption the kernel is restarted immediately. +With \-\-restart-on-corruption or \-\-panic-on-corruption the kernel +is restarted (panicked) immediately. (You have to provide way how to avoid restart loops.) \fBWARNING:\fR Use these options only for very specific cases. diff --git a/src/utils_arg_names.h b/src/utils_arg_names.h index e8172aaf..dd43beae 100644 --- a/src/utils_arg_names.h +++ b/src/utils_arg_names.h @@ -99,6 +99,7 @@ #define OPT_NEW_KEYFILE_OFFSET "new-keyfile-offset" #define OPT_NEW_KEYFILE_SIZE "new-keyfile-size" #define OPT_OFFSET "offset" +#define OPT_PANIC_ON_CORRUPTION "panic-on-corruption" #define OPT_PBKDF "pbkdf" #define OPT_PBKDF_FORCE_ITERATIONS "pbkdf-force-iterations" #define OPT_PBKDF_MEMORY "pbkdf-memory" diff --git a/src/veritysetup.c b/src/veritysetup.c index 0d1d5d93..5c431532 100644 --- a/src/veritysetup.c +++ b/src/veritysetup.c @@ -140,6 +140,8 @@ static int _activate(const char *dm_device, activate_flags |= CRYPT_ACTIVATE_IGNORE_CORRUPTION; if (ARG_SET(OPT_RESTART_ON_CORRUPTION_ID)) activate_flags |= CRYPT_ACTIVATE_RESTART_ON_CORRUPTION; + if (ARG_SET(OPT_PANIC_ON_CORRUPTION_ID)) + activate_flags |= CRYPT_ACTIVATE_PANIC_ON_CORRUPTION; if (ARG_SET(OPT_IGNORE_ZERO_BLOCKS_ID)) activate_flags |= CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS; if (ARG_SET(OPT_CHECK_AT_MOST_ONCE_ID)) @@ -336,11 +338,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" : ""); } @@ -539,6 +543,11 @@ int main(int argc, const char **argv) _("Option --ignore-corruption and --restart-on-corruption cannot be used together."), poptGetInvocationName(popt_context)); + if (ARG_SET(OPT_PANIC_ON_CORRUPTION_ID) && ARG_SET(OPT_RESTART_ON_CORRUPTION_ID)) + usage(popt_context, EXIT_FAILURE, + _("Option --panic-on-corruption and --restart-on-corruption cannot be used together."), + poptGetInvocationName(popt_context)); + if (ARG_SET(OPT_DEBUG_ID)) { ARG_SET(OPT_VERBOSE_ID) = true; crypt_set_debug_level(CRYPT_DEBUG_ALL); diff --git a/src/veritysetup_arg_list.h b/src/veritysetup_arg_list.h index 51ce0941..e49ce71c 100644 --- a/src/veritysetup_arg_list.h +++ b/src/veritysetup_arg_list.h @@ -49,6 +49,8 @@ ARG(OPT_IGNORE_ZERO_BLOCKS, '\0', POPT_ARG_NONE, N_("Do not verify zeroed blocks ARG(OPT_NO_SUPERBLOCK, '\0', POPT_ARG_NONE, N_("Do not use verity superblock"), NULL, CRYPT_ARG_BOOL, {}, {}) +ARG(OPT_PANIC_ON_CORRUPTION, '\0', POPT_ARG_NONE, N_("Panic kernel if corruption is detected"), NULL, CRYPT_ARG_BOOL, {}, OPT_PANIC_ON_CORRUPTION_ACTIONS) + ARG(OPT_RESTART_ON_CORRUPTION, '\0', POPT_ARG_NONE, N_("Restart kernel if corruption is detected"), NULL, CRYPT_ARG_BOOL, {}, OPT_RESTART_ON_CORRUPTION_ACTIONS) ARG(OPT_ROOT_HASH_SIGNATURE, '\0', POPT_ARG_STRING, N_("Path to root hash signature file"), NULL, CRYPT_ARG_STRING, {}, OPT_ROOT_HASH_SIGNATURE_ACTIONS) diff --git a/src/veritysetup_args.h b/src/veritysetup_args.h index 0220ba23..1a98960f 100644 --- a/src/veritysetup_args.h +++ b/src/veritysetup_args.h @@ -35,6 +35,7 @@ #define OPT_IGNORE_CORRUPTION_ACTIONS { OPEN_ACTION } #define OPT_IGNORE_ZERO_BLOCKS_ACTIONS { OPEN_ACTION } #define OPT_RESTART_ON_CORRUPTION_ACTIONS { OPEN_ACTION } +#define OPT_PANIC_ON_CORRUPTION_ACTIONS { OPEN_ACTION } #define OPT_ROOT_HASH_SIGNATURE_ACTIONS { OPEN_ACTION } enum { diff --git a/tests/verity-compat-test b/tests/verity-compat-test index d3bcdd99..2eedf77e 100755 --- a/tests/verity-compat-test +++ b/tests/verity-compat-test @@ -424,6 +424,9 @@ if check_version 1 3; then if check_version 1 4; then check_option 512 $HASH $SALT 1 sha256 "--check-at-most-once" "check_at_most_once" fi + if check_version 1 7; then + check_option 512 $HASH $SALT 1 sha256 "--panic-on-corruption" "panic_on_corruption" + fi fi echo "Veritysetup [hash-offset bigger than 2G works] "