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