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_mod 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 uuid_from_string(uuid, &uu, ret); 392 if (uuid && ret != uuid_s_ok) { 393 printf("crap happened in uuid_from_string(%s), err = %d\n", uuid, ret); 394 for (ptr = uuid2, i = 0; i < UUID_LEN; i++) 395 if (uuid[i] != '-') { 396 *ptr = uuid[i]; 397 ptr++; 398 } 399 } else { 400 printf("went well in uuid_from_string(%s), err = %d\n", uuid, ret); 401 } 402 403 i = snprintf(buf, buflen, DM_UUID_PREFIX "%s%s%s%s%s", 404 type ?: "", type ? "-" : "", 405 uuid2[0] ? uuid2 : "", uuid2[0] ? "-" : "", 406 name); 407 408 log_dbg("DM-UUID is %s", buf); 409 if (i >= buflen) 410 log_err(NULL, _("DM-UUID for device %s was truncated.\n"), name); 411 } 412 413 int dm_create_device(const char *name, 414 const char *device, 415 const char *cipher, 416 const char *type, 417 const char *uuid, 418 uint64_t size, 419 uint64_t skip, 420 uint64_t offset, 421 size_t key_size, 422 const char *key, 423 int read_only, 424 int reload) 425 { 426 struct dm_task *dmt = NULL; 427 struct dm_info dmi; 428 char *params = NULL; 429 char *error = NULL; 430 char dev_uuid[DM_UUID_LEN] = {0}; 431 int r = -EINVAL; 432 uint32_t read_ahead = 0; 433 uint32_t cookie = 0; 434 uint16_t udev_flags = 0; 435 436 params = get_params(device, skip, offset, cipher, key_size, key); 437 if (!params) 438 goto out_no_removal; 439 440 if (type && !strncmp(type, "TEMP", 4)) 441 udev_flags = CRYPT_TEMP_UDEV_FLAGS; 442 443 /* All devices must have DM_UUID, only resize on old device is exception */ 444 if (reload) { 445 if (!(dmt = dm_task_create(DM_DEVICE_RELOAD))) 446 goto out_no_removal; 447 448 if (!dm_task_set_name(dmt, name)) 449 goto out_no_removal; 450 } else { 451 dm_prepare_uuid(name, type, uuid, dev_uuid, sizeof(dev_uuid)); 452 453 if (!(dmt = dm_task_create(DM_DEVICE_CREATE))) 454 goto out_no_removal; 455 456 if (!dm_task_set_name(dmt, name)) 457 goto out_no_removal; 458 459 if (!dm_task_set_uuid(dmt, dev_uuid)) 460 goto out_no_removal; 461 462 if (_dm_use_udev() && !dm_task_set_cookie(dmt, &cookie, udev_flags)) 463 goto out_no_removal; 464 } 465 466 if (read_only && !dm_task_set_ro(dmt)) 467 goto out_no_removal; 468 if (!dm_task_add_target(dmt, 0, size, DM_CRYPT_TARGET, params)) 469 goto out_no_removal; 470 471 #ifdef DM_READ_AHEAD_MINIMUM_FLAG 472 if (_dev_read_ahead(device, &read_ahead) && 473 !dm_task_set_read_ahead(dmt, read_ahead, DM_READ_AHEAD_MINIMUM_FLAG)) 474 goto out_no_removal; 475 #endif 476 477 if (!dm_task_run(dmt)) 478 goto out_no_removal; 479 480 if (reload) { 481 dm_task_destroy(dmt); 482 if (!(dmt = dm_task_create(DM_DEVICE_RESUME))) 483 goto out; 484 if (!dm_task_set_name(dmt, name)) 485 goto out; 486 if (uuid && !dm_task_set_uuid(dmt, dev_uuid)) 487 goto out; 488 if (_dm_use_udev() && !dm_task_set_cookie(dmt, &cookie, udev_flags)) 489 goto out; 490 if (!dm_task_run(dmt)) 491 goto out; 492 } 493 494 if (!dm_task_get_info(dmt, &dmi)) 495 goto out; 496 497 r = 0; 498 out: 499 if (_dm_use_udev()) { 500 (void)dm_udev_wait(cookie); 501 cookie = 0; 502 } 503 504 if (r < 0 && !reload) { 505 if (get_error()) 506 error = strdup(get_error()); 507 508 dm_remove_device(name, 0, 0); 509 510 if (error) { 511 set_error(error); 512 free(error); 513 } 514 } 515 516 out_no_removal: 517 if (cookie && _dm_use_udev()) 518 (void)dm_udev_wait(cookie); 519 520 if (params) 521 safe_free(params); 522 if (dmt) 523 dm_task_destroy(dmt); 524 525 dm_task_update_nodes(); 526 return r; 527 } 528 529 int dm_status_device(const char *name) 530 { 531 struct dm_task *dmt; 532 struct dm_info dmi; 533 uint64_t start, length; 534 char *target_type, *params; 535 void *next = NULL; 536 int r = -EINVAL; 537 538 if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) 539 return -EINVAL; 540 541 if (!dm_task_set_name(dmt, name)) { 542 r = -EINVAL; 543 goto out; 544 } 545 546 if (!dm_task_run(dmt)) { 547 r = -EINVAL; 548 goto out; 549 } 550 551 if (!dm_task_get_info(dmt, &dmi)) { 552 r = -EINVAL; 553 goto out; 554 } 555 556 if (!dmi.exists) { 557 r = -ENODEV; 558 goto out; 559 } 560 561 next = dm_get_next_target(dmt, next, &start, &length, 562 &target_type, ¶ms); 563 if (!target_type || strcmp(target_type, DM_CRYPT_TARGET) != 0 || 564 start != 0 || next) 565 r = -EINVAL; 566 else 567 r = (dmi.open_count > 0); 568 out: 569 if (dmt) 570 dm_task_destroy(dmt); 571 572 return r; 573 } 574 575 int dm_query_device(const char *name, 576 char **device, 577 uint64_t *size, 578 uint64_t *skip, 579 uint64_t *offset, 580 char **cipher, 581 int *key_size, 582 char **key, 583 int *read_only, 584 int *suspended, 585 char **uuid) 586 { 587 struct dm_task *dmt; 588 struct dm_info dmi; 589 uint64_t start, length, val64; 590 char *target_type, *params, *rcipher, *key_, *rdevice, *endp, buffer[3], *tmp_uuid; 591 void *next = NULL; 592 int i, r = -EINVAL; 593 594 if (!(dmt = dm_task_create(DM_DEVICE_TABLE))) 595 goto out; 596 if (!dm_task_set_name(dmt, name)) 597 goto out; 598 r = -ENODEV; 599 if (!dm_task_run(dmt)) 600 goto out; 601 602 r = -EINVAL; 603 if (!dm_task_get_info(dmt, &dmi)) 604 goto out; 605 606 if (!dmi.exists) { 607 r = -ENODEV; 608 goto out; 609 } 610 611 next = dm_get_next_target(dmt, next, &start, &length, 612 &target_type, ¶ms); 613 if (!target_type || strcmp(target_type, DM_CRYPT_TARGET) != 0 || 614 start != 0 || next) 615 goto out; 616 617 if (size) 618 *size = length; 619 620 rcipher = strsep(¶ms, " "); 621 /* cipher */ 622 if (cipher) 623 *cipher = strdup(rcipher); 624 625 /* skip */ 626 key_ = strsep(¶ms, " "); 627 if (!params) 628 goto out; 629 val64 = strtoull(params, ¶ms, 10); 630 if (*params != ' ') 631 goto out; 632 params++; 633 if (skip) 634 *skip = val64; 635 636 /* device */ 637 rdevice = strsep(¶ms, " "); 638 if (device) 639 *device = lookup_dev(rdevice); 640 641 /*offset */ 642 if (!params) 643 goto out; 644 val64 = strtoull(params, ¶ms, 10); 645 if (*params) 646 goto out; 647 if (offset) 648 *offset = val64; 649 650 /* key_size */ 651 if (key_size) 652 *key_size = strlen(key_) / 2; 653 654 /* key */ 655 if (key_size && key) { 656 *key = safe_alloc(*key_size); 657 if (!*key) { 658 r = -ENOMEM; 659 goto out; 660 } 661 662 buffer[2] = '\0'; 663 for(i = 0; i < *key_size; i++) { 664 memcpy(buffer, &key_[i * 2], 2); 665 (*key)[i] = strtoul(buffer, &endp, 16); 666 if (endp != &buffer[2]) { 667 safe_free(key); 668 *key = NULL; 669 goto out; 670 } 671 } 672 } 673 memset(key_, 0, strlen(key_)); 674 675 if (read_only) 676 *read_only = dmi.read_only; 677 678 if (suspended) 679 *suspended = dmi.suspended; 680 681 if (uuid && (tmp_uuid = (char*)dm_task_get_uuid(dmt)) && 682 !strncmp(tmp_uuid, DM_UUID_PREFIX, DM_UUID_PREFIX_LEN)) 683 *uuid = strdup(tmp_uuid + DM_UUID_PREFIX_LEN); 684 685 r = (dmi.open_count > 0); 686 out: 687 if (dmt) 688 dm_task_destroy(dmt); 689 690 return r; 691 } 692 693 static int _dm_message(const char *name, const char *msg) 694 { 695 int r = 0; 696 struct dm_task *dmt; 697 698 if (!(dmt = dm_task_create(DM_DEVICE_TARGET_MSG))) 699 return 0; 700 701 if (name && !dm_task_set_name(dmt, name)) 702 goto out; 703 704 if (!dm_task_set_sector(dmt, (uint64_t) 0)) 705 goto out; 706 707 if (!dm_task_set_message(dmt, msg)) 708 goto out; 709 710 r = dm_task_run(dmt); 711 712 out: 713 dm_task_destroy(dmt); 714 return r; 715 } 716 717 int dm_suspend_and_wipe_key(const char *name) 718 { 719 if (!_dm_check_versions()) 720 return -ENOTSUP; 721 722 if (!_dm_crypt_wipe_key_supported) 723 return -ENOTSUP; 724 725 if (!_dm_simple(DM_DEVICE_SUSPEND, name, 0)) 726 return -EINVAL; 727 728 if (!_dm_message(name, "key wipe")) { 729 _dm_simple(DM_DEVICE_RESUME, name, 1); 730 return -EINVAL; 731 } 732 733 return 0; 734 } 735 736 int dm_resume_and_reinstate_key(const char *name, 737 size_t key_size, 738 const char *key) 739 { 740 int msg_size = key_size * 2 + 10; // key set <key> 741 char *msg; 742 int r = 0; 743 744 if (!_dm_check_versions()) 745 return -ENOTSUP; 746 747 if (!_dm_crypt_wipe_key_supported) 748 return -ENOTSUP; 749 750 msg = safe_alloc(msg_size); 751 if (!msg) 752 return -ENOMEM; 753 754 memset(msg, 0, msg_size); 755 strcpy(msg, "key set "); 756 hex_key(&msg[8], key_size, key); 757 758 if (!_dm_message(name, msg) || 759 !_dm_simple(DM_DEVICE_RESUME, name, 1)) 760 r = -EINVAL; 761 762 safe_free(msg); 763 return r; 764 } 765 766 const char *dm_get_dir(void) 767 { 768 return dm_dir(); 769 } 770