2 * Integrity volume handling
4 * Copyright (C) 2016-2023 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 /* For LUKS2, integrity metadata are on DATA device even for detached header! */
31 static struct device *INTEGRITY_metadata_device(struct crypt_device *cd)
33 const char *type = crypt_get_type(cd);
35 if (type && !strcmp(type, CRYPT_LUKS2))
36 return crypt_data_device(cd);
38 return crypt_metadata_device(cd);
41 static int INTEGRITY_read_superblock(struct crypt_device *cd,
42 struct device *device,
43 uint64_t offset, struct superblock *sb)
47 devfd = device_open(cd, device, O_RDONLY);
51 if (read_lseek_blockwise(devfd, device_block_size(cd, device),
52 device_alignment(device), sb, sizeof(*sb), offset) != sizeof(*sb) ||
53 memcmp(sb->magic, SB_MAGIC, sizeof(sb->magic))) {
54 log_dbg(cd, "No kernel dm-integrity metadata detected on %s.", device_path(device));
56 } else if (sb->version < SB_VERSION_1 || sb->version > SB_VERSION_5) {
57 log_err(cd, _("Incompatible kernel dm-integrity metadata (version %u) detected on %s."),
58 sb->version, device_path(device));
61 sb->integrity_tag_size = le16toh(sb->integrity_tag_size);
62 sb->journal_sections = le32toh(sb->journal_sections);
63 sb->provided_data_sectors = le64toh(sb->provided_data_sectors);
64 sb->recalc_sector = le64toh(sb->recalc_sector);
65 sb->flags = le32toh(sb->flags);
72 int INTEGRITY_read_sb(struct crypt_device *cd,
73 struct crypt_params_integrity *params,
79 r = INTEGRITY_read_superblock(cd, INTEGRITY_metadata_device(cd), 0, &sb);
83 params->sector_size = SECTOR_SIZE << sb.log2_sectors_per_block;
84 params->tag_size = sb.integrity_tag_size;
92 int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offset)
97 r = INTEGRITY_read_superblock(cd, device, offset, &sb);
101 log_std(cd, "Info for integrity device %s.\n", device_path(device));
102 log_std(cd, "superblock_version %d\n", (unsigned)sb.version);
103 log_std(cd, "log2_interleave_sectors %d\n", sb.log2_interleave_sectors);
104 log_std(cd, "integrity_tag_size %u\n", sb.integrity_tag_size);
105 log_std(cd, "journal_sections %u\n", sb.journal_sections);
106 log_std(cd, "provided_data_sectors %" PRIu64 "\n", sb.provided_data_sectors);
107 log_std(cd, "sector_size %u\n", SECTOR_SIZE << sb.log2_sectors_per_block);
108 if (sb.version >= SB_VERSION_2 && (sb.flags & SB_FLAG_RECALCULATING))
109 log_std(cd, "recalc_sector %" PRIu64 "\n", sb.recalc_sector);
110 log_std(cd, "log2_blocks_per_bitmap %u\n", sb.log2_blocks_per_bitmap_bit);
111 log_std(cd, "flags %s%s%s%s%s\n",
112 sb.flags & SB_FLAG_HAVE_JOURNAL_MAC ? "have_journal_mac " : "",
113 sb.flags & SB_FLAG_RECALCULATING ? "recalculating " : "",
114 sb.flags & SB_FLAG_DIRTY_BITMAP ? "dirty_bitmap " : "",
115 sb.flags & SB_FLAG_FIXED_PADDING ? "fix_padding " : "",
116 sb.flags & SB_FLAG_FIXED_HMAC ? "fix_hmac " : "");
121 int INTEGRITY_data_sectors(struct crypt_device *cd,
122 struct device *device, uint64_t offset,
123 uint64_t *data_sectors)
125 struct superblock sb;
128 r = INTEGRITY_read_superblock(cd, device, offset, &sb);
132 *data_sectors = sb.provided_data_sectors;
136 int INTEGRITY_key_size(const char *integrity)
141 //FIXME: use crypto backend hash size
142 if (!strcmp(integrity, "aead"))
144 else if (!strcmp(integrity, "hmac(sha1)"))
146 else if (!strcmp(integrity, "hmac(sha256)"))
148 else if (!strcmp(integrity, "hmac(sha512)"))
150 else if (!strcmp(integrity, "poly1305"))
152 else if (!strcmp(integrity, "none"))
158 /* Return hash or hmac(hash) size, if known */
159 int INTEGRITY_hash_tag_size(const char *integrity)
161 char hash[MAX_CIPHER_LEN];
167 if (!strcmp(integrity, "crc32") || !strcmp(integrity, "crc32c"))
170 if (!strcmp(integrity, "xxhash64"))
173 r = sscanf(integrity, "hmac(%" MAX_CIPHER_LEN_STR "[^)]s", hash);
175 r = crypt_hash_size(hash);
177 r = crypt_hash_size(integrity);
179 return r < 0 ? 0 : r;
182 int INTEGRITY_tag_size(const char *integrity,
184 const char *cipher_mode)
186 int iv_tag_size = 0, auth_tag_size = 0;
190 else if (!strcmp(cipher_mode, "xts-random"))
192 else if (!strcmp(cipher_mode, "gcm-random"))
194 else if (!strcmp(cipher_mode, "ccm-random"))
196 else if (!strcmp(cipher_mode, "ctr-random"))
198 else if (!strcmp(cipher, "aegis256") && !strcmp(cipher_mode, "random"))
200 else if (!strcmp(cipher_mode, "random"))
203 //FIXME: use crypto backend hash size
204 if (!integrity || !strcmp(integrity, "none"))
206 else if (!strcmp(integrity, "aead"))
207 auth_tag_size = 16; /* gcm- mode only */
208 else if (!strcmp(integrity, "cmac(aes)"))
210 else if (!strcmp(integrity, "hmac(sha1)"))
212 else if (!strcmp(integrity, "hmac(sha256)"))
214 else if (!strcmp(integrity, "hmac(sha512)"))
216 else if (!strcmp(integrity, "poly1305")) {
222 return iv_tag_size + auth_tag_size;
225 int INTEGRITY_create_dmd_device(struct crypt_device *cd,
226 const struct crypt_params_integrity *params,
227 struct volume_key *vk,
228 struct volume_key *journal_crypt_key,
229 struct volume_key *journal_mac_key,
230 struct crypt_dm_active_device *dmd,
231 uint32_t flags, uint32_t sb_flags)
238 *dmd = (struct crypt_dm_active_device) {
242 /* Workaround for kernel dm-integrity table bug */
243 if (sb_flags & SB_FLAG_RECALCULATING)
244 dmd->flags |= CRYPT_ACTIVATE_RECALCULATE;
246 r = INTEGRITY_data_sectors(cd, INTEGRITY_metadata_device(cd),
247 crypt_get_data_offset(cd) * SECTOR_SIZE, &dmd->size);
251 return dm_integrity_target_set(cd, &dmd->segment, 0, dmd->size,
252 INTEGRITY_metadata_device(cd), crypt_data_device(cd),
253 crypt_get_integrity_tag_size(cd), crypt_get_data_offset(cd),
254 crypt_get_sector_size(cd), vk, journal_crypt_key,
255 journal_mac_key, params);
258 int INTEGRITY_activate_dmd_device(struct crypt_device *cd,
261 struct crypt_dm_active_device *dmd,
266 struct dm_target *tgt = &dmd->segment;
268 if (!single_segment(dmd) || tgt->type != DM_INTEGRITY)
271 log_dbg(cd, "Trying to activate INTEGRITY device on top of %s, using name %s, tag size %d, provided sectors %" PRIu64".",
272 device_path(tgt->data_device), name, tgt->u.integrity.tag_size, dmd->size);
274 r = create_or_reload_device(cd, name, type, dmd);
276 if (r < 0 && (dm_flags(cd, DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
277 log_err(cd, _("Kernel does not support dm-integrity mapping."));
281 if (r < 0 && (sb_flags & SB_FLAG_FIXED_PADDING) && !dm_flags(cd, DM_INTEGRITY, &dmi_flags) &&
282 !(dmi_flags & DM_INTEGRITY_FIX_PADDING_SUPPORTED)) {
283 log_err(cd, _("Kernel does not support dm-integrity fixed metadata alignment."));
287 if (r < 0 && (dmd->flags & CRYPT_ACTIVATE_RECALCULATE) &&
288 !(crypt_get_compatibility(cd) & CRYPT_COMPAT_LEGACY_INTEGRITY_RECALC) &&
289 ((sb_flags & SB_FLAG_FIXED_HMAC) ?
290 (tgt->u.integrity.vk && !tgt->u.integrity.journal_integrity_key) :
291 (tgt->u.integrity.vk || tgt->u.integrity.journal_integrity_key))) {
292 log_err(cd, _("Kernel refuses to activate insecure recalculate option (see legacy activation options to override)."));
299 int INTEGRITY_activate(struct crypt_device *cd,
301 const struct crypt_params_integrity *params,
302 struct volume_key *vk,
303 struct volume_key *journal_crypt_key,
304 struct volume_key *journal_mac_key,
305 uint32_t flags, uint32_t sb_flags)
307 struct crypt_dm_active_device dmdq = {}, dmd = {};
310 if (flags & CRYPT_ACTIVATE_REFRESH) {
311 r = dm_query_device(cd, name, DM_ACTIVE_CRYPT_KEYSIZE |
312 DM_ACTIVE_CRYPT_KEY |
313 DM_ACTIVE_INTEGRITY_PARAMS |
314 DM_ACTIVE_JOURNAL_CRYPT_KEY |
315 DM_ACTIVE_JOURNAL_MAC_KEY, &dmdq);
319 r = INTEGRITY_create_dmd_device(cd, params, vk ?: dmdq.segment.u.integrity.vk,
320 journal_crypt_key ?: dmdq.segment.u.integrity.journal_crypt_key,
321 journal_mac_key ?: dmdq.segment.u.integrity.journal_integrity_key,
322 &dmd, flags, sb_flags);
325 dmd.size = dmdq.size;
327 r = INTEGRITY_create_dmd_device(cd, params, vk, journal_crypt_key,
328 journal_mac_key, &dmd, flags, sb_flags);
331 r = INTEGRITY_activate_dmd_device(cd, name, CRYPT_INTEGRITY, &dmd, sb_flags);
333 dm_targets_free(cd, &dmdq);
334 dm_targets_free(cd, &dmd);
338 int INTEGRITY_format(struct crypt_device *cd,
339 const struct crypt_params_integrity *params,
340 struct volume_key *journal_crypt_key,
341 struct volume_key *journal_mac_key)
344 char tmp_name[64], tmp_uuid[40];
345 struct crypt_dm_active_device dmdi = {
347 .flags = CRYPT_ACTIVATE_PRIVATE, /* We always create journal but it can be unused later */
349 struct dm_target *tgt = &dmdi.segment;
352 struct volume_key *vk = NULL;
354 uuid_generate(tmp_uuid_bin);
355 uuid_unparse(tmp_uuid_bin, tmp_uuid);
357 r = snprintf(tmp_name, sizeof(tmp_name), "temporary-cryptsetup-%s", tmp_uuid);
358 if (r < 0 || (size_t)r >= sizeof(tmp_name))
361 /* There is no data area, we can actually use fake zeroed key */
362 if (params && params->integrity_key_size)
363 vk = crypt_alloc_volume_key(params->integrity_key_size, NULL);
365 r = dm_integrity_target_set(cd, tgt, 0, dmdi.size, INTEGRITY_metadata_device(cd),
366 crypt_data_device(cd), crypt_get_integrity_tag_size(cd),
367 crypt_get_data_offset(cd), crypt_get_sector_size(cd), vk,
368 journal_crypt_key, journal_mac_key, params);
370 crypt_free_volume_key(vk);
374 log_dbg(cd, "Trying to format INTEGRITY device on top of %s, tmp name %s, tag size %d.",
375 device_path(tgt->data_device), tmp_name, tgt->u.integrity.tag_size);
377 r = device_block_adjust(cd, tgt->data_device, DEV_EXCL, tgt->u.integrity.offset, NULL, NULL);
378 if (r < 0 && (dm_flags(cd, DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) {
379 log_err(cd, _("Kernel does not support dm-integrity mapping."));
383 dm_targets_free(cd, &dmdi);
387 if (tgt->u.integrity.meta_device) {
388 r = device_block_adjust(cd, tgt->u.integrity.meta_device, DEV_EXCL, 0, NULL, NULL);
390 dm_targets_free(cd, &dmdi);
395 r = dm_create_device(cd, tmp_name, CRYPT_INTEGRITY, &dmdi);
396 crypt_free_volume_key(vk);
397 dm_targets_free(cd, &dmdi);
401 return dm_remove_device(cd, tmp_name, CRYPT_DEACTIVATE_FORCE);