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