libdevmapper.c 30.6 KB
Newer Older
1 2 3
/*
 * libdevmapper - device-mapper backend for cryptsetup
 *
Milan Broz's avatar
Milan Broz committed
4
 * Copyright (C) 2004, Jana Saout <jana@saout.de>
5
 * Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
6 7
 * Copyright (C) 2009-2016, Red Hat, Inc. All rights reserved.
 * Copyright (C) 2009-2016, Milan Broz
8 9 10
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
11 12
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
13 14 15 16 17 18 19 20
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 23
 */

24
#include <stdio.h>
25 26 27
#include <dirent.h>
#include <errno.h>
#include <libdevmapper.h>
28 29
#include <fcntl.h>
#include <linux/fs.h>
30
#include <uuid/uuid.h>
31
#include <sys/stat.h>
32 33 34

#include "internal.h"

35
#define DM_UUID_LEN		129
36 37 38
#define DM_UUID_PREFIX		"CRYPT-"
#define DM_UUID_PREFIX_LEN	6
#define DM_CRYPT_TARGET		"crypt"
39
#define DM_VERITY_TARGET	"verity"
40
#define RETRY_COUNT		5
41

42 43
/* Set if dm-crypt version was probed */
static int _dm_crypt_checked = 0;
44
static int _quiet_log = 0;
45
static uint32_t _dm_crypt_flags = 0;
46

47
static struct crypt_device *_context = NULL;
48
static int _dm_use_count = 0;
49

50 51 52 53 54
/* Check if we have DM flag to instruct kernel to force wipe buffers */
#if !HAVE_DECL_DM_TASK_SECURE_DATA
static int dm_task_secure_data(struct dm_task *dmt) { return 1; }
#endif

55
/* Compatibility for old device-mapper without udev support */
56
#if HAVE_DECL_DM_UDEV_DISABLE_DISK_RULES_FLAG
57 58 59
#define CRYPT_TEMP_UDEV_FLAGS	DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG | \
				DM_UDEV_DISABLE_DISK_RULES_FLAG | \
				DM_UDEV_DISABLE_OTHER_RULES_FLAG
60 61
#define _dm_task_set_cookie	dm_task_set_cookie
#define _dm_udev_wait		dm_udev_wait
62 63 64 65
#else
#define CRYPT_TEMP_UDEV_FLAGS	0
static int _dm_task_set_cookie(struct dm_task *dmt, uint32_t *cookie, uint16_t flags) { return 0; }
static int _dm_udev_wait(uint32_t cookie) { return 0; };
66 67
#endif

68
static int _dm_use_udev(void)
69 70 71 72 73 74 75 76
{
#ifdef USE_UDEV /* cannot be enabled if devmapper is too old */
	return dm_udev_get_sync_support();
#else
	return 0;
#endif
}

77 78 79 80
__attribute__((format(printf, 4, 5)))
static void set_dm_error(int level,
			 const char *file __attribute__((unused)),
			 int line __attribute__((unused)),
81
			 const char *f, ...)
82
{
83
	char *msg = NULL;
84 85 86
	va_list va;

	va_start(va, f);
87
	if (vasprintf(&msg, f, va) > 0) {
88
		if (level < 4 && !_quiet_log) {
89
			log_err(_context, "%s", msg);
90
			log_err(_context, "\n");
91 92 93
		} else {
			/* We do not use DM visual stack backtrace here */
			if (strncmp(msg, "<backtrace>", 11))
94
				log_dbg("%s", msg);
95
		}
96 97
	}
	free(msg);
98 99 100
	va_end(va);
}

101
static int _dm_simple(int task, const char *name, int udev_wait);
102

103 104 105 106 107 108 109 110 111 112 113 114
static int _dm_satisfies_version(unsigned target_maj, unsigned target_min,
				 unsigned actual_maj, unsigned actual_min)
{
	if (actual_maj > target_maj)
		return 1;

	if (actual_maj == target_maj && actual_min >= target_min)
		return 1;

	return 0;
}

115 116
static void _dm_set_crypt_compat(const char *dm_version, unsigned crypt_maj,
				 unsigned crypt_min, unsigned crypt_patch)
117
{
118
	unsigned dm_maj, dm_min, dm_patch;
119

120 121 122 123 124 125
	if (sscanf(dm_version, "%u.%u.%u", &dm_maj, &dm_min, &dm_patch) != 3)
		dm_maj = dm_min = dm_patch = 0;

	log_dbg("Detected dm-crypt version %i.%i.%i, dm-ioctl version %u.%u.%u.",
		crypt_maj, crypt_min, crypt_patch, dm_maj, dm_min, dm_patch);

126
	if (_dm_satisfies_version(1, 2, crypt_maj, crypt_min))
127
		_dm_crypt_flags |= DM_KEY_WIPE_SUPPORTED;
128 129
	else
		log_dbg("Suspend and resume disabled, no wipe key support.");
130

131
	if (_dm_satisfies_version(1, 10, crypt_maj, crypt_min))
132 133
		_dm_crypt_flags |= DM_LMK_SUPPORTED;

134
	if (_dm_satisfies_version(4, 20, dm_maj, dm_min))
135 136
		_dm_crypt_flags |= DM_SECURE_SUPPORTED;

137
	/* not perfect, 2.6.33 supports with 1.7.0 */
138
	if (_dm_satisfies_version(1, 8, crypt_maj, crypt_min))
139 140
		_dm_crypt_flags |= DM_PLAIN64_SUPPORTED;

141
	if (_dm_satisfies_version(1, 11, crypt_maj, crypt_min))
142 143
		_dm_crypt_flags |= DM_DISCARDS_SUPPORTED;

144
	if (_dm_satisfies_version(1, 13, crypt_maj, crypt_min))
145
		_dm_crypt_flags |= DM_TCW_SUPPORTED;
146

147 148 149 150 151
	if (_dm_satisfies_version(1, 14, crypt_maj, crypt_min)) {
		_dm_crypt_flags |= DM_SAME_CPU_CRYPT_SUPPORTED;
		_dm_crypt_flags |= DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED;
	}

152 153 154
	/* Repeat test if dm-crypt is not present */
	if (crypt_maj > 0)
		_dm_crypt_checked = 1;
155 156
}

Milan Broz's avatar
Milan Broz committed
157 158 159 160 161
static void _dm_set_verity_compat(const char *dm_version, unsigned verity_maj,
				   unsigned verity_min, unsigned verity_patch)
{
	if (verity_maj > 0)
		_dm_crypt_flags |= DM_VERITY_SUPPORTED;
162 163 164 165 166 167 168 169 170
	else
		return;
	/*
	 * ignore_corruption, restart_on corruption is available since 1.2 (kernel 4.1)
	 * ignore_zero_blocks since 1.3 (kernel 4.5)
	 * (but some dm-verity targets 1.2 don't support it)
	 */
	if (_dm_satisfies_version(1, 3, verity_maj, verity_min))
		_dm_crypt_flags |= DM_VERITY_ON_CORRUPTION_SUPPORTED;
Milan Broz's avatar
Milan Broz committed
171 172 173 174 175

	log_dbg("Detected dm-verity version %i.%i.%i.",
		verity_maj, verity_min, verity_patch);
}

176
static int _dm_check_versions(void)
177 178 179
{
	struct dm_task *dmt;
	struct dm_versions *target, *last_target;
180
	char dm_version[16];
181
	int r = 0;
182

183 184 185
	if (_dm_crypt_checked)
		return 1;

186 187 188
	/* Shut up DM while checking */
	_quiet_log = 1;

189
	/* FIXME: add support to DM so it forces crypt target module load here */
190
	if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
191
		goto out;
192

193 194
	if (!dm_task_run(dmt))
		goto out;
195

196 197
	if (!dm_task_get_driver_version(dmt, dm_version, sizeof(dm_version)))
		goto out;
198

199 200 201 202
	target = dm_task_get_versions(dmt);
	do {
		last_target = target;
		if (!strcmp(DM_CRYPT_TARGET, target->name)) {
203
			_dm_set_crypt_compat(dm_version,
Milan Broz's avatar
Milan Broz committed
204 205 206 207 208
					     (unsigned)target->version[0],
					     (unsigned)target->version[1],
					     (unsigned)target->version[2]);
		} else if (!strcmp(DM_VERITY_TARGET, target->name)) {
			_dm_set_verity_compat(dm_version,
209 210 211
					     (unsigned)target->version[0],
					     (unsigned)target->version[1],
					     (unsigned)target->version[2]);
212
		}
213
		target = (struct dm_versions *)((char *) target + target->next);
214 215
	} while (last_target != target);

216 217 218 219 220 221 222 223 224
	r = 1;
	log_dbg("Device-mapper backend running with UDEV support %sabled.",
		_dm_use_udev() ? "en" : "dis");
out:
	if (dmt)
		dm_task_destroy(dmt);

	_quiet_log = 0;
	return r;
225 226
}

227 228
uint32_t dm_flags(void)
{
229
	_dm_check_versions();
230 231 232
	return _dm_crypt_flags;
}

233 234
/* This doesn't run any kernel checks, just set up userspace libdevmapper */
void dm_backend_init(void)
235
{
236
	if (!_dm_use_count++) {
237
		log_dbg("Initialising device-mapper backend library.");
238 239
		dm_log_init(set_dm_error);
		dm_log_init_verbose(10);
240
	}
241 242
}

243
void dm_backend_exit(void)
244
{
245
	if (_dm_use_count && (!--_dm_use_count)) {
246
		log_dbg("Releasing device-mapper backend.");
247 248 249
		dm_log_init_verbose(0);
		dm_log_init(NULL);
		dm_lib_release();
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
	}
}

/*
 * libdevmapper is not context friendly, switch context on every DM call.
 * FIXME: this is not safe if called in parallel but neither is DM lib.
 */
static int dm_init_context(struct crypt_device *cd)
{
	_context = cd;
	if (!_dm_check_versions()) {
		if (getuid() || geteuid())
			log_err(cd, _("Cannot initialize device-mapper, "
				      "running as non-root user.\n"));
		else
			log_err(cd, _("Cannot initialize device-mapper. "
				      "Is dm_mod kernel module loaded?\n"));
267
		_context = NULL;
268
		return -ENOTSUP;
269
	}
270 271 272 273 274
	return 0;
}
static void dm_exit_context(void)
{
	_context = NULL;
275 276
}

277
/* Return path to DM device */
278
char *dm_device_path(const char *prefix, int major, int minor)
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
{
	struct dm_task *dmt;
	const char *name;
	char path[PATH_MAX];

	if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
		return NULL;
	if (!dm_task_set_minor(dmt, minor) ||
	    !dm_task_set_major(dmt, major) ||
	    !dm_task_run(dmt) ||
	    !(name = dm_task_get_name(dmt))) {
		dm_task_destroy(dmt);
		return NULL;
	}

294
	if (snprintf(path, sizeof(path), "%s%s", prefix ?: "", name) < 0)
295 296 297 298 299 300 301
		path[0] = '\0';

	dm_task_destroy(dmt);

	return strdup(path);
}

302 303
static void hex_key(char *hexkey, size_t key_size, const char *key)
{
304
	unsigned i;
305 306 307 308 309

	for(i = 0; i < key_size; i++)
		sprintf(&hexkey[i * 2], "%02x", (unsigned char)key[i]);
}

Milan Broz's avatar
Milan Broz committed
310
/* https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt */
311
static char *get_dm_crypt_params(struct crypt_dm_active_device *dmd, uint32_t flags)
312
{
313
	int r, max_size, null_cipher = 0, num_options = 0;
314
	char *params, *hexkey;
315
	char features[256];
316

317 318 319
	if (!dmd)
		return NULL;

320
	if (flags & CRYPT_ACTIVATE_ALLOW_DISCARDS)
321 322 323 324 325 326 327 328 329 330 331
		num_options++;
	if (flags & CRYPT_ACTIVATE_SAME_CPU_CRYPT)
		num_options++;
	if (flags & CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS)
		num_options++;

	if (num_options)
		snprintf(features, sizeof(features)-1, " %d%s%s%s", num_options,
		(flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) ? " allow_discards" : "",
		(flags & CRYPT_ACTIVATE_SAME_CPU_CRYPT) ? " same_cpu_crypt" : "",
		(flags & CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS) ? " submit_from_crypt_cpus" : "");
332
	else
333
		*features = '\0';
334

335
	if (!strncmp(dmd->u.crypt.cipher, "cipher_null-", 12))
336 337
		null_cipher = 1;

338
	hexkey = crypt_safe_alloc(null_cipher ? 2 : (dmd->u.crypt.vk->keylength * 2 + 1));
339
	if (!hexkey)
340 341
		return NULL;

342 343 344
	if (null_cipher)
		strncpy(hexkey, "-", 2);
	else
345
		hex_key(hexkey, dmd->u.crypt.vk->keylength, dmd->u.crypt.vk->key);
346

347
	max_size = strlen(hexkey) + strlen(dmd->u.crypt.cipher) +
Milan Broz's avatar
Milan Broz committed
348 349
		   strlen(device_block_path(dmd->data_device)) +
		   strlen(features) + 64;
350
	params = crypt_safe_alloc(max_size);
351
	if (!params)
352 353
		goto out;

354
	r = snprintf(params, max_size, "%s %s %" PRIu64 " %s %" PRIu64 "%s",
355
		     dmd->u.crypt.cipher, hexkey, dmd->u.crypt.iv_offset,
Milan Broz's avatar
Milan Broz committed
356 357
		     device_block_path(dmd->data_device), dmd->u.crypt.offset,
		     features);
358 359 360 361
	if (r < 0 || r >= max_size) {
		crypt_safe_free(params);
		params = NULL;
	}
362
out:
363
	crypt_safe_free(hexkey);
364 365
	return params;
}
366

Milan Broz's avatar
Milan Broz committed
367
/* https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity */
368
static char *get_dm_verity_params(struct crypt_params_verity *vp,
369
				   struct crypt_dm_active_device *dmd, uint32_t flags)
370
{
371
	int max_size, r, num_options = 0;
372
	char *params = NULL, *hexroot = NULL, *hexsalt = NULL;
373
	char features[256];
374

375 376 377
	if (!vp || !dmd)
		return NULL;

378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
	/* These flags are not compatible */
	if ((flags & CRYPT_ACTIVATE_IGNORE_CORRUPTION) &&
	    (flags & CRYPT_ACTIVATE_RESTART_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_IGNORE_ZERO_BLOCKS)
		num_options++;

	if (num_options)
		snprintf(features, sizeof(features)-1, " %d%s%s%s", num_options,
		(flags & CRYPT_ACTIVATE_IGNORE_CORRUPTION) ? " ignore_corruption" : "",
		(flags & CRYPT_ACTIVATE_RESTART_ON_CORRUPTION) ? " restart_on_corruption" : "",
		(flags & CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS) ? " ignore_zero_blocks" : "");
	else
		*features = '\0';

398
	hexroot = crypt_safe_alloc(dmd->u.verity.root_hash_size * 2 + 1);
399 400
	if (!hexroot)
		goto out;
401
	hex_key(hexroot, dmd->u.verity.root_hash_size, dmd->u.verity.root_hash);
402

403
	hexsalt = crypt_safe_alloc(vp->salt_size ? vp->salt_size * 2 + 1 : 2);
404 405
	if (!hexsalt)
		goto out;
406 407 408 409
	if (vp->salt_size)
		hex_key(hexsalt, vp->salt_size, vp->salt);
	else
		strncpy(hexsalt, "-", 2);
410 411

	max_size = strlen(hexroot) + strlen(hexsalt) +
Milan Broz's avatar
Milan Broz committed
412 413
		   strlen(device_block_path(dmd->data_device)) +
		   strlen(device_block_path(dmd->u.verity.hash_device)) +
414 415 416 417 418 419 420
		   strlen(vp->hash_name) + 128;

	params = crypt_safe_alloc(max_size);
	if (!params)
		goto out;

	r = snprintf(params, max_size,
421
		     "%u %s %s %u %u %" PRIu64 " %" PRIu64 " %s %s %s %s",
Milan Broz's avatar
Milan Broz committed
422 423
		     vp->hash_type, device_block_path(dmd->data_device),
		     device_block_path(dmd->u.verity.hash_device),
424
		     vp->data_block_size, vp->hash_block_size,
425
		     vp->data_size, dmd->u.verity.hash_offset,
426
		     vp->hash_name, hexroot, hexsalt, features);
427 428 429 430 431 432 433 434 435 436
	if (r < 0 || r >= max_size) {
		crypt_safe_free(params);
		params = NULL;
	}
out:
	crypt_safe_free(hexroot);
	crypt_safe_free(hexsalt);
	return params;

}
437

438
/* DM helpers */
439
static int _dm_simple(int task, const char *name, int udev_wait)
440 441 442
{
	int r = 0;
	struct dm_task *dmt;
443 444 445 446
	uint32_t cookie = 0;

	if (!_dm_use_udev())
		udev_wait = 0;
447 448 449 450

	if (!(dmt = dm_task_create(task)))
		return 0;

451
	if (name && !dm_task_set_name(dmt, name))
452 453
		goto out;

454 455 456 457 458
#if HAVE_DECL_DM_TASK_RETRY_REMOVE
	/* Used only in DM_DEVICE_REMOVE */
	if (name && !dm_task_retry_remove(dmt))
		goto out;
#endif
459
	if (udev_wait && !_dm_task_set_cookie(dmt, &cookie, 0))
460
		goto out;
461

462 463
	r = dm_task_run(dmt);

464
	if (udev_wait)
465
		(void)_dm_udev_wait(cookie);
466

467
out:
468 469 470 471
	dm_task_destroy(dmt);
	return r;
}

472
static int _error_device(const char *name, size_t size)
473 474 475 476 477 478 479
{
	struct dm_task *dmt;
	int r = 0;

	if (!(dmt = dm_task_create(DM_DEVICE_RELOAD)))
		return 0;

480
	if (!dm_task_set_name(dmt, name))
481 482
		goto error;

483
	if (!dm_task_add_target(dmt, UINT64_C(0), size, "error", ""))
484 485 486 487 488 489 490 491 492 493 494
		goto error;

	if (!dm_task_set_ro(dmt))
		goto error;

	if (!dm_task_no_open_count(dmt))
		goto error;

	if (!dm_task_run(dmt))
		goto error;

495 496
	if (!_dm_simple(DM_DEVICE_RESUME, name, 1)) {
		_dm_simple(DM_DEVICE_CLEAR, name, 0);
497 498 499 500 501 502 503 504 505 506
		goto error;
	}

	r = 1;

error:
	dm_task_destroy(dmt);
	return r;
}

Milan Broz's avatar
Milan Broz committed
507 508
int dm_remove_device(struct crypt_device *cd, const char *name,
		     int force, uint64_t size)
509 510 511
{
	int r = -EINVAL;
	int retries = force ? RETRY_COUNT : 1;
512
	int error_target = 0;
513

514 515 516
	if (!name || (force && !size))
		return -EINVAL;

517 518 519
	if (dm_init_context(cd))
		return -ENOTSUP;

520
	do {
521
		r = _dm_simple(DM_DEVICE_REMOVE, name, 1) ? 0 : -EINVAL;
522
		if (--retries && r) {
523 524
			log_dbg("WARNING: other process locked internal device %s, %s.",
				name, retries ? "retrying remove" : "giving up");
525
			sleep(1);
526 527 528 529 530 531 532 533 534 535 536 537
			if (force && !error_target) {
				/* If force flag is set, replace device with error, read-only target.
				 * it should stop processes from reading it and also removed underlying
				 * device from mapping, so it is usable again.
				 * Force flag should be used only for temporary devices, which are
				 * intended to work inside cryptsetup only!
				 * Anyway, if some process try to read temporary cryptsetup device,
				 * it is bug - no other process should try touch it (e.g. udev).
				 */
				_error_device(name, size);
				error_target = 1;
			}
538
		}
539 540 541
	} while (r == -EINVAL && retries);

	dm_task_update_nodes();
542
	dm_exit_context();
543 544 545 546

	return r;
}

547 548 549 550 551 552 553
#define UUID_LEN 37 /* 36 + \0, libuuid ... */
/*
 * UUID has format: CRYPT-<devicetype>-[<uuid>-]<device name>
 * CRYPT-PLAIN-name
 * CRYPT-LUKS1-00000000000000000000000000000000-name
 * CRYPT-TEMP-name
 */
554
static int dm_prepare_uuid(const char *name, const char *type, const char *uuid, char *buf, size_t buflen)
555 556 557
{
	char *ptr, uuid2[UUID_LEN] = {0};
	uuid_t uu;
558
	unsigned i = 0;
559 560

	/* Remove '-' chars */
561 562 563
	if (uuid) {
		if (uuid_parse(uuid, uu) < 0) {
			log_dbg("Requested UUID %s has invalid format.", uuid);
564
			return 0;
565 566
		}

567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
		for (ptr = uuid2, i = 0; i < UUID_LEN; i++)
			if (uuid[i] != '-') {
				*ptr = uuid[i];
				ptr++;
			}
	}

	i = snprintf(buf, buflen, DM_UUID_PREFIX "%s%s%s%s%s",
		type ?: "", type ? "-" : "",
		uuid2[0] ? uuid2 : "", uuid2[0] ? "-" : "",
		name);

	log_dbg("DM-UUID is %s", buf);
	if (i >= buflen)
		log_err(NULL, _("DM-UUID for device %s was truncated.\n"), name);
582

583
	return 1;
584 585
}

586
static int _dm_create_device(const char *name, const char *type,
Milan Broz's avatar
Milan Broz committed
587
			     struct device *device, uint32_t flags,
588 589
			     const char *uuid, uint64_t size,
			     char *params, int reload)
590 591 592
{
	struct dm_task *dmt = NULL;
	struct dm_info dmi;
593
	char dev_uuid[DM_UUID_LEN] = {0};
594
	int r = -EINVAL;
595
	uint32_t read_ahead = 0;
596
	uint32_t cookie = 0;
597
	uint16_t udev_flags = 0;
598

599 600 601
	if (!params)
		return -EINVAL;

602
	if (flags & CRYPT_ACTIVATE_PRIVATE)
603 604
		udev_flags = CRYPT_TEMP_UDEV_FLAGS;

605 606 607 608 609 610 611 612
	/* All devices must have DM_UUID, only resize on old device is exception */
	if (reload) {
		if (!(dmt = dm_task_create(DM_DEVICE_RELOAD)))
			goto out_no_removal;

		if (!dm_task_set_name(dmt, name))
			goto out_no_removal;
	} else {
613 614
		if (!dm_prepare_uuid(name, type, uuid, dev_uuid, sizeof(dev_uuid)))
			goto out_no_removal;
615 616 617 618 619 620 621 622 623

		if (!(dmt = dm_task_create(DM_DEVICE_CREATE)))
			goto out_no_removal;

		if (!dm_task_set_name(dmt, name))
			goto out_no_removal;

		if (!dm_task_set_uuid(dmt, dev_uuid))
			goto out_no_removal;
624
	}
625

626
	if ((dm_flags() & DM_SECURE_SUPPORTED) && !dm_task_secure_data(dmt))
627
		goto out_no_removal;
628
	if ((flags & CRYPT_ACTIVATE_READONLY) && !dm_task_set_ro(dmt))
629
		goto out_no_removal;
630 631 632

	if (!dm_task_add_target(dmt, 0, size,
		!strcmp("VERITY", type) ? DM_VERITY_TARGET : DM_CRYPT_TARGET, params))
633
		goto out_no_removal;
634 635

#ifdef DM_READ_AHEAD_MINIMUM_FLAG
636
	if (device_read_ahead(device, &read_ahead) &&
637
	    !dm_task_set_read_ahead(dmt, read_ahead, DM_READ_AHEAD_MINIMUM_FLAG))
638
		goto out_no_removal;
639
#endif
640 641 642
	/* do not set cookie for DM_DEVICE_RELOAD task */
	if (!reload && _dm_use_udev() && !_dm_task_set_cookie(dmt, &cookie, udev_flags))
		goto out_no_removal;
643

644
	if (!dm_task_run(dmt))
645
		goto out_no_removal;
646 647 648 649 650

	if (reload) {
		dm_task_destroy(dmt);
		if (!(dmt = dm_task_create(DM_DEVICE_RESUME)))
			goto out;
651
		if (!dm_task_set_name(dmt, name))
652
			goto out;
653
		if (uuid && !dm_task_set_uuid(dmt, dev_uuid))
654
			goto out;
655
		if (_dm_use_udev() && !_dm_task_set_cookie(dmt, &cookie, udev_flags))
656
			goto out;
657 658 659 660 661 662 663 664 665
		if (!dm_task_run(dmt))
			goto out;
	}

	if (!dm_task_get_info(dmt, &dmi))
		goto out;

	r = 0;
out:
666
	if (_dm_use_udev()) {
667
		(void)_dm_udev_wait(cookie);
668 669 670
		cookie = 0;
	}

Milan Broz's avatar
Milan Broz committed
671
	if (r < 0 && !reload)
Milan Broz's avatar
Milan Broz committed
672
		_dm_simple(DM_DEVICE_REMOVE, name, 1);
673 674

out_no_removal:
675
	if (cookie && _dm_use_udev())
676
		(void)_dm_udev_wait(cookie);
677

678 679
	if (dmt)
		dm_task_destroy(dmt);
680

681
	dm_task_update_nodes();
682 683 684 685

	/* If code just loaded target module, update versions */
	_dm_check_versions();

686 687 688
	return r;
}

Milan Broz's avatar
Milan Broz committed
689
int dm_create_device(struct crypt_device *cd, const char *name,
690 691 692 693 694
		     const char *type,
		     struct crypt_dm_active_device *dmd,
		     int reload)
{
	char *table_params = NULL;
695
	uint32_t dmd_flags;
696
	int r;
697 698 699 700 701 702

	if (!type)
		return -EINVAL;

	if (dm_init_context(cd))
		return -ENOTSUP;
703

704 705
	dmd_flags = dmd->flags;

706
	if (dmd->target == DM_CRYPT)
707
		table_params = get_dm_crypt_params(dmd, dmd_flags);
708
	else if (dmd->target == DM_VERITY)
709
		table_params = get_dm_verity_params(dmd->u.verity.vp, dmd, dmd_flags);
710

711 712 713 714 715 716 717 718 719 720 721 722 723 724
	r = _dm_create_device(name, type, dmd->data_device, dmd_flags,
			      dmd->uuid, dmd->size, table_params, reload);

	/* If discard not supported try to load without discard */
	if (!reload && r && dmd->target == DM_CRYPT &&
	    (dmd->flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) &&
	    !(dm_flags() & DM_DISCARDS_SUPPORTED)) {
		log_dbg("Discard/TRIM is not supported, retrying activation.");
		dmd_flags = dmd_flags & ~CRYPT_ACTIVATE_ALLOW_DISCARDS;
		crypt_safe_free(table_params);
		table_params = get_dm_crypt_params(dmd, dmd_flags);
		r = _dm_create_device(name, type, dmd->data_device, dmd_flags,
				      dmd->uuid, dmd->size, table_params, reload);
	}
725

726 727 728
	if (r == -EINVAL &&
	    dmd_flags & (CRYPT_ACTIVATE_SAME_CPU_CRYPT|CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS) &&
	    !(dm_flags() & (DM_SAME_CPU_CRYPT_SUPPORTED|DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED)))
729 730 731 732 733 734 735
		log_err(cd, _("Requested dm-crypt performance options are not supported.\n"));

	if (r == -EINVAL && dmd_flags & (CRYPT_ACTIVATE_IGNORE_CORRUPTION|
					  CRYPT_ACTIVATE_RESTART_ON_CORRUPTION|
					  CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS) &&
	    !(dm_flags() & DM_VERITY_ON_CORRUPTION_SUPPORTED))
		log_err(cd, _("Requested dm-verity data corruption handling options are not supported.\n"));
736

737
	crypt_safe_free(table_params);
738 739
	dm_exit_context();
	return r;
740 741 742 743
}

static int dm_status_dmi(const char *name, struct dm_info *dmi,
			  const char *target, char **status_line)
744 745 746
{
	struct dm_task *dmt;
	uint64_t start, length;
747
	char *target_type, *params = NULL;
748 749 750
	void *next = NULL;
	int r = -EINVAL;

751
	if (!(dmt = dm_task_create(DM_DEVICE_STATUS)))
752
		goto out;
753

754
	if (!dm_task_set_name(dmt, name))
755 756
		goto out;

757
	if (!dm_task_run(dmt))
758 759
		goto out;

760
	if (!dm_task_get_info(dmt, dmi))
761 762
		goto out;

763
	if (!dmi->exists) {
764 765 766 767 768 769
		r = -ENODEV;
		goto out;
	}

	next = dm_get_next_target(dmt, next, &start, &length,
	                          &target_type, &params);
770 771 772 773 774 775 776 777 778 779 780 781

	if (!target_type || start != 0 || next)
		goto out;

	if (target && strcmp(target_type, target))
		goto out;

	/* for target == NULL check all supported */
	if (!target && (strcmp(target_type, DM_CRYPT_TARGET) &&
			strcmp(target_type, DM_VERITY_TARGET)))
		goto out;
	r = 0;
782
out:
783 784 785
	if (!r && status_line && !(*status_line = strdup(params)))
		r = -ENOMEM;

786 787 788 789 790 791
	if (dmt)
		dm_task_destroy(dmt);

	return r;
}

Milan Broz's avatar
Milan Broz committed
792
int dm_status_device(struct crypt_device *cd, const char *name)
793 794 795
{
	int r;
	struct dm_info dmi;
796 797 798 799 800 801 802 803
	struct stat st;

	/* libdevmapper is too clever and handles
	 * path argument differenly with error.
	 * Fail early here if parameter is non-existent path.
	 */
	if (strchr(name, '/') && stat(name, &st) < 0)
		return -ENODEV;
804

805 806
	if (dm_init_context(cd))
		return -ENOTSUP;
807
	r = dm_status_dmi(name, &dmi, NULL, NULL);
808
	dm_exit_context();
809 810 811 812 813 814
	if (r < 0)
		return r;

	return (dmi.open_count > 0);
}

Milan Broz's avatar
Milan Broz committed
815
int dm_status_suspended(struct crypt_device *cd, const char *name)
816 817 818 819
{
	int r;
	struct dm_info dmi;

820 821
	if (dm_init_context(cd))
		return -ENOTSUP;
822
	r = dm_status_dmi(name, &dmi, DM_CRYPT_TARGET, NULL);
823
	dm_exit_context();
824 825 826 827 828 829
	if (r < 0)
		return r;

	return dmi.suspended ? 1 : 0;
}

Milan Broz's avatar
Milan Broz committed
830
static int _dm_status_verity_ok(const char *name)
831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848
{
	int r;
	struct dm_info dmi;
	char *status_line = NULL;

	r = dm_status_dmi(name, &dmi, DM_VERITY_TARGET, &status_line);
	if (r < 0 || !status_line) {
		free(status_line);
		return r;
	}

	log_dbg("Verity volume %s status is %s.", name, status_line ?: "");
	r = status_line[0] == 'V' ? 1 : 0;
	free(status_line);

	return r;
}

Milan Broz's avatar
Milan Broz committed
849 850
int dm_status_verity_ok(struct crypt_device *cd, const char *name)
{
851 852 853 854 855 856 857
	int r;

	if (dm_init_context(cd))
		return -ENOTSUP;
	r = _dm_status_verity_ok(name);
	dm_exit_context();
	return r;
Milan Broz's avatar
Milan Broz committed
858 859
}

860
/* FIXME use hex wrapper, user val wrappers for line parsing */
861 862 863 864
static int _dm_query_crypt(uint32_t get_flags,
			   struct dm_info *dmi,
			   char *params,
			   struct crypt_dm_active_device *dmd)
865
{
866 867
	uint64_t val64;
	char *rcipher, *key_, *rdevice, *endp, buffer[3], *arg;
868
	unsigned int i;
Milan Broz's avatar
Milan Broz committed
869
	int r;
870

871
	memset(dmd, 0, sizeof(*dmd));
872
	dmd->target = DM_CRYPT;
873

874 875
	rcipher = strsep(&params, " ");
	/* cipher */
876
	if (get_flags & DM_ACTIVE_CRYPT_CIPHER)
877
		dmd->u.crypt.cipher = strdup(rcipher);
878

879 880 881
	/* skip */
	key_ = strsep(&params, " ");
	if (!params)
882
		return -EINVAL;
883 884
	val64 = strtoull(params, &params, 10);
	if (*params != ' ')
885
		return -EINVAL;
886
	params++;
887

888
	dmd->u.crypt.iv_offset = val64;
889

890 891
	/* device */
	rdevice = strsep(&params, " ");
Milan Broz's avatar
Milan Broz committed
892 893 894 895 896 897 898
	if (get_flags & DM_ACTIVE_DEVICE) {
		arg = crypt_lookup_dev(rdevice);
		r = device_alloc(&dmd->data_device, arg);
		free(arg);
		if (r < 0 && r != -ENOTBLK)
			return r;
	}
899

900 901
	/*offset */
	if (!params)
902
		return -EINVAL;
903
	val64 = strtoull(params, &params, 10);
904
	dmd->u.crypt.offset = val64;
905

906 907 908
	/* Features section, available since crypt target version 1.11 */
	if (*params) {
		if (*params != ' ')
909
			return -EINVAL;
910 911 912 913 914
		params++;

		/* Number of arguments */
		val64 = strtoull(params, &params, 10);
		if (*params != ' ')
915
			return -EINVAL;
916 917 918 919
		params++;

		for (i = 0; i < val64; i++) {
			if (!params)
920
				return -EINVAL;
921 922 923
			arg = strsep(&params, " ");
			if (!strcasecmp(arg, "allow_discards"))
				dmd->flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
924 925 926 927
			else if (!strcasecmp(arg, "same_cpu_crypt"))
				dmd->flags |= CRYPT_ACTIVATE_SAME_CPU_CRYPT;
			else if (!strcasecmp(arg, "submit_from_crypt_cpus"))
				dmd->flags |= CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS;
928
			else /* unknown option */
929
				return -EINVAL;
930 931
		}

932
		/* All parameters should be processed */
933
		if (params)
934
			return -EINVAL;
935 936
	}

937
	/* Never allow to return empty key */
938
	if ((get_flags & DM_ACTIVE_CRYPT_KEY) && dmi->suspended) {
939
		log_dbg("Cannot read volume key while suspended.");
940
		return -EINVAL;
941 942
	}

943
	if (get_flags & DM_ACTIVE_CRYPT_KEYSIZE) {
944
		dmd->u.crypt.vk = crypt_alloc_volume_key(strlen(key_) / 2, NULL);
945 946
		if (!dmd->u.crypt.vk)
			return -ENOMEM;
947

948
		if (get_flags & DM_ACTIVE_CRYPT_KEY) {
949
			buffer[2] = '\0';
950
			for(i = 0; i < dmd->u.crypt.vk->keylength; i++) {
951
				memcpy(buffer, &key_[i * 2], 2);
952
				dmd->u.crypt.vk->key[i] = strtoul(buffer, &endp, 16);
953
				if (endp != &buffer[2]) {
954 955
					crypt_free_volume_key(dmd->u.crypt.vk);
					dmd->u.crypt.vk = NULL;
956
					return -EINVAL;
957
				}
958 959 960
			}
		}
	}
961
	memset(key_, 0, strlen(key_));
962

963 964 965 966 967 968 969 970
	return 0;
}

static int _dm_query_verity(uint32_t get_flags,
			     struct dm_info *dmi,
			     char *params,
			     struct crypt_dm_active_device *dmd)
{
971 972 973
	struct crypt_params_verity *vp = NULL;
	uint32_t val32;
	uint64_t val64;
974
	ssize_t len;
975 976
	char *str, *str2, *arg;
	unsigned int i;
Milan Broz's avatar
Milan Broz committed
977
	int r;
978 979 980 981 982 983

	if (get_flags & DM_ACTIVE_VERITY_PARAMS)
		vp = dmd->u.verity.vp;

	memset(dmd, 0, sizeof(*dmd));

984
	dmd->target = DM_VERITY;
985 986 987 988 989 990 991
	dmd->u.verity.vp = vp;

	/* version */
	val32 = strtoul(params, &params, 10);
	if (*params != ' ')
		return -EINVAL;
	if (vp)
992
		vp->hash_type = val32;
993 994 995 996 997 998
	params++;

	/* data device */
	str = strsep(&params, " ");
	if (!params)
		return -EINVAL;
Milan Broz's avatar
Milan Broz committed
999 1000 1001 1002 1003 1004 1005
	if (get_flags & DM_ACTIVE_DEVICE) {
		str2 = crypt_lookup_dev(str);
		r = device_alloc(&dmd->data_device, str2);
		free(str2);
		if (r < 0 && r != -ENOTBLK)
			return r;
	}
1006 1007 1008 1009 1010

	/* hash device */
	str = strsep(&params, " ");
	if (!params)
		return -EINVAL;
Milan Broz's avatar
Milan Broz committed
1011 1012 1013 1014 1015 1016 1017
	if (get_flags & DM_ACTIVE_VERITY_HASH_DEVICE) {
		str2 = crypt_lookup_dev(str);
		r = device_alloc(&dmd->u.verity.hash_device, str2);
		free(str2);
		if (r < 0 && r != -ENOTBLK)
			return r;
	}
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060

	/* data block size*/
	val32 = strtoul(params, &params, 10);
	if (*params != ' ')
		return -EINVAL;
	if (vp)
		vp->data_block_size = val32;
	params++;

	/* hash block size */
	val32 = strtoul(params, &params, 10);
	if (*params != ' ')
		return -EINVAL;
	if (vp)
		vp->hash_block_size = val32;
	params++;

	/* data blocks */
	val64 = strtoull(params, &params, 10);
	if (*params != ' ')
		return -EINVAL;
	if (vp)
		vp->data_size = val64;
	params++;

	/* hash start */
	val64 = strtoull(params, &params, 10);
	if (*params != ' ')
		return -EINVAL;
	dmd->u.verity.hash_offset = val64;
	params++;

	/* hash algorithm */
	str = strsep(&params, " ");
	if (!params)
		return -EINVAL;
	if (vp)
		vp->hash_name = strdup(str);

	/* root digest */
	str = strsep(&params, " ");
	if (!params)
		return -EINVAL;
1061 1062 1063
	len = crypt_hex_to_bytes(str, &str2, 0);
	if (len < 0)
		return len;
1064
	dmd->u.verity.root_hash_size = len;
1065
	if (get_flags & DM_ACTIVE_VERITY_ROOT_HASH)
1066
		dmd->u.verity.root_hash = str2;
1067 1068
	else
		free(str2);
1069 1070 1071 1072

	/* salt */
	str = strsep(&params, " ");
	if (vp) {
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082
		if (!strcmp(str, "-")) {
			vp->salt_size = 0;
			vp->salt = NULL;
		} else {
			len = crypt_hex_to_bytes(str, &str2, 0);
			if (len < 0)
				return len;
			vp->salt_size = len;
			vp->salt = str2;
		}
1083 1084
	}

1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
	/* Features section, available since verity target version 1.3 */
	if (params) {
		/* Number of arguments */
		val64 = strtoull(params, &params, 10);
		if (*params != ' ')
			return -EINVAL;
		params++;

		for (i = 0; i < val64; i++) {
			if (!params)
				return -EINVAL;
			arg = strsep(&params, " ");
			if (!strcasecmp(arg, "ignore_corruption"))
				dmd->flags |= CRYPT_ACTIVATE_IGNORE_CORRUPTION;
			else if (!strcasecmp(arg, "restart_on_corruption"))
				dmd->flags |= CRYPT_ACTIVATE_RESTART_ON_CORRUPTION;
			else if (!strcasecmp(arg, "ignore_zero_blocks"))
				dmd->flags |= CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS;
			else /* unknown option */
				return -EINVAL;
		}

		/* All parameters should be processed */
		if (params)
			return -EINVAL;
	}

1112
	return 0;
1113 1114
}

Milan Broz's avatar
Milan Broz committed
1115 1116
int dm_query_device(struct crypt_device *cd, const char *name,
		    uint32_t get_flags, struct crypt_dm_active_device *dmd)
1117 1118 1119 1120 1121 1122 1123 1124 1125
{
	struct dm_task *dmt;
	struct dm_info dmi;
	uint64_t start, length;
	char *target_type, *params;
	const char *tmp_uuid;
	void *next = NULL;
	int r = -EINVAL;

1126 1127
	if (dm_init_context(cd))
		return -ENOTSUP;
1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
	if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
		goto out;
	if ((dm_flags() & DM_SECURE_SUPPORTED) && !dm_task_secure_data(dmt))
		goto out;
	if (!dm_task_set_name(dmt, name))
		goto out;
	r = -ENODEV;
	if (!dm_task_run(dmt))
		goto out;

	r = -EINVAL;
	if (!dm_task_get_info(dmt, &dmi))
		goto out;

	if (!dmi.exists) {
		r = -ENODEV;
		goto out;
	}

	next = dm_get_next_target(dmt, next, &start, &length,
	                          &target_type, &params);

	if (!target_type || start != 0 || next)
		goto out;

1153
	if (!strcmp(target_type, DM_CRYPT_TARGET)) {
1154
		r = _dm_query_crypt(get_flags, &dmi, params, dmd);
1155
	} else if (!strcmp(target_type, DM_VERITY_TARGET)) {
1156
		r = _dm_query_verity(get_flags, &dmi, params, dmd);
1157 1158
		if (r < 0)
			goto out;
Milan Broz's avatar
Milan Broz committed
1159
		r = _dm_status_verity_ok(name);
1160 1161 1162 1163 1164 1165
		if (r < 0)
			goto out;
		if (r == 0)
			dmd->flags |= CRYPT_ACTIVATE_CORRUPTED;
		r = 0;
	} else
1166 1167 1168 1169 1170 1171 1172
		r = -EINVAL;

	if (r < 0)
		goto out;

	dmd->size = length;

1173 1174
	if (dmi.read_only)
		dmd->flags |= CRYPT_ACTIVATE_READONLY;
1175

1176
	tmp_uuid = dm_task_get_uuid(dmt);
1177 1178 1179 1180 1181 1182
	if (!tmp_uuid)
		dmd->flags |= CRYPT_ACTIVATE_NO_UUID;
	else if (get_flags & DM_ACTIVE_UUID) {
		if (!strncmp(tmp_uuid, DM_UUID_PREFIX, DM_UUID_PREFIX_LEN))
			dmd->uuid = strdup(tmp_uuid + DM_UUID_PREFIX_LEN);
	}
1183

1184
	r = (dmi.open_count > 0);
1185 1186 1187 1188
out:
	if (dmt)
		dm_task_destroy(dmt);

1189
	dm_exit_context();
1190
	return r;
1191 1192
}

1193 1194 1195 1196 1197 1198 1199 1200
static int _dm_message(const char *name, const char *msg)
{
	int r = 0;
	struct dm_task *dmt;

	if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG)))
		return 0;

1201
	if ((dm_flags() & DM_SECURE_SUPPORTED) && !dm_task_secure_data(dmt))
1202 1203
		goto out;

1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219
	if (name && !dm_task_set_name(dmt, name))
		goto out;

	if (!dm_task_set_sector(dmt, (uint64_t) 0))
		goto out;

	if (!dm_task_set_message(dmt, msg))
		goto out;

	r = dm_task_run(dmt);

      out:
	dm_task_destroy(dmt);
	return r;
}

Milan Broz's avatar
Milan Broz committed
1220
int dm_suspend_and_wipe_key(struct crypt_device *cd, const char *name)
1221
{
1222 1223 1224
	int r = -ENOTSUP;

	if (dm_init_context(cd))
1225 1226
		return -ENOTSUP;

1227
	if (!(_dm_crypt_flags & DM_KEY_WIPE_SUPPORTED))
1228
		goto out;
1229

1230 1231 1232 1233
	if (!_dm_simple(DM_DEVICE_SUSPEND, name, 0)) {
		r = -EINVAL;
		goto out;
	}
1234 1235

	if (!_dm_message(name, "key wipe")) {
1236
		_dm_simple(DM_DEVICE_RESUME, name, 1);
1237 1238
		r = -EINVAL;
		goto out;
1239
	}
1240 1241 1242 1243
	r = 0;
out:
	dm_exit_context();
	return r;
1244 1245
}

Milan Broz's avatar
Milan Broz committed
1246 1247
int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name,
				size_t key_size, const char *key)
1248 1249
{
	int msg_size = key_size * 2 + 10; // key set <key>
1250 1251
	char *msg = NULL;
	int r = -ENOTSUP;
1252

1253
	if (dm_init_context(cd))
1254 1255
		return -ENOTSUP;

1256
	if (!(_dm_crypt_flags & DM_KEY_WIPE_SUPPORTED))
1257
		goto out;
1258

1259
	msg = crypt_safe_alloc(msg_size);
1260 1261 1262 1263
	if (!msg) {
		r = -ENOMEM;
		goto out;
	}
1264 1265 1266 1267 1268

	strcpy(msg, "key set ");
	hex_key(&msg[8], key_size, key);

	if (!_dm_message(name, msg) ||
1269
	    !_dm_simple(DM_DEVICE_RESUME, name, 1)) {
1270
		r = -EINVAL;
1271 1272 1273 1274
		goto out;
	}
	r = 0;
out:
1275
	crypt_safe_free(msg);
1276
	dm_exit_context();
1277 1278 1279
	return r;
}

1280
const char *dm_get_dir(void)
1281 1282 1283
{
	return dm_dir();
}
1284

1285
int dm_is_dm_device(int major, int minor)
1286 1287 1288
{
	return dm_is_dm_major((uint32_t)major);
}
1289 1290 1291 1292 1293

int dm_is_dm_kernel_name(const char *name)
{
	return strncmp(name, "dm-", 3) ? 0 : 1;
}