1 #include <sys/ioctl.h> 2 #include <sys/stat.h> 3 #include <stdio.h> 4 #include <string.h> 5 #include <dirent.h> 6 #include <errno.h> 7 #include <libdevmapper.h> 8 #include <fcntl.h> 9 #include <uuid.h> 10 11 #include "internal.h" 12 #include "luks.h" 13 14 #define DEVICE_DIR "/dev" 15 #define DM_UUID_LEN 129 16 #define DM_UUID_PREFIX "CRYPT-" 17 #define DM_UUID_PREFIX_LEN 6 18 #define DM_CRYPT_TARGET "crypt" 19 #define RETRY_COUNT 5 20 21 /* Set if dm-crypt version was probed */ 22 static int _dm_crypt_checked = 0; 23 static int _dm_crypt_wipe_key_supported = 0; 24 25 static int _dm_use_count = 0; 26 static struct crypt_device *_context = NULL; 27 28 /* Compatibility for old device-mapper without udev support */ 29 #ifndef HAVE_DM_TASK_SET_COOKIE 30 #define CRYPT_TEMP_UDEV_FLAGS 0 31 #else 32 #define CRYPT_TEMP_UDEV_FLAGS DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG | \ 33 DM_UDEV_DISABLE_DISK_RULES_FLAG | \ 34 DM_UDEV_DISABLE_OTHER_RULES_FLAG 35 #endif 36 37 static int _dm_use_udev() 38 { 39 #ifdef USE_UDEV /* cannot be enabled if devmapper is too old */ 40 return dm_udev_get_sync_support(); 41 #else 42 return 0; 43 #endif 44 } 45 46 static void set_dm_error(int level, const char *file, int line, 47 const char *f, ...) 48 { 49 char *msg = NULL; 50 va_list va; 51 52 va_start(va, f); 53 if (vasprintf(&msg, f, va) > 0) { 54 if (level < 4) { 55 log_err(_context, msg); 56 log_err(_context, "\n"); 57 } else 58 log_dbg(msg); 59 } 60 free(msg); 61 va_end(va); 62 } 63 64 static int _dm_simple(int task, const char *name, int udev_wait); 65 66 static void _dm_set_crypt_compat(int maj, int min, int patch) 67 { 68 log_dbg("Detected dm-crypt target of version %i.%i.%i.", maj, min, patch); 69 70 if (maj >= 1 && min >=2) 71 _dm_crypt_wipe_key_supported = 1; 72 else 73 log_dbg("Suspend and resume disabled, no wipe key support."); 74 75 _dm_crypt_checked = 1; 76 } 77 78 static int _dm_check_versions(void) 79 { 80 struct dm_task *dmt; 81 struct dm_versions *target, *last_target; 82 83 if (_dm_crypt_checked) 84 return 1; 85 86 if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS))) 87 return 0; 88 89 if (!dm_task_run(dmt)) { 90 dm_task_destroy(dmt); 91 return 0; 92 } 93 94 target = dm_task_get_versions(dmt); 95 do { 96 last_target = target; 97 if (!strcmp(DM_CRYPT_TARGET, target->name)) { 98 _dm_set_crypt_compat((int)target->version[0], 99 (int)target->version[1], 100 (int)target->version[2]); 101 } 102 target = (void *) target + target->next; 103 } while (last_target != target); 104 105 dm_task_destroy(dmt); 106 return 1; 107 } 108 109 int dm_init(struct crypt_device *context, int check_kernel) 110 { 111 if (!_dm_use_count++) { 112 log_dbg("Initialising device-mapper backend%s, UDEV is %sabled.", 113 check_kernel ? "" : " (NO kernel check requested)", 114 _dm_use_udev() ? "en" : "dis"); 115 if (check_kernel && !_dm_check_versions()) { 116 log_err(context, _("Cannot initialize device-mapper. Is dm kernel module loaded?\n")); 117 return -1; 118 } 119 if (getuid() || geteuid()) 120 log_dbg(("WARNING: Running as a non-root user. Functionality may be unavailable.")); 121 dm_log_init(set_dm_error); 122 dm_log_init_verbose(10); 123 } 124 125 // FIXME: global context is not safe 126 if (context) 127 _context = context; 128 129 return 1; /* unsafe memory */ 130 } 131 132 void dm_exit(void) 133 { 134 if (_dm_use_count && (!--_dm_use_count)) { 135 log_dbg("Releasing device-mapper backend."); 136 dm_log_init_verbose(0); 137 dm_log_init(NULL); 138 dm_lib_release(); 139 _context = NULL; 140 } 141 } 142 143 static char *__lookup_dev(char *path, dev_t dev, int dir_level, const int max_level) 144 { 145 struct dirent *entry; 146 struct stat st; 147 char *ptr; 148 char *result = NULL; 149 DIR *dir; 150 int space; 151 152 /* Ignore strange nested directories */ 153 if (dir_level > max_level) 154 return NULL; 155 156 path[PATH_MAX - 1] = '\0'; 157 ptr = path + strlen(path); 158 *ptr++ = '/'; 159 *ptr = '\0'; 160 space = PATH_MAX - (ptr - path); 161 162 dir = opendir(path); 163 if (!dir) 164 return NULL; 165 166 while((entry = readdir(dir))) { 167 if (entry->d_name[0] == '.' || 168 !strncmp(entry->d_name, "..", 2)) 169 continue; 170 171 strncpy(ptr, entry->d_name, space); 172 if (stat(path, &st) < 0) 173 continue; 174 175 if (S_ISDIR(st.st_mode)) { 176 result = __lookup_dev(path, dev, dir_level + 1, max_level); 177 if (result) 178 break; 179 } else if (S_ISBLK(st.st_mode)) { 180 /* workaround: ignore dm-X devices, these are internal kernel names */ 181 if (dir_level == 0 && !strncmp(entry->d_name, "dm-", 3)) 182 continue; 183 if (st.st_rdev == dev) { 184 result = strdup(path); 185 break; 186 } 187 } 188 } 189 190 closedir(dir); 191 return result; 192 } 193 194 static char *lookup_dev(const char *dev_id) 195 { 196 uint32_t major, minor; 197 dev_t dev; 198 char *result = NULL, buf[PATH_MAX + 1]; 199 200 if (sscanf(dev_id, "%" PRIu32 ":%" PRIu32, &major, &minor) != 2) 201 return NULL; 202 203 dev = makedev(major, minor); 204 strncpy(buf, DEVICE_DIR, PATH_MAX); 205 buf[PATH_MAX] = '\0'; 206 207 /* First try low level device */ 208 if ((result = __lookup_dev(buf, dev, 0, 0))) 209 return result; 210 211 /* If it is dm, try DM dir */ 212 if (dm_is_dm_major(major)) { 213 strncpy(buf, dm_dir(), PATH_MAX); 214 if ((result = __lookup_dev(buf, dev, 0, 0))) 215 return result; 216 } 217 218 strncpy(buf, DEVICE_DIR, PATH_MAX); 219 result = __lookup_dev(buf, dev, 0, 4); 220 221 /* If not found, return NULL */ 222 return result; 223 } 224 225 static int _dev_read_ahead(const char *dev, uint32_t *read_ahead) 226 { 227 int fd, r = 0; 228 long read_ahead_long; 229 230 if ((fd = open(dev, O_RDONLY)) < 0) 231 return 0; 232 233 r = 0; 234 //r = ioctl(fd, BLKRAGET, &read_ahead_long) ? 0 : 1; 235 close(fd); 236 237 if (r) 238 *read_ahead = (uint32_t) read_ahead_long; 239 240 return r; 241 } 242 243 static void hex_key(char *hexkey, size_t key_size, const char *key) 244 { 245 int i; 246 247 for(i = 0; i < key_size; i++) 248 sprintf(&hexkey[i * 2], "%02x", (unsigned char)key[i]); 249 } 250 251 static char *get_params(const char *device, uint64_t skip, uint64_t offset, 252 const char *cipher, size_t key_size, const char *key) 253 { 254 char *params; 255 char *hexkey; 256 257 hexkey = safe_alloc(key_size * 2 + 1); 258 if (!hexkey) 259 return NULL; 260 261 hex_key(hexkey, key_size, key); 262 263 params = safe_alloc(strlen(hexkey) + strlen(cipher) + strlen(device) + 64); 264 if (!params) 265 goto out; 266 267 sprintf(params, "%s %s %" PRIu64 " %s %" PRIu64, 268 cipher, hexkey, skip, device, offset); 269 270 out: 271 safe_free(hexkey); 272 return params; 273 } 274 275 /* DM helpers */ 276 static int _dm_simple(int task, const char *name, int udev_wait) 277 { 278 int r = 0; 279 struct dm_task *dmt; 280 uint32_t cookie = 0; 281 282 if (!_dm_use_udev()) 283 udev_wait = 0; 284 285 if (!(dmt = dm_task_create(task))) 286 return 0; 287 288 if (name && !dm_task_set_name(dmt, name)) 289 goto out; 290 291 if (udev_wait && !dm_task_set_cookie(dmt, &cookie, 0)) 292 goto out; 293 294 r = dm_task_run(dmt); 295 296 if (udev_wait) 297 (void)dm_udev_wait(cookie); 298 299 out: 300 dm_task_destroy(dmt); 301 return r; 302 } 303 304 static int _error_device(const char *name, size_t size) 305 { 306 struct dm_task *dmt; 307 int r = 0; 308 309 if (!(dmt = dm_task_create(DM_DEVICE_RELOAD))) 310 return 0; 311 312 if (!dm_task_set_name(dmt, name)) 313 goto error; 314 315 if (!dm_task_add_target(dmt, UINT64_C(0), size, "error", "")) 316 goto error; 317 318 if (!dm_task_set_ro(dmt)) 319 goto error; 320 321 if (!dm_task_no_open_count(dmt)) 322 goto error; 323 324 if (!dm_task_run(dmt)) 325 goto error; 326 327 if (!_dm_simple(DM_DEVICE_RESUME, name, 1)) { 328 _dm_simple(DM_DEVICE_CLEAR, name, 0); 329 goto error; 330 } 331 332 r = 1; 333 334 error: 335 dm_task_destroy(dmt); 336 return r; 337 } 338 339 int dm_remove_device(const char *name, int force, uint64_t size) 340 { 341 int r = -EINVAL; 342 int retries = force ? RETRY_COUNT : 1; 343 int error_target = 0; 344 345 if (!name || (force && !size)) 346 return -EINVAL; 347 348 do { 349 r = _dm_simple(DM_DEVICE_REMOVE, name, 1) ? 0 : -EINVAL; 350 if (--retries && r) { 351 log_dbg("WARNING: other process locked internal device %s, %s.", 352 name, retries ? "retrying remove" : "giving up"); 353 if (force && (crypt_get_debug_level() == CRYPT_LOG_DEBUG)) 354 debug_processes_using_device(name); 355 sleep(1); 356 if (force && !error_target) { 357 /* If force flag is set, replace device with error, read-only target. 358 * it should stop processes from reading it and also removed underlying 359 * device from mapping, so it is usable again. 360 * Force flag should be used only for temporary devices, which are 361 * intended to work inside cryptsetup only! 362 * Anyway, if some process try to read temporary cryptsetup device, 363 * it is bug - no other process should try touch it (e.g. udev). 364 */ 365 _error_device(name, size); 366 error_target = 1; 367 } 368 } 369 } while (r == -EINVAL && retries); 370 371 dm_task_update_nodes(); 372 373 return r; 374 } 375 376 #define UUID_LEN 37 /* 36 + \0, libuuid ... */ 377 /* 378 * UUID has format: CRYPT-<devicetype>-[<uuid>-]<device name> 379 * CRYPT-PLAIN-name 380 * CRYPT-LUKS1-00000000000000000000000000000000-name 381 * CRYPT-TEMP-name 382 */ 383 static void dm_prepare_uuid(const char *name, const char *type, const char *uuid, char *buf, size_t buflen) 384 { 385 char *ptr, uuid2[UUID_LEN] = {0}; 386 uuid_t uu; 387 int i = 0; 388 uint32_t ret; 389 390 /* Remove '-' chars */ 391 if (uuid) { 392 uuid_from_string(uuid, &uu, &ret); 393 if (ret != uuid_s_ok) { 394 printf("error in uuid_from_string(%s), err = %d\n", uuid, ret); 395 for (ptr = uuid2, i = 0; i < UUID_LEN; i++) { 396 if (uuid[i] != '-') { 397 *ptr = uuid[i]; 398 ptr++; 399 } 400 } 401 } 402 } 403 404 i = snprintf(buf, buflen, DM_UUID_PREFIX "%s%s%s%s%s", 405 type ?: "", type ? "-" : "", 406 uuid2[0] ? uuid2 : "", uuid2[0] ? "-" : "", 407 name); 408 409 log_dbg("DM-UUID is %s", buf); 410 if (i >= buflen) 411 log_err(NULL, _("DM-UUID for device %s was truncated.\n"), name); 412 } 413 414 int dm_create_device(const char *name, 415 const char *device, 416 const char *cipher, 417 const char *type, 418 const char *uuid, 419 uint64_t size, 420 uint64_t skip, 421 uint64_t offset, 422 size_t key_size, 423 const char *key, 424 int read_only, 425 int reload) 426 { 427 struct dm_task *dmt = NULL; 428 struct dm_info dmi; 429 char *params = NULL; 430 char *error = NULL; 431 char dev_uuid[DM_UUID_LEN] = {0}; 432 int r = -EINVAL; 433 uint32_t read_ahead = 0; 434 uint32_t cookie = 0; 435 uint16_t udev_flags = 0; 436 437 params = get_params(device, skip, offset, cipher, key_size, key); 438 if (!params) 439 goto out_no_removal; 440 441 if (type && !strncmp(type, "TEMP", 4)) 442 udev_flags = CRYPT_TEMP_UDEV_FLAGS; 443 444 /* All devices must have DM_UUID, only resize on old device is exception */ 445 if (reload) { 446 if (!(dmt = dm_task_create(DM_DEVICE_RELOAD))) 447 goto out_no_removal; 448 449 if (!dm_task_set_name(dmt, name)) 450 goto out_no_removal; 451 } else { 452 dm_prepare_uuid(name, type, uuid, dev_uuid, sizeof(dev_uuid)); 453 454 if (!(dmt = dm_task_create(DM_DEVICE_CREATE))) 455 goto out_no_removal; 456 457 if (!dm_task_set_name(dmt, name)) 458 goto out_no_removal; 459 460 if (!dm_task_set_uuid(dmt, dev_uuid)) 461 goto out_no_removal; 462 463 if (_dm_use_udev() && !dm_task_set_cookie(dmt, &cookie, udev_flags)) 464 goto out_no_removal; 465 } 466 467 if (read_only && !dm_task_set_ro(dmt)) 468 goto out_no_removal; 469 if (!dm_task_add_target(dmt, 0, size, DM_CRYPT_TARGET, params)) 470 goto out_no_removal; 471 472 #ifdef DM_READ_AHEAD_MINIMUM_FLAG 473 if (_dev_read_ahead(device, &read_ahead) && 474 !dm_task_set_read_ahead(dmt, read_ahead, DM_READ_AHEAD_MINIMUM_FLAG)) 475 goto out_no_removal; 476 #endif 477 478 if (!dm_task_run(dmt)) 479 goto out_no_removal; 480 481 if (reload) { 482 dm_task_destroy(dmt); 483 if (!(dmt = dm_task_create(DM_DEVICE_RESUME))) 484 goto out; 485 if (!dm_task_set_name(dmt, name)) 486 goto out; 487 if (uuid && !dm_task_set_uuid(dmt, dev_uuid)) 488 goto out; 489 if (_dm_use_udev() && !dm_task_set_cookie(dmt, &cookie, udev_flags)) 490 goto out; 491 if (!dm_task_run(dmt)) 492 goto out; 493 } 494 495 if (!dm_task_get_info(dmt, &dmi)) 496 goto out; 497 498 r = 0; 499 out: 500 if (_dm_use_udev()) { 501 (void)dm_udev_wait(cookie); 502 cookie = 0; 503 } 504 505 if (r < 0 && !reload) { 506 if (get_error()) 507 error = strdup(get_error()); 508 509 dm_remove_device(name, 0, 0); 510 511 if (error) { 512 set_error(error); 513 free(error); 514 } 515 } 516 517 out_no_removal: 518 if (cookie && _dm_use_udev()) 519 (void)dm_udev_wait(cookie); 520 521 if (params) 522 safe_free(params); 523 if (dmt) 524 dm_task_destroy(dmt); 525 526 dm_task_update_nodes(); 527 return r; 528 } 529 530 int dm_status_device(const char *name) 531 { 532 struct dm_task *dmt; 533 struct dm_info dmi; 534 uint64_t start, length; 535 char *target_type, *params; 536 void *next = NULL; 537 int r = -EINVAL; 538 539 if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) 540 return -EINVAL; 541 542 if (!dm_task_set_name(dmt, name)) { 543 r = -EINVAL; 544 goto out; 545 } 546 547 if (!dm_task_run(dmt)) { 548 r = -EINVAL; 549 goto out; 550 } 551 552 if (!dm_task_get_info(dmt, &dmi)) { 553 r = -EINVAL; 554 goto out; 555 } 556 557 if (!dmi.exists) { 558 r = -ENODEV; 559 goto out; 560 } 561 562 next = dm_get_next_target(dmt, next, &start, &length, 563 &target_type, ¶ms); 564 if (!target_type || strcmp(target_type, DM_CRYPT_TARGET) != 0 || 565 start != 0 || next) 566 r = -EINVAL; 567 else 568 r = (dmi.open_count > 0); 569 out: 570 if (dmt) 571 dm_task_destroy(dmt); 572 573 return r; 574 } 575 576 int dm_query_device(const char *name, 577 char **device, 578 uint64_t *size, 579 uint64_t *skip, 580 uint64_t *offset, 581 char **cipher, 582 int *key_size, 583 char **key, 584 int *read_only, 585 int *suspended, 586 char **uuid) 587 { 588 struct dm_task *dmt; 589 struct dm_info dmi; 590 uint64_t start, length, val64; 591 char *target_type, *params, *rcipher, *key_, *rdevice, *endp, buffer[3], *tmp_uuid; 592 void *next = NULL; 593 int i, r = -EINVAL; 594 595 if (!(dmt = dm_task_create(DM_DEVICE_TABLE))) 596 goto out; 597 if (!dm_task_set_name(dmt, name)) 598 goto out; 599 r = -ENODEV; 600 if (!dm_task_run(dmt)) 601 goto out; 602 603 r = -EINVAL; 604 if (!dm_task_get_info(dmt, &dmi)) 605 goto out; 606 607 if (!dmi.exists) { 608 r = -ENODEV; 609 goto out; 610 } 611 612 next = dm_get_next_target(dmt, next, &start, &length, 613 &target_type, ¶ms); 614 if (!target_type || strcmp(target_type, DM_CRYPT_TARGET) != 0 || 615 start != 0 || next) 616 goto out; 617 618 if (size) 619 *size = length; 620 621 rcipher = strsep(¶ms, " "); 622 /* cipher */ 623 if (cipher) 624 *cipher = strdup(rcipher); 625 626 /* skip */ 627 key_ = strsep(¶ms, " "); 628 if (!params) 629 goto out; 630 val64 = strtoull(params, ¶ms, 10); 631 if (*params != ' ') 632 goto out; 633 params++; 634 if (skip) 635 *skip = val64; 636 637 /* device */ 638 rdevice = strsep(¶ms, " "); 639 if (device) 640 *device = lookup_dev(rdevice); 641 642 /*offset */ 643 if (!params) 644 goto out; 645 val64 = strtoull(params, ¶ms, 10); 646 if (*params) 647 goto out; 648 if (offset) 649 *offset = val64; 650 651 /* key_size */ 652 if (key_size) 653 *key_size = strlen(key_) / 2; 654 655 /* key */ 656 if (key_size && key) { 657 *key = safe_alloc(*key_size); 658 if (!*key) { 659 r = -ENOMEM; 660 goto out; 661 } 662 663 buffer[2] = '\0'; 664 for(i = 0; i < *key_size; i++) { 665 memcpy(buffer, &key_[i * 2], 2); 666 (*key)[i] = strtoul(buffer, &endp, 16); 667 if (endp != &buffer[2]) { 668 safe_free(key); 669 *key = NULL; 670 goto out; 671 } 672 } 673 } 674 memset(key_, 0, strlen(key_)); 675 676 if (read_only) 677 *read_only = dmi.read_only; 678 679 if (suspended) 680 *suspended = dmi.suspended; 681 682 if (uuid && (tmp_uuid = (char*)dm_task_get_uuid(dmt)) && 683 !strncmp(tmp_uuid, DM_UUID_PREFIX, DM_UUID_PREFIX_LEN)) 684 *uuid = strdup(tmp_uuid + DM_UUID_PREFIX_LEN); 685 686 r = (dmi.open_count > 0); 687 out: 688 if (dmt) 689 dm_task_destroy(dmt); 690 691 return r; 692 } 693 694 static int _dm_message(const char *name, const char *msg) 695 { 696 int r = 0; 697 struct dm_task *dmt; 698 699 if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG))) 700 return 0; 701 702 if (name && !dm_task_set_name(dmt, name)) 703 goto out; 704 705 if (!dm_task_set_sector(dmt, (uint64_t) 0)) 706 goto out; 707 708 if (!dm_task_set_message(dmt, msg)) 709 goto out; 710 711 r = dm_task_run(dmt); 712 713 out: 714 dm_task_destroy(dmt); 715 return r; 716 } 717 718 int dm_suspend_and_wipe_key(const char *name) 719 { 720 if (!_dm_check_versions()) 721 return -ENOTSUP; 722 723 if (!_dm_crypt_wipe_key_supported) 724 return -ENOTSUP; 725 726 if (!_dm_simple(DM_DEVICE_SUSPEND, name, 0)) 727 return -EINVAL; 728 729 if (!_dm_message(name, "key wipe")) { 730 _dm_simple(DM_DEVICE_RESUME, name, 1); 731 return -EINVAL; 732 } 733 734 return 0; 735 } 736 737 int dm_resume_and_reinstate_key(const char *name, 738 size_t key_size, 739 const char *key) 740 { 741 int msg_size = key_size * 2 + 10; // key set <key> 742 char *msg; 743 int r = 0; 744 745 if (!_dm_check_versions()) 746 return -ENOTSUP; 747 748 if (!_dm_crypt_wipe_key_supported) 749 return -ENOTSUP; 750 751 msg = safe_alloc(msg_size); 752 if (!msg) 753 return -ENOMEM; 754 755 memset(msg, 0, msg_size); 756 strcpy(msg, "key set "); 757 hex_key(&msg[8], key_size, key); 758 759 if (!_dm_message(name, msg) || 760 !_dm_simple(DM_DEVICE_RESUME, name, 1)) 761 r = -EINVAL; 762 763 safe_free(msg); 764 return r; 765 } 766 767 const char *dm_get_dir(void) 768 { 769 return dm_dir(); 770 } 771