Makefile: Add security compiling option (RELRO, SC, and FORTIFY)
[platform/upstream/cryptsetup.git] / tests / test_utils.c
1 /*
2  * cryptsetup library API test utilities
3  *
4  * Copyright (C) 2009-2023 Red Hat, Inc. All rights reserved.
5  * Copyright (C) 2009-2023 Milan Broz
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include <assert.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <inttypes.h>
26 #include <stdlib.h>
27 #include <libdevmapper.h>
28 #include <linux/fs.h>
29 #include <sys/ioctl.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 #ifdef KERNEL_KEYRING
34 # include <linux/keyctl.h>
35 # include <sys/syscall.h>
36 #endif
37 #ifdef HAVE_SYS_SYSMACROS_H
38 # include <sys/sysmacros.h>
39 #endif
40 #include <linux/loop.h>
41
42 #include "api_test.h"
43 #include "libcryptsetup.h"
44
45 #ifndef LOOP_CONFIGURE
46 #define LOOP_CONFIGURE 0x4C0A
47 struct loop_config {
48   __u32 fd;
49   __u32 block_size;
50   struct loop_info64 info;
51   __u64 __reserved[8];
52 };
53 #endif
54
55 static char last_error[256];
56 static char global_log[4096];
57 static uint32_t t_dm_crypt_flags = 0;
58
59 char *THE_LOOP_DEV = NULL;
60 int _debug   = 0;
61 int global_lines = 0;
62 int _quit = 0;
63 int _verbose = 0;
64 uint64_t t_dev_offset = 0;
65
66 static void (*_cleanup)(void);
67
68 void register_cleanup(void (*cleanup)(void))
69 {
70         _cleanup = cleanup;
71 }
72
73 void check_ok(int status, int line, const char *func)
74 {
75         if (status) {
76                 printf("FAIL line %d [%s]: code %d, %s\n", line, func, status, last_error);
77                 _cleanup();
78                 exit(-1);
79         }
80 }
81
82 void check_ok_return(int status, int line, const char *func)
83 {
84         if (status < 0) {
85                 printf("FAIL line %d [%s]: code %d, %s\n", line, func, status, last_error);
86                 _cleanup();
87                 exit(-1);
88         }
89 }
90
91 void check_ko(int status, int line, const char *func)
92 {
93         if (status >= 0) {
94                 printf("FAIL line %d [%s]: code %d, %s\n", line, func, status, last_error);
95                 _cleanup();
96                 exit(-1);
97         } else if (_verbose)
98                 printf("   => errno %d, errmsg: %s\n", status, last_error);
99 }
100
101 void check_equal(int line, const char *func, int64_t x, int64_t y)
102 {
103         printf("FAIL line %d [%s]: expected equal values differs: %"
104                 PRIi64 " != %" PRIi64 "\n", line, func, x, y);
105         _cleanup();
106         exit(-1);
107 }
108
109 void check_ge_equal(int line, const char *func, int64_t x, int64_t y)
110 {
111         printf("FAIL line %d [%s]: expected greater or equal values differs: %"
112                 PRIi64 " < %" PRIi64 "\n", line, func, x, y);
113         _cleanup();
114         exit(-1);
115 }
116
117 void check_null(int line, const char *func, const void *x)
118 {
119         if (x) {
120                 printf("FAIL line %d [%s]: expected NULL value: %p\n", line, func, x);
121                 _cleanup();
122                 exit(-1);
123         }
124 }
125
126 void check_notnull(int line, const char *func, const void *x)
127 {
128         if (!x) {
129                 printf("FAIL line %d [%s]: expected not NULL value: %p\n", line, func, x);
130                 _cleanup();
131                 exit(-1);
132         }
133 }
134
135 void xlog(const char *msg, const char *tst, const char *func, int line, const char *txt)
136 {
137         if (_verbose) {
138                 if (txt)
139                         printf(" [%s,%s:%d] %s [%s]\n", msg, func, line, tst, txt);
140                 else
141                         printf(" [%s,%s:%d] %s\n", msg, func, line, tst);
142         }
143         if (_quit) {
144                 if (_verbose)
145                         printf("Interrupted by a signal.\n");
146                 _cleanup();
147                 exit(-1);
148         }
149 }
150
151 int t_device_size(const char *device, uint64_t *size)
152 {
153         int devfd, r = 0;
154
155         devfd = open(device, O_RDONLY);
156         if(devfd == -1)
157                 return -EINVAL;
158
159         if (ioctl(devfd, BLKGETSIZE64, size) < 0)
160                 r = -EINVAL;
161         close(devfd);
162         return r;
163 }
164
165 int t_set_readahead(const char *device, unsigned value)
166 {
167         int devfd, r = 0;
168
169         devfd = open(device, O_RDONLY);
170         if(devfd == -1)
171                 return -EINVAL;
172
173         if (ioctl(devfd, BLKRASET, value) < 0)
174                 r = -EINVAL;
175         close(devfd);
176         return r;
177 }
178
179 int fips_mode(void)
180 {
181         int fd;
182         char buf = 0;
183
184         fd = open("/proc/sys/crypto/fips_enabled", O_RDONLY);
185
186         if (fd < 0)
187                 return 0;
188
189         if (read(fd, &buf, 1) != 1)
190                 buf = '0';
191
192         close(fd);
193
194         return (buf == '1');
195 }
196
197 /*
198  * Creates dm-linear target over the test loop device. Offset is held in
199  * global variables so that size can be tested whether it fits into remaining
200  * size of the loop device or not
201  */
202 int create_dmdevice_over_loop(const char *dm_name, const uint64_t size)
203 {
204         char cmd[128];
205         int r;
206         uint64_t r_size;
207
208         if (t_device_size(THE_LOOP_DEV, &r_size) < 0 || r_size <= t_dev_offset || !size)
209                 return -1;
210         if ((r_size - t_dev_offset) < size) {
211                 printf("No enough space on backing loop device\n.");
212                 return -2;
213         }
214         r = snprintf(cmd, sizeof(cmd),
215                      "dmsetup create %s --table \"0 %" PRIu64 " linear %s %" PRIu64 "\"",
216                      dm_name, size, THE_LOOP_DEV, t_dev_offset);
217         if (r < 0 || (size_t)r >= sizeof(cmd))
218                 return -3;
219
220         if (!(r = _system(cmd, 1)))
221                 t_dev_offset += size;
222         return r;
223 }
224
225 __attribute__((format(printf, 3, 4)))
226 static int _snprintf(char **r_ptr, size_t *r_remains, const char *format, ...)
227 {
228         int len, r = 0;
229         va_list argp;
230
231         assert(r_remains);
232         assert(r_ptr);
233
234         va_start(argp, format);
235
236         len = vsnprintf(*r_ptr, *r_remains, format, argp);
237         if (len < 0 || (size_t)len >= *r_remains) {
238                 r = -EINVAL;
239         } else {
240                 *r_ptr += len;
241                 *r_remains -= len;
242         }
243
244         va_end(argp);
245
246         return r;
247 }
248
249 int dmdevice_error_io(const char *dm_name,
250         const char *dm_device,
251         const char *error_device,
252         uint64_t data_offset,
253         uint64_t offset,
254         uint64_t length,
255         error_io_info ei)
256 {
257         char str[256], cmd[384];
258         int r;
259         uint64_t dev_size;
260         size_t remains;
261         char *ptr;
262
263         if (t_device_size(dm_device, &dev_size) < 0 || !length)
264                 return -1;
265
266         dev_size >>= TST_SECTOR_SHIFT;
267
268         if (dev_size <= offset)
269                 return -1;
270
271         if (ei == ERR_REMOVE) {
272                 r = snprintf(cmd, sizeof(cmd),
273                              "dmsetup load %s --table \"0 %" PRIu64 " linear %s %" PRIu64 "\"",
274                              dm_name, dev_size, THE_LOOP_DEV, data_offset);
275                 if (r < 0 || (size_t)r >= sizeof(str))
276                         return -3;
277
278                 if ((r = _system(cmd, 1)))
279                         return r;
280
281                 r = snprintf(cmd, sizeof(cmd), "dmsetup resume %s", dm_name);
282                 if (r < 0 || (size_t)r >= sizeof(cmd))
283                         return -3;
284
285                 return _system(cmd, 1);
286         }
287
288         if ((dev_size - offset) < length) {
289                 printf("Not enough space on target device\n.");
290                 return -2;
291         }
292
293         remains = sizeof(str);
294         ptr = str;
295
296         if (offset) {
297                 r = _snprintf(&ptr, &remains,
298                              "0 %" PRIu64 " linear %s %" PRIu64 "\n",
299                              offset, THE_LOOP_DEV, data_offset);
300                 if (r < 0)
301                         return r;
302         }
303         r = _snprintf(&ptr, &remains, "%" PRIu64 " %" PRIu64 " delay ",
304                       offset, length);
305         if (r < 0)
306                 return r;
307
308         if (ei == ERR_RW || ei == ERR_RD) {
309                 r = _snprintf(&ptr, &remains, "%s 0 0",
310                              error_device);
311                 if (r < 0)
312                         return r;
313                 if (ei == ERR_RD) {
314                         r = _snprintf(&ptr, &remains, " %s %" PRIu64 " 0",
315                                      THE_LOOP_DEV, data_offset + offset);
316                         if (r < 0)
317                                 return r;
318                 }
319         } else if (ei == ERR_WR) {
320                 r = _snprintf(&ptr, &remains, "%s %" PRIu64 " 0 %s 0 0",
321                              THE_LOOP_DEV, data_offset + offset, error_device);
322                 if (r < 0)
323                         return r;
324         }
325
326         if (dev_size > (offset + length)) {
327                 r = _snprintf(&ptr, &remains,
328                              "\n%" PRIu64 " %" PRIu64 " linear %s %" PRIu64,
329                              offset + length, dev_size - offset - length, THE_LOOP_DEV,
330                              data_offset + offset + length);
331                 if (r < 0)
332                         return r;
333         }
334
335         /*
336          * Hello darkness, my old friend...
337          *
338          * On few old distributions there's issue with
339          * processing multiline tables via dmsetup load --table.
340          * This workaround passes on all systems we run tests on.
341          */
342         r = snprintf(cmd, sizeof(cmd), "dmsetup load %s <<EOF\n%s\nEOF", dm_name, str);
343         if (r < 0 || (size_t)r >= sizeof(cmd))
344                 return -3;
345
346         if ((r = _system(cmd, 1)))
347                 return r;
348
349         r = snprintf(cmd, sizeof(cmd), "dmsetup resume %s", dm_name);
350         if (r < 0 || (size_t)r >= sizeof(cmd))
351                 return -3;
352
353         if ((r = _system(cmd, 1)))
354                 return r;
355
356         return t_set_readahead(dm_device, 0);
357 }
358
359 // Get key from kernel dm mapping table using dm-ioctl
360 int get_key_dm(const char *name, char *buffer, unsigned int buffer_size)
361 {
362         struct dm_task *dmt;
363         struct dm_info dmi;
364         uint64_t start, length;
365         char *target_type, *key, *params;
366         int r = -EINVAL;
367
368         if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
369                 goto out;
370         if (!dm_task_set_name(dmt, name))
371                 goto out;
372         if (!dm_task_run(dmt))
373                 goto out;
374         if (!dm_task_get_info(dmt, &dmi))
375                 goto out;
376         if (!dmi.exists)
377                 goto out;
378
379         dm_get_next_target(dmt, NULL, &start, &length, &target_type, &params);
380         if (!target_type || strcmp(target_type, "crypt") != 0)
381                 goto out;
382
383         (void)strsep(&params, " "); /* rcipher */
384         key = strsep(&params, " ");
385
386         if (buffer_size <= strlen(key))
387                 goto out;
388
389         strncpy(buffer, key, buffer_size);
390         r = 0;
391 out:
392         if (dmt)
393                 dm_task_destroy(dmt);
394
395         return r;
396 }
397
398 int prepare_keyfile(const char *name, const char *passphrase, int size)
399 {
400         int fd, r;
401
402         fd = open(name, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR|S_IWUSR);
403         if (fd != -1) {
404                 r = write(fd, passphrase, size);
405                 close(fd);
406         } else
407                 r = 0;
408
409         return r == size ? 0 : 1;
410 }
411
412 // Decode key from its hex representation
413 int crypt_decode_key(char *key, const char *hex, unsigned int size)
414 {
415         char buffer[3];
416         char *endp;
417         unsigned int i;
418
419         buffer[2] = '\0';
420
421         for (i = 0; i < size; i++) {
422                 buffer[0] = *hex++;
423                 buffer[1] = *hex++;
424
425                 key[i] = (unsigned char)strtoul(buffer, &endp, 16);
426
427                 if (endp != &buffer[2])
428                         return -1;
429         }
430
431         if (*hex != '\0')
432                 return -1;
433
434         return 0;
435 }
436
437 void global_log_callback(int level, const char *msg, void *usrptr __attribute__((unused)))
438 {
439         size_t len;
440
441         if (_debug) {
442                 if (level == CRYPT_LOG_DEBUG)
443                         fprintf(stdout, "# %s", msg);
444                 else
445                         fprintf(stdout, "%s", msg);
446         }
447
448         if (level <= CRYPT_LOG_DEBUG)
449                 return;
450
451         len = strlen(global_log);
452
453         if (len + strlen(msg) > sizeof(global_log)) {
454                         printf("Log buffer is too small, fix the test.\n");
455                         return;
456         }
457
458         strncat(global_log, msg, sizeof(global_log) - len);
459         global_lines++;
460         if (level == CRYPT_LOG_ERROR) {
461                 len = strlen(msg);
462                 if (len > sizeof(last_error))
463                         len = sizeof(last_error);
464                 strncpy(last_error, msg, sizeof(last_error));
465                 last_error[len-1] = '\0';
466         }
467 }
468
469 void reset_log(void)
470 {
471         memset(global_log, 0, sizeof(global_log));
472         memset(last_error, 0, sizeof(last_error));
473         global_lines = 0;
474 }
475
476 int _system(const char *command, int warn)
477 {
478         int r;
479         if (_debug)
480                 printf("Running system: %s\n", command);
481         if ((r=system(command)) < 0 && warn)
482                 printf("System command failed: %s", command);
483         return r;
484 }
485
486 static int _keyring_check(void)
487 {
488 #ifdef KERNEL_KEYRING
489         return syscall(__NR_request_key, "logon", "dummy", NULL, 0) == -1l && errno != ENOSYS;
490 #else
491         return 0;
492 #endif
493 }
494
495 static int t_dm_satisfies_version(unsigned target_maj, unsigned target_min, unsigned target_patch,
496                                  unsigned actual_maj, unsigned actual_min, unsigned actual_patch)
497 {
498         if (actual_maj > target_maj)
499                 return 1;
500         if (actual_maj == target_maj && actual_min > target_min)
501                 return 1;
502         if (actual_maj == target_maj && actual_min == target_min && actual_patch >= target_patch)
503                 return 1;
504         return 0;
505 }
506
507 static void t_dm_set_crypt_compat(const char *dm_version, unsigned crypt_maj,
508                                  unsigned crypt_min, unsigned crypt_patch)
509 {
510         unsigned dm_maj = 0, dm_min = 0, dm_patch = 0;
511
512         if (sscanf(dm_version, "%u.%u.%u", &dm_maj, &dm_min, &dm_patch) != 3) {
513                 dm_maj = 0;
514                 dm_min = 0;
515                 dm_patch = 0;
516         }
517
518         if (t_dm_satisfies_version(1, 2, 0, crypt_maj, crypt_min, 0))
519                 t_dm_crypt_flags |= T_DM_KEY_WIPE_SUPPORTED;
520
521         if (t_dm_satisfies_version(1, 10, 0, crypt_maj, crypt_min, 0))
522                 t_dm_crypt_flags |= T_DM_LMK_SUPPORTED;
523
524         if (t_dm_satisfies_version(4, 20, 0, dm_maj, dm_min, 0))
525                 t_dm_crypt_flags |= T_DM_SECURE_SUPPORTED;
526
527         if (t_dm_satisfies_version(1, 8, 0, crypt_maj, crypt_min, 0))
528                 t_dm_crypt_flags |= T_DM_PLAIN64_SUPPORTED;
529
530         if (t_dm_satisfies_version(1, 11, 0, crypt_maj, crypt_min, 0))
531                 t_dm_crypt_flags |= T_DM_DISCARDS_SUPPORTED;
532
533         if (t_dm_satisfies_version(1, 13, 0, crypt_maj, crypt_min, 0))
534                 t_dm_crypt_flags |= T_DM_TCW_SUPPORTED;
535
536         if (t_dm_satisfies_version(1, 14, 0, crypt_maj, crypt_min, 0)) {
537                 t_dm_crypt_flags |= T_DM_SAME_CPU_CRYPT_SUPPORTED;
538                 t_dm_crypt_flags |= T_DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED;
539         }
540
541         if (t_dm_satisfies_version(1, 18, 1, crypt_maj, crypt_min, crypt_patch) && _keyring_check())
542                 t_dm_crypt_flags |= T_DM_KERNEL_KEYRING_SUPPORTED;
543
544         if (t_dm_satisfies_version(1, 17, 0, crypt_maj, crypt_min, crypt_patch)) {
545                 t_dm_crypt_flags |= T_DM_SECTOR_SIZE_SUPPORTED;
546                 t_dm_crypt_flags |= T_DM_CAPI_STRING_SUPPORTED;
547         }
548
549         if (t_dm_satisfies_version(1, 19, 0, crypt_maj, crypt_min, crypt_patch))
550                 t_dm_crypt_flags |= T_DM_BITLK_EBOIV_SUPPORTED;
551
552         if (t_dm_satisfies_version(1, 20, 0, crypt_maj, crypt_min, crypt_patch))
553                 t_dm_crypt_flags |= T_DM_BITLK_ELEPHANT_SUPPORTED;
554
555         if (t_dm_satisfies_version(1, 22, 0, crypt_maj, crypt_min, crypt_patch))
556                 t_dm_crypt_flags |= T_DM_CRYPT_NO_WORKQUEUE_SUPPORTED;
557 }
558
559 static void t_dm_set_verity_compat(const char *dm_version __attribute__((unused)),
560         unsigned verity_maj,
561         unsigned verity_min,
562         unsigned verity_patch __attribute__((unused)))
563 {
564         if (verity_maj > 0)
565                 t_dm_crypt_flags |= T_DM_VERITY_SUPPORTED;
566         else
567                 return;
568         /*
569          * ignore_corruption, restart_on corruption is available since 1.2 (kernel 4.1)
570          * ignore_zero_blocks since 1.3 (kernel 4.5)
571          * (but some dm-verity targets 1.2 don't support it)
572          * FEC is added in 1.3 as well.
573          */
574         if (t_dm_satisfies_version(1, 3, 0, verity_maj, verity_min, 0)) {
575                 t_dm_crypt_flags |= T_DM_VERITY_ON_CORRUPTION_SUPPORTED;
576                 t_dm_crypt_flags |= T_DM_VERITY_FEC_SUPPORTED;
577         }
578
579         if (t_dm_satisfies_version(1, 5, 0, verity_maj, verity_min, verity_patch))
580                 t_dm_crypt_flags |= T_DM_VERITY_SIGNATURE_SUPPORTED;
581
582         if (t_dm_satisfies_version(1, 7, 0, verity_maj, verity_min, verity_patch))
583                 t_dm_crypt_flags |= T_DM_VERITY_PANIC_CORRUPTION_SUPPORTED;
584
585         if (t_dm_satisfies_version(1, 9, 0, verity_maj, verity_min, verity_patch))
586                 t_dm_crypt_flags |= T_DM_VERITY_TASKLETS_SUPPORTED;
587 }
588
589 static void t_dm_set_integrity_compat(const char *dm_version __attribute__((unused)),
590         unsigned integrity_maj __attribute__((unused)),
591         unsigned integrity_min __attribute__((unused)),
592         unsigned integrity_patch __attribute__((unused)))
593 {
594         if (integrity_maj > 0)
595                 t_dm_crypt_flags |= T_DM_INTEGRITY_SUPPORTED;
596
597         if (t_dm_satisfies_version(1, 2, 0, integrity_maj, integrity_min, integrity_patch))
598                 t_dm_crypt_flags |= T_DM_INTEGRITY_RECALC_SUPPORTED;
599
600         if (t_dm_satisfies_version(1, 3, 0, integrity_maj, integrity_min, integrity_patch))
601                 t_dm_crypt_flags |= T_DM_INTEGRITY_BITMAP_SUPPORTED;
602
603         if (t_dm_satisfies_version(1, 4, 0, integrity_maj, integrity_min, integrity_patch))
604                 t_dm_crypt_flags |= T_DM_INTEGRITY_FIX_PADDING_SUPPORTED;
605
606         if (t_dm_satisfies_version(1, 6, 0, integrity_maj, integrity_min, integrity_patch))
607                 t_dm_crypt_flags |= T_DM_INTEGRITY_DISCARDS_SUPPORTED;
608
609         if (t_dm_satisfies_version(1, 7, 0, integrity_maj, integrity_min, integrity_patch))
610                 t_dm_crypt_flags |= T_DM_INTEGRITY_FIX_HMAC_SUPPORTED;
611
612         if (t_dm_satisfies_version(1, 8, 0, integrity_maj, integrity_min, integrity_patch))
613                 t_dm_crypt_flags |= T_DM_INTEGRITY_RESET_RECALC_SUPPORTED;
614 }
615
616 int t_dm_check_versions(void)
617 {
618         struct dm_task *dmt;
619         struct dm_versions *target, *last_target;
620         char dm_version[16];
621         int r = 1;
622
623         if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
624                 goto out;
625
626         if (!dm_task_run(dmt))
627                 goto out;
628
629         if (!dm_task_get_driver_version(dmt, dm_version, sizeof(dm_version)))
630                 goto out;
631
632         target = dm_task_get_versions(dmt);
633         do {
634                 last_target = target;
635                 if (!strcmp("crypt", target->name)) {
636                         t_dm_set_crypt_compat(dm_version,
637                                              (unsigned)target->version[0],
638                                              (unsigned)target->version[1],
639                                              (unsigned)target->version[2]);
640                 } else if (!strcmp("verity", target->name)) {
641                         t_dm_set_verity_compat(dm_version,
642                                              (unsigned)target->version[0],
643                                              (unsigned)target->version[1],
644                                              (unsigned)target->version[2]);
645                 } else if (!strcmp("integrity", target->name)) {
646                         t_dm_set_integrity_compat(dm_version,
647                                              (unsigned)target->version[0],
648                                              (unsigned)target->version[1],
649                                              (unsigned)target->version[2]);
650                 }
651                 target = VOIDP_CAST(struct dm_versions *)((char *) target + target->next);
652         } while (last_target != target);
653
654         r = 0;
655 out:
656         if (dmt)
657                 dm_task_destroy(dmt);
658
659         return r;
660 }
661
662 int t_dm_crypt_keyring_support(void)
663 {
664         return t_dm_crypt_flags & T_DM_KERNEL_KEYRING_SUPPORTED;
665 }
666
667 int t_dm_crypt_cpu_switch_support(void)
668 {
669         return t_dm_crypt_flags & (T_DM_SAME_CPU_CRYPT_SUPPORTED |
670                                    T_DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED);
671 }
672
673 int t_dm_crypt_discard_support(void)
674 {
675         return t_dm_crypt_flags & T_DM_DISCARDS_SUPPORTED;
676 }
677
678 int t_dm_integrity_resize_support(void)
679 {
680         return t_dm_crypt_flags & T_DM_INTEGRITY_RESIZE_SUPPORTED;
681 }
682
683 int t_dm_integrity_recalculate_support(void)
684 {
685         return t_dm_crypt_flags & T_DM_INTEGRITY_RECALC_SUPPORTED;
686 }
687
688 int t_dm_capi_string_supported(void)
689 {
690         return t_dm_crypt_flags & T_DM_CAPI_STRING_SUPPORTED;
691 }
692
693 /* loop helpers */
694
695 #define LOOP_DEV_MAJOR 7
696
697 #ifndef LO_FLAGS_AUTOCLEAR
698 #define LO_FLAGS_AUTOCLEAR 4
699 #endif
700
701 #ifndef LOOP_CTL_GET_FREE
702 #define LOOP_CTL_GET_FREE 0x4C82
703 #endif
704
705 #ifndef LOOP_SET_CAPACITY
706 #define LOOP_SET_CAPACITY 0x4C07
707 #endif
708
709 int loop_device(const char *loop)
710 {
711         struct stat st;
712
713         if (!loop)
714                 return 0;
715
716         if (stat(loop, &st) || !S_ISBLK(st.st_mode) ||
717             major(st.st_rdev) != LOOP_DEV_MAJOR)
718                 return 0;
719
720         return 1;
721 }
722
723 static char *crypt_loop_get_device_old(void)
724 {
725         char dev[64];
726         int i, loop_fd;
727         struct loop_info64 lo64 = {0};
728
729         for (i = 0; i < 256; i++) {
730                 sprintf(dev, "/dev/loop%d", i);
731
732                 loop_fd = open(dev, O_RDONLY);
733                 if (loop_fd < 0)
734                         return NULL;
735
736                 if (ioctl(loop_fd, LOOP_GET_STATUS64, &lo64) &&
737                     errno == ENXIO) {
738                         close(loop_fd);
739                         return strdup(dev);
740                 }
741                 close(loop_fd);
742         }
743
744         return NULL;
745 }
746
747 static char *crypt_loop_get_device(void)
748 {
749         char dev[64];
750         int i, loop_fd;
751         struct stat st;
752
753         loop_fd = open("/dev/loop-control", O_RDONLY);
754         if (loop_fd < 0)
755                 return crypt_loop_get_device_old();
756
757         i = ioctl(loop_fd, LOOP_CTL_GET_FREE);
758         if (i < 0) {
759                 close(loop_fd);
760                 return NULL;
761         }
762         close(loop_fd);
763
764         if (sprintf(dev, "/dev/loop%d", i) < 0)
765                 return NULL;
766
767         if (stat(dev, &st) || !S_ISBLK(st.st_mode))
768                 return NULL;
769
770         return strdup(dev);
771 }
772
773 int loop_attach(char **loop, const char *file, int offset,
774                       int autoclear, int *readonly)
775 {
776         struct loop_config config = {0};
777         char *lo_file_name;
778         int loop_fd = -1, file_fd = -1, r = 1;
779         int fallback = 0;
780
781         *loop = NULL;
782
783         file_fd = open(file, (*readonly ? O_RDONLY : O_RDWR) | O_EXCL);
784         if (file_fd < 0 && (errno == EROFS || errno == EACCES) && !*readonly) {
785                 *readonly = 1;
786                 file_fd = open(file, O_RDONLY | O_EXCL);
787         }
788         if (file_fd < 0)
789                 goto out;
790
791         config.fd = file_fd;
792
793         lo_file_name = (char*)config.info.lo_file_name;
794         lo_file_name[LO_NAME_SIZE-1] = '\0';
795         strncpy(lo_file_name, file, LO_NAME_SIZE-1);
796         config.info.lo_offset = offset;
797         if (autoclear)
798                 config.info.lo_flags |= LO_FLAGS_AUTOCLEAR;
799
800         while (loop_fd < 0)  {
801                 *loop = crypt_loop_get_device();
802                 if (!*loop)
803                         goto out;
804
805                 loop_fd = open(*loop, *readonly ? O_RDONLY : O_RDWR);
806                 if (loop_fd < 0)
807                         goto out;
808                 if (ioctl(loop_fd, LOOP_CONFIGURE, &config) < 0) {
809                         if (errno == EINVAL || errno == ENOTTY) {
810                                 free(*loop);
811                                 *loop = NULL;
812
813                                 close(loop_fd);
814                                 loop_fd = -1;
815
816                                 /* kernel doesn't support LOOP_CONFIGURE */
817                                 fallback = 1;
818                                 break;
819                         }
820                         if (errno != EBUSY)
821                                 goto out;
822                         free(*loop);
823                         *loop = NULL;
824
825                         close(loop_fd);
826                         loop_fd = -1;
827                 }
828         }
829
830         if (fallback)
831         {
832                 while (loop_fd < 0)  {
833                         *loop = crypt_loop_get_device();
834                         if (!*loop)
835                                 goto out;
836
837                         loop_fd = open(*loop, *readonly ? O_RDONLY : O_RDWR);
838                         if (loop_fd < 0)
839                                 goto out;
840                         if (ioctl(loop_fd, LOOP_SET_FD, file_fd) < 0) {
841                                 if (errno != EBUSY)
842                                         goto out;
843                                 free(*loop);
844                                 *loop = NULL;
845
846                                 close(loop_fd);
847                                 loop_fd = -1;
848                         }
849                 }
850
851                 if (ioctl(loop_fd, LOOP_SET_STATUS64, &config.info) < 0) {
852                         (void)ioctl(loop_fd, LOOP_CLR_FD, 0);
853                         goto out;
854                 }
855         }
856
857         /* Verify that autoclear is really set */
858         if (autoclear) {
859                 memset(&config.info, 0, sizeof(config.info));
860                 if (ioctl(loop_fd, LOOP_GET_STATUS64, &config.info) < 0 ||
861                    !(config.info.lo_flags & LO_FLAGS_AUTOCLEAR)) {
862                 (void)ioctl(loop_fd, LOOP_CLR_FD, 0);
863                         goto out;
864                 }
865         }
866
867         r = 0;
868 out:
869         if (r && loop_fd >= 0)
870                 close(loop_fd);
871         if (file_fd >= 0)
872                 close(file_fd);
873         if (r && *loop) {
874                 free(*loop);
875                 *loop = NULL;
876         }
877         return r ? -1 : loop_fd;
878 }
879
880 int loop_detach(const char *loop)
881 {
882         int loop_fd = -1, r = 1;
883
884         loop_fd = open(loop, O_RDONLY);
885         if (loop_fd < 0)
886                 return 1;
887
888         if (!ioctl(loop_fd, LOOP_CLR_FD, 0))
889                 r = 0;
890
891         close(loop_fd);
892         return r;
893 }
894
895 int t_get_devno(const char *name, dev_t *devno)
896 {
897         char path[PATH_MAX];
898         int r;
899         struct stat st;
900
901         r = snprintf(path, sizeof(path), DMDIR "%s", name);
902         if (r < 0 || (size_t)r >= sizeof(path))
903                 return 1;
904
905         if (stat(path, &st) || !S_ISBLK(st.st_mode))
906                 return 1;
907
908         *devno = st.st_rdev;
909
910         return 0;
911 }
912
913 static int _read_uint64(const char *sysfs_path, uint64_t *value)
914 {
915         char tmp[64] = {0};
916         int fd, r;
917
918         if ((fd = open(sysfs_path, O_RDONLY)) < 0)
919                 return 0;
920         r = read(fd, tmp, sizeof(tmp));
921         close(fd);
922
923         if (r <= 0)
924                 return 0;
925
926         if (sscanf(tmp, "%" PRIu64, value) != 1)
927                 return 0;
928
929         return 1;
930 }
931
932 static int _sysfs_get_uint64(int major, int minor, uint64_t *value, const char *attr)
933 {
934         char path[PATH_MAX];
935
936         if (snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/%s",
937                      major, minor, attr) < 0)
938                 return 0;
939
940         return _read_uint64(path, value);
941 }
942
943 int t_device_size_by_devno(dev_t devno, uint64_t *retval)
944 {
945         if (!_sysfs_get_uint64(major(devno), minor(devno), retval, "size"))
946                 return 1;
947
948         *retval *= 512;
949         return 0;
950 }