2 * Integrity volume handling
4 * Copyright (C) 2016-2021 Milan Broz
6 * This file is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This file is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this file; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include <uuid/uuid.h>
27 #include "integrity.h"
30 static int INTEGRITY_read_superblock(struct crypt_device *cd,
31 struct device *device,
32 uint64_t offset, struct superblock *sb)
36 devfd = device_open(cd, device, O_RDONLY);
40 if (read_lseek_blockwise(devfd, device_block_size(cd, device),
41 device_alignment(device), sb, sizeof(*sb), offset) != sizeof(*sb) ||
42 memcmp(sb->magic, SB_MAGIC, sizeof(sb->magic)) ||
43 sb->version < SB_VERSION_1 || sb->version > SB_VERSION_5) {
44 log_std(cd, "No integrity superblock detected on %s.\n",
48 sb->integrity_tag_size = le16toh(sb->integrity_tag_size);
49 sb->journal_sections = le32toh(sb->journal_sections);
50 sb->provided_data_sectors = le64toh(sb->provided_data_sectors);
51 sb->recalc_sector = le64toh(sb->recalc_sector);
52 sb->flags = le32toh(sb->flags);
59 int INTEGRITY_read_sb(struct crypt_device *cd,
60 struct crypt_params_integrity *params,
66 r = INTEGRITY_read_superblock(cd, crypt_metadata_device(cd), 0, &sb);
70 params->sector_size = SECTOR_SIZE << sb.log2_sectors_per_block;
71 params->tag_size = sb.integrity_tag_size;
79 int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offset)
84 r = INTEGRITY_read_superblock(cd, device, offset, &sb);
88 log_std(cd, "Info for integrity device %s.\n", device_path(device));
89 log_std(cd, "superblock_version %d\n", (unsigned)sb.version);
90 log_std(cd, "log2_interleave_sectors %d\n", sb.log2_interleave_sectors);
91 log_std(cd, "integrity_tag_size %u\n", sb.integrity_tag_size);
92 log_std(cd, "journal_sections %u\n", sb.journal_sections);
93 log_std(cd, "provided_data_sectors %" PRIu64 "\n", sb.provided_data_sectors);
94 log_std(cd, "sector_size %u\n", SECTOR_SIZE << sb.log2_sectors_per_block);
95 if (sb.version >= SB_VERSION_2 && (sb.flags & SB_FLAG_RECALCULATING))
96 log_std(cd, "recalc_sector %" PRIu64 "\n", sb.recalc_sector);
97 log_std(cd, "log2_blocks_per_bitmap %u\n", sb.log2_blocks_per_bitmap_bit);
98 log_std(cd, "flags %s%s%s%s%s\n",
99 sb.flags & SB_FLAG_HAVE_JOURNAL_MAC ? "have_journal_mac " : "",
100 sb.flags & SB_FLAG_RECALCULATING ? "recalculating " : "",
101 sb.flags & SB_FLAG_DIRTY_BITMAP ? "dirty_bitmap " : "",
102 sb.flags & SB_FLAG_FIXED_PADDING ? "fix_padding " : "",
103 sb.flags & SB_FLAG_FIXED_HMAC ? "fix_hmac " : "");
108 int INTEGRITY_data_sectors(struct crypt_device *cd,
109 struct device *device, uint64_t offset,
110 uint64_t *data_sectors)
112 struct superblock sb;
115 r = INTEGRITY_read_superblock(cd, device, offset, &sb);
119 *data_sectors = sb.provided_data_sectors;
123 int INTEGRITY_key_size(struct crypt_device *cd, const char *integrity)
128 //FIXME: use crypto backend hash size
129 if (!strcmp(integrity, "aead"))
131 else if (!strcmp(integrity, "hmac(sha1)"))
133 else if (!strcmp(integrity, "hmac(sha256)"))
135 else if (!strcmp(integrity, "hmac(sha512)"))
137 else if (!strcmp(integrity, "poly1305"))
139 else if (!strcmp(integrity, "none"))
145 /* Return hash or hmac(hash) size, if known */
146 int INTEGRITY_hash_tag_size(const char *integrity)
148 char hash[MAX_CIPHER_LEN];
154 if (!strcmp(integrity, "crc32") || !strcmp(integrity, "crc32c"))
157 r = sscanf(integrity, "hmac(%" MAX_CIPHER_LEN_STR "[^)]s", hash);
159 r = crypt_hash_size(hash);
161 r = crypt_hash_size(integrity);
163 return r < 0 ? 0 : r;
166 int INTEGRITY_tag_size(struct crypt_device *cd,
167 const char *integrity,
169 const char *cipher_mode)
171 int iv_tag_size = 0, auth_tag_size = 0;
175 else if (!strcmp(cipher_mode, "xts-random"))
177 else if (!strcmp(cipher_mode, "gcm-random"))
179 else if (!strcmp(cipher_mode, "ccm-random"))
181 else if (!strcmp(cipher_mode, "ctr-random"))
183 else if (!strcmp(cipher, "aegis256") && !strcmp(cipher_mode, "random"))
185 else if (!strcmp(cipher_mode, "random"))
188 //FIXME: use crypto backend hash size
189 if (!integrity || !strcmp(integrity, "none"))
191 else if (!strcmp(integrity, "aead"))
192 auth_tag_size = 16; //FIXME gcm- mode only
193 else if (!strcmp(integrity, "cmac(aes)"))
195 else if (!strcmp(integrity, "hmac(sha1)"))
197 else if (!strcmp(integrity, "hmac(sha256)"))
199 else if (!strcmp(integrity, "hmac(sha512)"))
201 else if (!strcmp(integrity, "poly1305")) {
207 return iv_tag_size + auth_tag_size;
210 int INTEGRITY_create_dmd_device(struct crypt_device *cd,
211 const struct crypt_params_integrity *params,
212 struct volume_key *vk,
213 struct volume_key *journal_crypt_key,
214 struct volume_key *journal_mac_key,
215 struct crypt_dm_active_device *dmd,
216 uint32_t flags, uint32_t sb_flags)
223 *dmd = (struct crypt_dm_active_device) {
227 /* Workaround for kernel dm-integrity table bug */
228 if (sb_flags & SB_FLAG_RECALCULATING)
229 dmd->flags |= CRYPT_ACTIVATE_RECALCULATE;
231 r = INTEGRITY_data_sectors(cd, crypt_metadata_device(cd),
232 crypt_get_data_offset(cd) * SECTOR_SIZE, &dmd->size);
236 return dm_integrity_target_set(cd, &dmd->segment, 0, dmd->size,
237 crypt_metadata_device(cd), crypt_data_device(cd),
238 crypt_get_integrity_tag_size(cd), crypt_get_data_offset(cd),
239 crypt_get_sector_size(cd), vk, journal_crypt_key,
240 journal_mac_key, params);
243 int INTEGRITY_activate_dmd_device(struct crypt_device *cd,
246 struct crypt_dm_active_device *dmd,
251 struct dm_target *tgt = &dmd->segment;
253 if (!single_segment(dmd) || tgt->type != DM_INTEGRITY)
256 log_dbg(cd, "Trying to activate INTEGRITY device on top of %s, using name %s, tag size %d, provided sectors %" PRIu64".",
257 device_path(tgt->data_device), name, tgt->u.integrity.tag_size, dmd->size);
259 r = device_block_adjust(cd, tgt->data_device, DEV_EXCL,
260 tgt->u.integrity.offset, NULL, &dmd->flags);
264 if (tgt->u.integrity.meta_device) {
265 r = device_block_adjust(cd, tgt->u.integrity.meta_device, DEV_EXCL, 0, NULL, NULL);
270 r = dm_create_device(cd, name, type, dmd);
271 if (r < 0 && (dm_flags(cd, DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
272 log_err(cd, _("Kernel does not support dm-integrity mapping."));
276 if (r < 0 && (sb_flags & SB_FLAG_FIXED_PADDING) && !dm_flags(cd, DM_INTEGRITY, &dmi_flags) &&
277 !(dmi_flags & DM_INTEGRITY_FIX_PADDING_SUPPORTED)) {
278 log_err(cd, _("Kernel does not support dm-integrity fixed metadata alignment."));
282 if (r < 0 && (dmd->flags & CRYPT_ACTIVATE_RECALCULATE) &&
283 !(crypt_get_compatibility(cd) & CRYPT_COMPAT_LEGACY_INTEGRITY_RECALC) &&
284 ((sb_flags & SB_FLAG_FIXED_HMAC) ?
285 (tgt->u.integrity.vk && !tgt->u.integrity.journal_integrity_key) :
286 (tgt->u.integrity.vk || tgt->u.integrity.journal_integrity_key))) {
287 log_err(cd, _("Kernel refuses to activate insecure recalculate option (see legacy activation options to override)."));
294 int INTEGRITY_activate(struct crypt_device *cd,
296 const struct crypt_params_integrity *params,
297 struct volume_key *vk,
298 struct volume_key *journal_crypt_key,
299 struct volume_key *journal_mac_key,
300 uint32_t flags, uint32_t sb_flags)
302 struct crypt_dm_active_device dmd = {};
303 int r = INTEGRITY_create_dmd_device(cd, params, vk, journal_crypt_key,
304 journal_mac_key, &dmd, flags, sb_flags);
309 r = INTEGRITY_activate_dmd_device(cd, name, CRYPT_INTEGRITY, &dmd, sb_flags);
310 dm_targets_free(cd, &dmd);
314 int INTEGRITY_format(struct crypt_device *cd,
315 const struct crypt_params_integrity *params,
316 struct volume_key *journal_crypt_key,
317 struct volume_key *journal_mac_key)
320 char tmp_name[64], tmp_uuid[40];
321 struct crypt_dm_active_device dmdi = {
323 .flags = CRYPT_ACTIVATE_PRIVATE, /* We always create journal but it can be unused later */
325 struct dm_target *tgt = &dmdi.segment;
328 struct volume_key *vk = NULL;
330 uuid_generate(tmp_uuid_bin);
331 uuid_unparse(tmp_uuid_bin, tmp_uuid);
333 r = snprintf(tmp_name, sizeof(tmp_name), "temporary-cryptsetup-%s", tmp_uuid);
334 if (r < 0 || (size_t)r >= sizeof(tmp_name))
337 /* There is no data area, we can actually use fake zeroed key */
338 if (params && params->integrity_key_size)
339 vk = crypt_alloc_volume_key(params->integrity_key_size, NULL);
341 r = dm_integrity_target_set(cd, tgt, 0, dmdi.size, crypt_metadata_device(cd),
342 crypt_data_device(cd), crypt_get_integrity_tag_size(cd),
343 crypt_get_data_offset(cd), crypt_get_sector_size(cd), vk,
344 journal_crypt_key, journal_mac_key, params);
346 crypt_free_volume_key(vk);
350 log_dbg(cd, "Trying to format INTEGRITY device on top of %s, tmp name %s, tag size %d.",
351 device_path(tgt->data_device), tmp_name, tgt->u.integrity.tag_size);
353 r = device_block_adjust(cd, tgt->data_device, DEV_EXCL, tgt->u.integrity.offset, NULL, NULL);
354 if (r < 0 && (dm_flags(cd, DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
355 log_err(cd, _("Kernel does not support dm-integrity mapping."));
359 dm_targets_free(cd, &dmdi);
363 if (tgt->u.integrity.meta_device) {
364 r = device_block_adjust(cd, tgt->u.integrity.meta_device, DEV_EXCL, 0, NULL, NULL);
366 dm_targets_free(cd, &dmdi);
371 r = dm_create_device(cd, tmp_name, CRYPT_INTEGRITY, &dmdi);
372 crypt_free_volume_key(vk);
373 dm_targets_free(cd, &dmdi);
377 return dm_remove_device(cd, tmp_name, CRYPT_DEACTIVATE_FORCE);