9f070e999dd4e99a03acfb9909a1897230eda4c9
[platform/upstream/cryptsetup.git] / tests / test_utils.c
1 /*
2  * cryptsetup library API test utilities
3  *
4  * Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
5  * Copyright (C) 2009-2021 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 <errno.h>
23 #include <fcntl.h>
24 #include <inttypes.h>
25 #include <stdlib.h>
26 #include <libdevmapper.h>
27 #include <linux/fs.h>
28 #include <sys/ioctl.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 #ifdef KERNEL_KEYRING
33 # include <linux/keyctl.h>
34 # include <sys/syscall.h>
35 #endif
36 #ifdef HAVE_SYS_SYSMACROS_H
37 # include <sys/sysmacros.h>
38 #endif
39 #include <linux/loop.h>
40
41 #include "api_test.h"
42 #include "libcryptsetup.h"
43
44 static char last_error[256];
45 static char global_log[4096];
46 static uint32_t t_dm_crypt_flags = 0;
47
48 char *THE_LOOP_DEV = NULL;
49 int _debug   = 0;
50 int global_lines = 0;
51 int _quit = 0;
52 int _verbose = 0;
53 uint64_t t_dev_offset = 0;
54
55 static void (*_cleanup)(void);
56
57 void register_cleanup(void (*cleanup)(void))
58 {
59         _cleanup = cleanup;
60 }
61
62 void check_ok(int status, int line, const char *func)
63 {
64         if (status) {
65                 printf("FAIL line %d [%s]: code %d, %s\n", line, func, status, last_error);
66                 _cleanup();
67                 exit(-1);
68         }
69 }
70
71 void check_ok_return(int status, int line, const char *func)
72 {
73         if (status < 0) {
74                 printf("FAIL line %d [%s]: code %d, %s\n", line, func, status, last_error);
75                 _cleanup();
76                 exit(-1);
77         }
78 }
79
80 void check_ko(int status, int line, const char *func)
81 {
82         if (status >= 0) {
83                 printf("FAIL line %d [%s]: code %d, %s\n", line, func, status, last_error);
84                 _cleanup();
85                 exit(-1);
86         } else if (_verbose)
87                 printf("   => errno %d, errmsg: %s\n", status, last_error);
88 }
89
90 void check_equal(int line, const char *func, int64_t x, int64_t y)
91 {
92         printf("FAIL line %d [%s]: expected equal values differs: %"
93                 PRIi64 " != %" PRIi64 "\n", line, func, x, y);
94         _cleanup();
95         exit(-1);
96 }
97
98 void check_ge_equal(int line, const char *func, int64_t x, int64_t y)
99 {
100         printf("FAIL line %d [%s]: expected greater or equal values differs: %"
101                 PRIi64 " < %" PRIi64 "\n", line, func, x, y);
102         _cleanup();
103         exit(-1);
104 }
105
106 void check_null(int line, const char *func, const void *x)
107 {
108         if (x) {
109                 printf("FAIL line %d [%s]: expected NULL value: %p\n", line, func, x);
110                 _cleanup();
111                 exit(-1);
112         }
113 }
114
115 void check_notnull(int line, const char *func, const void *x)
116 {
117         if (!x) {
118                 printf("FAIL line %d [%s]: expected not NULL value: %p\n", line, func, x);
119                 _cleanup();
120                 exit(-1);
121         }
122 }
123
124 void xlog(const char *msg, const char *tst, const char *func, int line, const char *txt)
125 {
126         if (_verbose) {
127                 if (txt)
128                         printf(" [%s,%s:%d] %s [%s]\n", msg, func, line, tst, txt);
129                 else
130                         printf(" [%s,%s:%d] %s\n", msg, func, line, tst);
131         }
132         if (_quit) {
133                 if (_verbose)
134                         printf("Interrupted by a signal.\n");
135                 _cleanup();
136                 exit(-1);
137         }
138 }
139
140 int t_device_size(const char *device, uint64_t *size)
141 {
142         int devfd, r = 0;
143
144         devfd = open(device, O_RDONLY);
145         if(devfd == -1)
146                 return -EINVAL;
147
148         if (ioctl(devfd, BLKGETSIZE64, size) < 0)
149                 r = -EINVAL;
150         close(devfd);
151         return r;
152 }
153
154 int fips_mode(void)
155 {
156         int fd;
157         char buf = 0;
158
159         fd = open("/proc/sys/crypto/fips_enabled", O_RDONLY);
160
161         if (fd < 0)
162                 return 0;
163
164         if (read(fd, &buf, 1) != 1)
165                 buf = '0';
166
167         close(fd);
168
169         return (buf == '1');
170 }
171
172 /*
173  * Creates dm-linear target over the test loop device. Offset is held in
174  * global variables so that size can be tested whether it fits into remaining
175  * size of the loop device or not
176  */
177 int create_dmdevice_over_loop(const char *dm_name, const uint64_t size)
178 {
179         char cmd[128];
180         int r;
181         uint64_t r_size;
182
183         if (t_device_size(THE_LOOP_DEV, &r_size) < 0 || r_size <= t_dev_offset || !size)
184                 return -1;
185         if ((r_size - t_dev_offset) < size) {
186                 printf("No enough space on backing loop device\n.");
187                 return -2;
188         }
189         snprintf(cmd, sizeof(cmd),
190                  "dmsetup create %s --table \"0 %" PRIu64 " linear %s %" PRIu64 "\"",
191                  dm_name, size, THE_LOOP_DEV, t_dev_offset);
192         if (!(r = _system(cmd, 1)))
193                 t_dev_offset += size;
194         return r;
195 }
196
197 // Get key from kernel dm mapping table using dm-ioctl
198 int get_key_dm(const char *name, char *buffer, unsigned int buffer_size)
199 {
200         struct dm_task *dmt;
201         struct dm_info dmi;
202         uint64_t start, length;
203         char *target_type, *key, *params;
204         void *next = NULL;
205         int r = -EINVAL;
206
207         if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
208                 goto out;
209         if (!dm_task_set_name(dmt, name))
210                 goto out;
211         if (!dm_task_run(dmt))
212                 goto out;
213         if (!dm_task_get_info(dmt, &dmi))
214                 goto out;
215         if (!dmi.exists)
216                 goto out;
217
218         next = dm_get_next_target(dmt, next, &start, &length, &target_type, &params);
219         if (!target_type || strcmp(target_type, "crypt") != 0)
220                 goto out;
221
222         (void)strsep(&params, " "); /* rcipher */
223         key = strsep(&params, " ");
224
225         if (buffer_size <= strlen(key))
226                 goto out;
227
228         strncpy(buffer, key, buffer_size);
229         r = 0;
230 out:
231         if (dmt)
232                 dm_task_destroy(dmt);
233
234         return r;
235 }
236
237 int prepare_keyfile(const char *name, const char *passphrase, int size)
238 {
239         int fd, r;
240
241         fd = open(name, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR|S_IWUSR);
242         if (fd != -1) {
243                 r = write(fd, passphrase, size);
244                 close(fd);
245         } else
246                 r = 0;
247
248         return r == size ? 0 : 1;
249 }
250
251 // Decode key from its hex representation
252 int crypt_decode_key(char *key, const char *hex, unsigned int size)
253 {
254         char buffer[3];
255         char *endp;
256         unsigned int i;
257
258         buffer[2] = '\0';
259
260         for (i = 0; i < size; i++) {
261                 buffer[0] = *hex++;
262                 buffer[1] = *hex++;
263
264                 key[i] = (unsigned char)strtoul(buffer, &endp, 16);
265
266                 if (endp != &buffer[2])
267                         return -1;
268         }
269
270         if (*hex != '\0')
271                 return -1;
272
273         return 0;
274 }
275
276 void global_log_callback(int level, const char *msg, void *usrptr)
277 {
278         size_t len;
279
280         if (_debug) {
281                 if (level == CRYPT_LOG_DEBUG)
282                         fprintf(stdout, "# %s", msg);
283                 else
284                         fprintf(stdout, "%s", msg);
285         }
286
287         if (level <= CRYPT_LOG_DEBUG)
288                 return;
289
290         len = strlen(global_log);
291
292         if (len + strlen(msg) > sizeof(global_log)) {
293                         printf("Log buffer is too small, fix the test.\n");
294                         return;
295         }
296
297         strncat(global_log, msg, sizeof(global_log) - len);
298         global_lines++;
299         if (level == CRYPT_LOG_ERROR) {
300                 len = strlen(msg);
301                 if (len > sizeof(last_error))
302                         len = sizeof(last_error);
303                 strncpy(last_error, msg, sizeof(last_error));
304                 last_error[len-1] = '\0';
305         }
306 }
307
308 void reset_log(void)
309 {
310         memset(global_log, 0, sizeof(global_log));
311         memset(last_error, 0, sizeof(last_error));
312         global_lines = 0;
313 }
314
315 int _system(const char *command, int warn)
316 {
317         int r;
318         if (_debug)
319                 printf("Running system: %s\n", command);
320         if ((r=system(command)) < 0 && warn)
321                 printf("System command failed: %s", command);
322         return r;
323 }
324
325 static int keyring_check(void)
326 {
327 #ifdef KERNEL_KEYRING
328         return syscall(__NR_request_key, "logon", "dummy", NULL, 0) == -1l && errno != ENOSYS;
329 #else
330         return 0;
331 #endif
332 }
333
334 static int t_dm_satisfies_version(unsigned target_maj, unsigned target_min, unsigned target_patch,
335                                  unsigned actual_maj, unsigned actual_min, unsigned actual_patch)
336 {
337         if (actual_maj > target_maj)
338                 return 1;
339         if (actual_maj == target_maj && actual_min > target_min)
340                 return 1;
341         if (actual_maj == target_maj && actual_min == target_min && actual_patch >= target_patch)
342                 return 1;
343         return 0;
344 }
345
346 static void t_dm_set_crypt_compat(const char *dm_version, unsigned crypt_maj,
347                                  unsigned crypt_min, unsigned crypt_patch)
348 {
349         unsigned dm_maj = 0, dm_min = 0, dm_patch = 0;
350
351         if (sscanf(dm_version, "%u.%u.%u", &dm_maj, &dm_min, &dm_patch) != 3) {
352                 dm_maj = 0;
353                 dm_min = 0;
354                 dm_patch = 0;
355         }
356
357         if (t_dm_satisfies_version(1, 2, 0, crypt_maj, crypt_min, 0))
358                 t_dm_crypt_flags |= T_DM_KEY_WIPE_SUPPORTED;
359
360         if (t_dm_satisfies_version(1, 10, 0, crypt_maj, crypt_min, 0))
361                 t_dm_crypt_flags |= T_DM_LMK_SUPPORTED;
362
363         if (t_dm_satisfies_version(4, 20, 0, dm_maj, dm_min, 0))
364                 t_dm_crypt_flags |= T_DM_SECURE_SUPPORTED;
365
366         if (t_dm_satisfies_version(1, 8, 0, crypt_maj, crypt_min, 0))
367                 t_dm_crypt_flags |= T_DM_PLAIN64_SUPPORTED;
368
369         if (t_dm_satisfies_version(1, 11, 0, crypt_maj, crypt_min, 0))
370                 t_dm_crypt_flags |= T_DM_DISCARDS_SUPPORTED;
371
372         if (t_dm_satisfies_version(1, 13, 0, crypt_maj, crypt_min, 0))
373                 t_dm_crypt_flags |= T_DM_TCW_SUPPORTED;
374
375         if (t_dm_satisfies_version(1, 14, 0, crypt_maj, crypt_min, 0)) {
376                 t_dm_crypt_flags |= T_DM_SAME_CPU_CRYPT_SUPPORTED;
377                 t_dm_crypt_flags |= T_DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED;
378         }
379
380         if (t_dm_satisfies_version(1, 18, 1, crypt_maj, crypt_min, crypt_patch) && keyring_check())
381                 t_dm_crypt_flags |= T_DM_KERNEL_KEYRING_SUPPORTED;
382 }
383
384 static void t_dm_set_verity_compat(const char *dm_version, unsigned verity_maj,
385                                    unsigned verity_min, unsigned verity_patch)
386 {
387         if (verity_maj > 0)
388                 t_dm_crypt_flags |= T_DM_VERITY_SUPPORTED;
389         else
390                 return;
391         /*
392          * ignore_corruption, restart_on corruption is available since 1.2 (kernel 4.1)
393          * ignore_zero_blocks since 1.3 (kernel 4.5)
394          * (but some dm-verity targets 1.2 don't support it)
395          * FEC is added in 1.3 as well.
396          */
397         if (t_dm_satisfies_version(1, 3, 0, verity_maj, verity_min, 0)) {
398                 t_dm_crypt_flags |= T_DM_VERITY_ON_CORRUPTION_SUPPORTED;
399                 t_dm_crypt_flags |= T_DM_VERITY_FEC_SUPPORTED;
400         }
401 }
402
403 static void t_dm_set_integrity_compat(const char *dm_version, unsigned integrity_maj,
404                                       unsigned integrity_min, unsigned integrity_patch)
405 {
406         if (integrity_maj > 0)
407                 t_dm_crypt_flags |= T_DM_INTEGRITY_SUPPORTED;
408 }
409
410 int t_dm_check_versions(void)
411 {
412         struct dm_task *dmt;
413         struct dm_versions *target, *last_target;
414         char dm_version[16];
415         int r = 1;
416
417         if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
418                 goto out;
419
420         if (!dm_task_run(dmt))
421                 goto out;
422
423         if (!dm_task_get_driver_version(dmt, dm_version, sizeof(dm_version)))
424                 goto out;
425
426         target = dm_task_get_versions(dmt);
427         do {
428                 last_target = target;
429                 if (!strcmp("crypt", target->name)) {
430                         t_dm_set_crypt_compat(dm_version,
431                                              (unsigned)target->version[0],
432                                              (unsigned)target->version[1],
433                                              (unsigned)target->version[2]);
434                 } else if (!strcmp("verity", target->name)) {
435                         t_dm_set_verity_compat(dm_version,
436                                              (unsigned)target->version[0],
437                                              (unsigned)target->version[1],
438                                              (unsigned)target->version[2]);
439                 } else if (!strcmp("integrity", target->name)) {
440                         t_dm_set_integrity_compat(dm_version,
441                                              (unsigned)target->version[0],
442                                              (unsigned)target->version[1],
443                                              (unsigned)target->version[2]);
444                 }
445                 target = (struct dm_versions *)((char *) target + target->next);
446         } while (last_target != target);
447
448         r = 0;
449 out:
450         if (dmt)
451                 dm_task_destroy(dmt);
452
453         return r;
454 }
455
456 int t_dm_crypt_keyring_support(void)
457 {
458         return t_dm_crypt_flags & T_DM_KERNEL_KEYRING_SUPPORTED;
459 }
460
461 int t_dm_crypt_cpu_switch_support(void)
462 {
463         return t_dm_crypt_flags & (T_DM_SAME_CPU_CRYPT_SUPPORTED |
464                                    T_DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED);
465 }
466
467 int t_dm_crypt_discard_support(void)
468 {
469         return t_dm_crypt_flags & T_DM_DISCARDS_SUPPORTED;
470 }
471
472 /* loop helpers */
473
474 #define LOOP_DEV_MAJOR 7
475
476 #ifndef LO_FLAGS_AUTOCLEAR
477 #define LO_FLAGS_AUTOCLEAR 4
478 #endif
479
480 #ifndef LOOP_CTL_GET_FREE
481 #define LOOP_CTL_GET_FREE 0x4C82
482 #endif
483
484 #ifndef LOOP_SET_CAPACITY
485 #define LOOP_SET_CAPACITY 0x4C07
486 #endif
487
488 int loop_device(const char *loop)
489 {
490         struct stat st;
491
492         if (!loop)
493                 return 0;
494
495         if (stat(loop, &st) || !S_ISBLK(st.st_mode) ||
496             major(st.st_rdev) != LOOP_DEV_MAJOR)
497                 return 0;
498
499         return 1;
500 }
501
502 static char *crypt_loop_get_device_old(void)
503 {
504         char dev[20];
505         int i, loop_fd;
506         struct loop_info64 lo64 = {0};
507
508         for (i = 0; i < 256; i++) {
509                 sprintf(dev, "/dev/loop%d", i);
510
511                 loop_fd = open(dev, O_RDONLY);
512                 if (loop_fd < 0)
513                         return NULL;
514
515                 if (ioctl(loop_fd, LOOP_GET_STATUS64, &lo64) &&
516                     errno == ENXIO) {
517                         close(loop_fd);
518                         return strdup(dev);
519                 }
520                 close(loop_fd);
521         }
522
523         return NULL;
524 }
525
526 static char *crypt_loop_get_device(void)
527 {
528         char dev[64];
529         int i, loop_fd;
530         struct stat st;
531
532         loop_fd = open("/dev/loop-control", O_RDONLY);
533         if (loop_fd < 0)
534                 return crypt_loop_get_device_old();
535
536         i = ioctl(loop_fd, LOOP_CTL_GET_FREE);
537         if (i < 0) {
538                 close(loop_fd);
539                 return NULL;
540         }
541         close(loop_fd);
542
543         if (sprintf(dev, "/dev/loop%d", i) < 0)
544                 return NULL;
545
546         if (stat(dev, &st) || !S_ISBLK(st.st_mode))
547                 return NULL;
548
549         return strdup(dev);
550 }
551
552 int loop_attach(char **loop, const char *file, int offset,
553                       int autoclear, int *readonly)
554 {
555         struct loop_info64 lo64 = {0};
556         char *lo_file_name;
557         int loop_fd = -1, file_fd = -1, r = 1;
558
559         *loop = NULL;
560
561         file_fd = open(file, (*readonly ? O_RDONLY : O_RDWR) | O_EXCL);
562         if (file_fd < 0 && (errno == EROFS || errno == EACCES) && !*readonly) {
563                 *readonly = 1;
564                 file_fd = open(file, O_RDONLY | O_EXCL);
565         }
566         if (file_fd < 0)
567                 goto out;
568
569         while (loop_fd < 0)  {
570                 *loop = crypt_loop_get_device();
571                 if (!*loop)
572                         goto out;
573
574                 loop_fd = open(*loop, *readonly ? O_RDONLY : O_RDWR);
575                 if (loop_fd < 0)
576                         goto out;
577
578                 if (ioctl(loop_fd, LOOP_SET_FD, file_fd) < 0) {
579                         if (errno != EBUSY)
580                                 goto out;
581                         free(*loop);
582                         *loop = NULL;
583
584                         close(loop_fd);
585                         loop_fd = -1;
586                 }
587         }
588
589         lo_file_name = (char*)lo64.lo_file_name;
590         lo_file_name[LO_NAME_SIZE-1] = '\0';
591         strncpy(lo_file_name, file, LO_NAME_SIZE-1);
592         lo64.lo_offset = offset;
593         if (autoclear)
594                 lo64.lo_flags |= LO_FLAGS_AUTOCLEAR;
595
596         if (ioctl(loop_fd, LOOP_SET_STATUS64, &lo64) < 0) {
597                 (void)ioctl(loop_fd, LOOP_CLR_FD, 0);
598                 goto out;
599         }
600
601         /* Verify that autoclear is really set */
602         if (autoclear) {
603                 memset(&lo64, 0, sizeof(lo64));
604                 if (ioctl(loop_fd, LOOP_GET_STATUS64, &lo64) < 0 ||
605                    !(lo64.lo_flags & LO_FLAGS_AUTOCLEAR)) {
606                 (void)ioctl(loop_fd, LOOP_CLR_FD, 0);
607                         goto out;
608                 }
609         }
610
611         r = 0;
612 out:
613         if (r && loop_fd >= 0)
614                 close(loop_fd);
615         if (file_fd >= 0)
616                 close(file_fd);
617         if (r && *loop) {
618                 free(*loop);
619                 *loop = NULL;
620         }
621         return r ? -1 : loop_fd;
622 }
623
624 int loop_detach(const char *loop)
625 {
626         int loop_fd = -1, r = 1;
627
628         loop_fd = open(loop, O_RDONLY);
629         if (loop_fd < 0)
630                 return 1;
631
632         if (!ioctl(loop_fd, LOOP_CLR_FD, 0))
633                 r = 0;
634
635         close(loop_fd);
636         return r;
637 }