X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=lib%2Fverity%2Fverity.c;h=af31784d6984f1ef790270fd9dd1e7936314a459;hb=322b430a2589cdc7985e98a14ec12322b91c9d5e;hp=5108e9e3dcbcf62d75f65bf427fa2b79e0aae2e3;hpb=ad21d48762fa70838d4ab4fbe8fe2a2e8a4dcef1;p=platform%2Fupstream%2Fcryptsetup.git diff --git a/lib/verity/verity.c b/lib/verity/verity.c index 5108e9e..af31784 100644 --- a/lib/verity/verity.c +++ b/lib/verity/verity.c @@ -1,7 +1,7 @@ /* * dm-verity volume handling * - * Copyright (C) 2012, Red Hat, Inc. All rights reserved. + * Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved. * * This file is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,7 +25,6 @@ #include #include #include -#include #include #include @@ -58,52 +57,49 @@ int VERITY_read_sb(struct crypt_device *cd, struct crypt_params_verity *params) { struct device *device = crypt_metadata_device(cd); - int bsize = device_block_size(device); struct verity_sb sb = {}; ssize_t hdr_size = sizeof(struct verity_sb); - int devfd = 0, sb_version; + int devfd, sb_version; - log_dbg("Reading VERITY header of size %zu on device %s, offset %" PRIu64 ".", + log_dbg(cd, "Reading VERITY header of size %zu on device %s, offset %" PRIu64 ".", sizeof(struct verity_sb), device_path(device), sb_offset); if (params->flags & CRYPT_VERITY_NO_HEADER) { - log_err(cd, _("Verity device %s doesn't use on-disk header.\n"), + log_err(cd, _("Verity device %s does not use on-disk header."), device_path(device)); return -EINVAL; } - if (sb_offset % 512) { - log_err(cd, _("Unsupported VERITY hash offset.\n")); + if (MISALIGNED_512(sb_offset)) { + log_err(cd, _("Unsupported VERITY hash offset.")); return -EINVAL; } - devfd = device_open(device, O_RDONLY); - if(devfd == -1) { - log_err(cd, _("Cannot open device %s.\n"), device_path(device)); + devfd = device_open(cd, device, O_RDONLY); + if (devfd < 0) { + log_err(cd, _("Cannot open device %s."), device_path(device)); return -EINVAL; } - if(lseek(devfd, sb_offset, SEEK_SET) < 0 || - read_blockwise(devfd, bsize, &sb, hdr_size) < hdr_size) { - close(devfd); + if (read_lseek_blockwise(devfd, device_block_size(cd, device), + device_alignment(device), &sb, hdr_size, + sb_offset) < hdr_size) return -EIO; - } - close(devfd); if (memcmp(sb.signature, VERITY_SIGNATURE, sizeof(sb.signature))) { - log_err(cd, _("Device %s is not a valid VERITY device.\n"), + log_err(cd, _("Device %s is not a valid VERITY device."), device_path(device)); return -EINVAL; } sb_version = le32_to_cpu(sb.version); if (sb_version != 1) { - log_err(cd, _("Unsupported VERITY version %d.\n"), sb_version); + log_err(cd, _("Unsupported VERITY version %d."), sb_version); return -EINVAL; } params->hash_type = le32_to_cpu(sb.hash_type); if (params->hash_type > VERITY_MAX_HASH_TYPE) { - log_err(cd, _("Unsupported VERITY hash type %d.\n"), params->hash_type); + log_err(cd, _("Unsupported VERITY hash type %d."), params->hash_type); return -EINVAL; } @@ -111,7 +107,7 @@ int VERITY_read_sb(struct crypt_device *cd, params->hash_block_size = le32_to_cpu(sb.hash_block_size); if (VERITY_BLOCK_SIZE_OK(params->data_block_size) || VERITY_BLOCK_SIZE_OK(params->hash_block_size)) { - log_err(cd, _("Unsupported VERITY block size.\n")); + log_err(cd, _("Unsupported VERITY block size.")); return -EINVAL; } params->data_size = le64_to_cpu(sb.data_blocks); @@ -120,21 +116,24 @@ int VERITY_read_sb(struct crypt_device *cd, if (!params->hash_name) return -ENOMEM; if (crypt_hash_size(params->hash_name) <= 0) { - log_err(cd, _("Hash algorithm %s not supported.\n"), + log_err(cd, _("Hash algorithm %s not supported."), params->hash_name); free(CONST_CAST(char*)params->hash_name); + params->hash_name = NULL; return -EINVAL; } params->salt_size = le16_to_cpu(sb.salt_size); if (params->salt_size > sizeof(sb.salt)) { - log_err(cd, _("VERITY header corrupted.\n")); + log_err(cd, _("VERITY header corrupted.")); free(CONST_CAST(char*)params->hash_name); + params->hash_name = NULL; return -EINVAL; } params->salt = malloc(params->salt_size); if (!params->salt) { free(CONST_CAST(char*)params->hash_name); + params->hash_name = NULL; return -ENOMEM; } memcpy(CONST_CAST(char*)params->salt, sb.salt, params->salt_size); @@ -153,30 +152,30 @@ int VERITY_write_sb(struct crypt_device *cd, struct crypt_params_verity *params) { struct device *device = crypt_metadata_device(cd); - int bsize = device_block_size(device); struct verity_sb sb = {}; ssize_t hdr_size = sizeof(struct verity_sb); + char *algorithm; uuid_t uuid; - int r, devfd = 0; + int r, devfd; - log_dbg("Updating VERITY header of size %zu on device %s, offset %" PRIu64 ".", + log_dbg(cd, "Updating VERITY header of size %zu on device %s, offset %" PRIu64 ".", sizeof(struct verity_sb), device_path(device), sb_offset); if (!uuid_string || uuid_parse(uuid_string, uuid) == -1) { - log_err(cd, _("Wrong VERITY UUID format provided on device %s.\n"), + log_err(cd, _("Wrong VERITY UUID format provided on device %s."), device_path(device)); return -EINVAL; } if (params->flags & CRYPT_VERITY_NO_HEADER) { - log_err(cd, _("Verity device %s doesn't use on-disk header.\n"), + log_err(cd, _("Verity device %s does not use on-disk header."), device_path(device)); return -EINVAL; } - devfd = device_open(device, O_RDWR); - if(devfd == -1) { - log_err(cd, _("Cannot open device %s.\n"), device_path(device)); + devfd = device_open(cd, device, O_RDWR); + if (devfd < 0) { + log_err(cd, _("Cannot open device %s."), device_path(device)); return -EINVAL; } @@ -187,15 +186,19 @@ int VERITY_write_sb(struct crypt_device *cd, sb.hash_block_size = cpu_to_le32(params->hash_block_size); sb.salt_size = cpu_to_le16(params->salt_size); sb.data_blocks = cpu_to_le64(params->data_size); - strncpy((char *)sb.algorithm, params->hash_name, sizeof(sb.algorithm)); + algorithm = (char *)sb.algorithm; + algorithm[sizeof(sb.algorithm)-1] = '\0'; + strncpy(algorithm, params->hash_name, sizeof(sb.algorithm)-1); memcpy(sb.salt, params->salt, params->salt_size); memcpy(sb.uuid, uuid, sizeof(sb.uuid)); - r = write_lseek_blockwise(devfd, bsize, (char*)&sb, hdr_size, sb_offset) < hdr_size ? -EIO : 0; + r = write_lseek_blockwise(devfd, device_block_size(cd, device), device_alignment(device), + (char*)&sb, hdr_size, sb_offset) < hdr_size ? -EIO : 0; if (r) - log_err(cd, _("Error during update of verity header on device %s.\n"), + log_err(cd, _("Error during update of verity header on device %s."), device_path(device)); - close(devfd); + + device_sync(cd, device); return r; } @@ -218,7 +221,8 @@ int VERITY_UUID_generate(struct crypt_device *cd, char **uuid_string) { uuid_t uuid; - if (!(*uuid_string = malloc(40))) + *uuid_string = malloc(40); + if (!*uuid_string) return -ENOMEM; uuid_generate(uuid); uuid_unparse(uuid, *uuid_string); @@ -230,19 +234,42 @@ int VERITY_activate(struct crypt_device *cd, const char *name, const char *root_hash, size_t root_hash_size, + const char *signature_description, + struct device *fec_device, struct crypt_params_verity *verity_hdr, uint32_t activation_flags) { - struct crypt_dm_active_device dmd; + uint32_t dmv_flags; + unsigned int fec_errors = 0; int r; + struct crypt_dm_active_device dmd = { + .size = verity_hdr->data_size * verity_hdr->data_block_size / 512, + .flags = activation_flags, + .uuid = crypt_get_uuid(cd), + }; - log_dbg("Trying to activate VERITY device %s using hash %s.", + log_dbg(cd, "Trying to activate VERITY device %s using hash %s.", name ?: "[none]", verity_hdr->hash_name); if (verity_hdr->flags & CRYPT_VERITY_CHECK_HASH) { - log_dbg("Verification of data in userspace required."); - r = VERITY_verify(cd, verity_hdr, - root_hash, root_hash_size); + if (signature_description) { + log_err(cd, _("Root hash signature verification is not supported.")); + return -EINVAL; + } + + log_dbg(cd, "Verification of data in userspace required."); + r = VERITY_verify(cd, verity_hdr, root_hash, root_hash_size); + + if (r == -EPERM && fec_device) { + log_dbg(cd, "Verification failed, trying to repair with FEC device."); + r = VERITY_FEC_process(cd, verity_hdr, fec_device, 1, &fec_errors); + if (r < 0) + log_err(cd, _("Errors cannot be repaired with FEC device.")); + else if (fec_errors) + log_err(cd, _("Found %u repairable errors with FEC device."), + fec_errors); + } + if (r < 0) return r; } @@ -250,40 +277,53 @@ int VERITY_activate(struct crypt_device *cd, if (!name) return 0; - dmd.target = DM_VERITY; - dmd.data_device = crypt_data_device(cd); - dmd.u.verity.hash_device = crypt_metadata_device(cd); - dmd.u.verity.root_hash = root_hash; - dmd.u.verity.root_hash_size = root_hash_size; - dmd.u.verity.hash_offset = VERITY_hash_offset_block(verity_hdr), - dmd.flags = activation_flags; - dmd.size = verity_hdr->data_size * verity_hdr->data_block_size / 512; - dmd.uuid = crypt_get_uuid(cd); - dmd.u.verity.vp = verity_hdr; - - r = device_block_adjust(cd, dmd.u.verity.hash_device, DEV_OK, + r = device_block_adjust(cd, crypt_metadata_device(cd), DEV_OK, 0, NULL, NULL); if (r) return r; - r = device_block_adjust(cd, dmd.data_device, DEV_EXCL, + r = device_block_adjust(cd, crypt_data_device(cd), DEV_EXCL, 0, &dmd.size, &dmd.flags); if (r) return r; - r = dm_create_device(cd, name, CRYPT_VERITY, &dmd, 0); - if (r < 0 && !(dm_flags() & DM_VERITY_SUPPORTED)) { - log_err(cd, _("Kernel doesn't support dm-verity mapping.\n")); - return -ENOTSUP; + if (fec_device) { + r = device_block_adjust(cd, fec_device, DEV_OK, + 0, NULL, NULL); + if (r) + return r; } - if (r < 0) + + r = dm_verity_target_set(&dmd.segment, 0, dmd.size, crypt_data_device(cd), + crypt_metadata_device(cd), fec_device, root_hash, + root_hash_size, signature_description, + VERITY_hash_offset_block(verity_hdr), + VERITY_hash_blocks(cd, verity_hdr), verity_hdr); + + if (r) return r; + r = dm_create_device(cd, name, CRYPT_VERITY, &dmd); + if (r < 0 && (dm_flags(cd, DM_VERITY, &dmv_flags) || !(dmv_flags & DM_VERITY_SUPPORTED))) { + log_err(cd, _("Kernel does not support dm-verity mapping.")); + r = -ENOTSUP; + } + if (r < 0 && signature_description && !(dmv_flags & DM_VERITY_SIGNATURE_SUPPORTED)) { + log_err(cd, _("Kernel does not support dm-verity signature option.")); + r = -ENOTSUP; + } + if (r < 0) + goto out; + r = dm_status_verity_ok(cd, name); if (r < 0) - return r; + goto out; if (!r) - log_err(cd, _("Verity device detected corruption after activation.\n")); - return 0; + log_err(cd, _("Verity device detected corruption after activation.")); + + r = 0; +out: + dm_targets_free(cd, &dmd); + return r; }