1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright 2018 Google LLC
4 */
5 #define _GNU_SOURCE
6
7 #include <alloca.h>
8 #include <dirent.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <lz4.h>
12 #include <poll.h>
13 #include <stdbool.h>
14 #include <stdint.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <time.h>
19 #include <unistd.h>
20 #include <zstd.h>
21
22 #include <sys/inotify.h>
23 #include <sys/mman.h>
24 #include <sys/mount.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <sys/wait.h>
28 #include <sys/xattr.h>
29 #include <sys/statvfs.h>
30
31 #include <linux/random.h>
32 #include <linux/stat.h>
33 #include <linux/unistd.h>
34
35 #include <openssl/pem.h>
36 #include <openssl/x509.h>
37
38 #include <kselftest.h>
39 #include <include/uapi/linux/fsverity.h>
40
41 #include "utils.h"
42
43 /* Can't include uapi/linux/fs.h because it clashes with mount.h */
44 #define FS_IOC_GETFLAGS _IOR('f', 1, long)
45 #define FS_VERITY_FL 0x00100000 /* Verity protected inode */
46
47 #define TEST_SKIP 2
48 #define TEST_FAILURE 1
49 #define TEST_SUCCESS 0
50
51 #define INCFS_ROOT_INODE 0
52
53 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
54 #define le16_to_cpu(x) (x)
55 #define le32_to_cpu(x) (x)
56 #define le64_to_cpu(x) (x)
57 #else
58 #error Big endian not supported!
59 #endif
60
61 struct {
62 int file;
63 int test;
64 bool verbose;
65 } options;
66
67 #define TESTCOND(condition) \
68 do { \
69 if (!(condition)) { \
70 ksft_print_msg("%s failed %d\n", \
71 __func__, __LINE__); \
72 goto out; \
73 } else if (options.verbose) \
74 ksft_print_msg("%s succeeded %d\n", \
75 __func__, __LINE__); \
76 } while (false)
77
78 #define TEST(statement, condition) \
79 do { \
80 statement; \
81 TESTCOND(condition); \
82 } while (false)
83
84 #define TESTEQUAL(statement, res) \
85 TESTCOND((statement) == (res))
86
87 #define TESTNE(statement, res) \
88 TESTCOND((statement) != (res))
89
90 #define TESTSYSCALL(statement) \
91 do { \
92 int res = statement; \
93 \
94 if (res) \
95 ksft_print_msg("Failed: %s (%d)\n", \
96 strerror(errno), errno); \
97 TESTEQUAL(res, 0); \
98 } while (false)
99
print_bytes(const void * data,size_t size)100 void print_bytes(const void *data, size_t size)
101 {
102 const uint8_t *bytes = data;
103 int i;
104
105 for (i = 0; i < size; ++i) {
106 if (i % 0x10 == 0)
107 printf("%08x:", i);
108 printf("%02x ", (unsigned int) bytes[i]);
109 if (i % 0x10 == 0x0f)
110 printf("\n");
111 }
112
113 if (i % 0x10 != 0)
114 printf("\n");
115 }
116
117 struct hash_block {
118 char data[INCFS_DATA_FILE_BLOCK_SIZE];
119 };
120
121 struct test_signature {
122 void *data;
123 size_t size;
124
125 char add_data[100];
126 size_t add_data_size;
127 };
128
129 struct test_file {
130 int index;
131 incfs_uuid_t id;
132 char *name;
133 off_t size;
134 char root_hash[INCFS_MAX_HASH_SIZE];
135 struct hash_block *mtree;
136 int mtree_block_count;
137 struct test_signature sig;
138 unsigned char *verity_sig;
139 size_t verity_sig_size;
140 };
141
142 struct test_files_set {
143 struct test_file *files;
144 int files_count;
145 };
146
147 struct linux_dirent64 {
148 uint64_t d_ino;
149 int64_t d_off;
150 unsigned short d_reclen;
151 unsigned char d_type;
152 char d_name[0];
153 } __packed;
154
get_test_files_set(void)155 struct test_files_set get_test_files_set(void)
156 {
157 static struct test_file files[] = {
158 { .index = 0, .name = "file_one_byte", .size = 1 },
159 { .index = 1,
160 .name = "file_one_block",
161 .size = INCFS_DATA_FILE_BLOCK_SIZE },
162 { .index = 2,
163 .name = "file_one_and_a_half_blocks",
164 .size = INCFS_DATA_FILE_BLOCK_SIZE +
165 INCFS_DATA_FILE_BLOCK_SIZE / 2 },
166 { .index = 3,
167 .name = "file_three",
168 .size = 300 * INCFS_DATA_FILE_BLOCK_SIZE + 3 },
169 { .index = 4,
170 .name = "file_four",
171 .size = 400 * INCFS_DATA_FILE_BLOCK_SIZE + 7 },
172 { .index = 5,
173 .name = "file_five",
174 .size = 500 * INCFS_DATA_FILE_BLOCK_SIZE + 7 },
175 { .index = 6,
176 .name = "file_six",
177 .size = 600 * INCFS_DATA_FILE_BLOCK_SIZE + 7 },
178 { .index = 7,
179 .name = "file_seven",
180 .size = 700 * INCFS_DATA_FILE_BLOCK_SIZE + 7 },
181 { .index = 8,
182 .name = "file_eight",
183 .size = 800 * INCFS_DATA_FILE_BLOCK_SIZE + 7 },
184 { .index = 9,
185 .name = "file_nine",
186 .size = 900 * INCFS_DATA_FILE_BLOCK_SIZE + 7 },
187 { .index = 10, .name = "file_big", .size = 500 * 1024 * 1024 }
188 };
189
190 if (options.file)
191 return (struct test_files_set) {
192 .files = files + options.file - 1,
193 .files_count = 1,
194 };
195
196 return (struct test_files_set){ .files = files,
197 .files_count = ARRAY_SIZE(files) };
198 }
199
get_small_test_files_set(void)200 struct test_files_set get_small_test_files_set(void)
201 {
202 static struct test_file files[] = {
203 { .index = 0, .name = "file_one_byte", .size = 1 },
204 { .index = 1,
205 .name = "file_one_block",
206 .size = INCFS_DATA_FILE_BLOCK_SIZE },
207 { .index = 2,
208 .name = "file_one_and_a_half_blocks",
209 .size = INCFS_DATA_FILE_BLOCK_SIZE +
210 INCFS_DATA_FILE_BLOCK_SIZE / 2 },
211 { .index = 3,
212 .name = "file_three",
213 .size = 300 * INCFS_DATA_FILE_BLOCK_SIZE + 3 },
214 { .index = 4,
215 .name = "file_four",
216 .size = 400 * INCFS_DATA_FILE_BLOCK_SIZE + 7 }
217 };
218 return (struct test_files_set){ .files = files,
219 .files_count = ARRAY_SIZE(files) };
220 }
221
get_file_block_seed(int file,int block)222 static int get_file_block_seed(int file, int block)
223 {
224 return 7919 * file + block;
225 }
226
min(loff_t a,loff_t b)227 static loff_t min(loff_t a, loff_t b)
228 {
229 return a < b ? a : b;
230 }
231
ilog2(size_t n)232 static int ilog2(size_t n)
233 {
234 int l = 0;
235
236 while (n > 1) {
237 ++l;
238 n >>= 1;
239 }
240 return l;
241 }
242
flush_and_fork(void)243 static pid_t flush_and_fork(void)
244 {
245 fflush(stdout);
246 return fork();
247 }
248
print_error(char * msg)249 static void print_error(char *msg)
250 {
251 ksft_print_msg("%s: %s\n", msg, strerror(errno));
252 }
253
wait_for_process(pid_t pid)254 static int wait_for_process(pid_t pid)
255 {
256 int status;
257 int wait_res;
258
259 wait_res = waitpid(pid, &status, 0);
260 if (wait_res <= 0) {
261 print_error("Can't wait for the child");
262 return -EINVAL;
263 }
264 if (!WIFEXITED(status)) {
265 ksft_print_msg("Unexpected child status pid=%d\n", pid);
266 return -EINVAL;
267 }
268 status = WEXITSTATUS(status);
269 if (status != 0)
270 return status;
271 return 0;
272 }
273
rnd_buf(uint8_t * data,size_t len,unsigned int seed)274 static void rnd_buf(uint8_t *data, size_t len, unsigned int seed)
275 {
276 int i;
277
278 for (i = 0; i < len; i++) {
279 seed = 1103515245 * seed + 12345;
280 data[i] = (uint8_t)(seed >> (i % 13));
281 }
282 }
283
bin2hex(char * dst,const void * src,size_t count)284 char *bin2hex(char *dst, const void *src, size_t count)
285 {
286 const unsigned char *_src = src;
287 static const char hex_asc[] = "0123456789abcdef";
288
289 while (count--) {
290 unsigned char x = *_src++;
291
292 *dst++ = hex_asc[(x & 0xf0) >> 4];
293 *dst++ = hex_asc[(x & 0x0f)];
294 }
295 *dst = 0;
296 return dst;
297 }
298
get_index_filename(const char * mnt_dir,incfs_uuid_t id)299 static char *get_index_filename(const char *mnt_dir, incfs_uuid_t id)
300 {
301 char path[FILENAME_MAX];
302 char str_id[1 + 2 * sizeof(id)];
303
304 bin2hex(str_id, id.bytes, sizeof(id.bytes));
305 snprintf(path, ARRAY_SIZE(path), "%s/.index/%s", mnt_dir, str_id);
306
307 return strdup(path);
308 }
309
get_incomplete_filename(const char * mnt_dir,incfs_uuid_t id)310 static char *get_incomplete_filename(const char *mnt_dir, incfs_uuid_t id)
311 {
312 char path[FILENAME_MAX];
313 char str_id[1 + 2 * sizeof(id)];
314
315 bin2hex(str_id, id.bytes, sizeof(id.bytes));
316 snprintf(path, ARRAY_SIZE(path), "%s/.incomplete/%s", mnt_dir, str_id);
317
318 return strdup(path);
319 }
320
open_file_by_id(const char * mnt_dir,incfs_uuid_t id,bool use_ioctl)321 int open_file_by_id(const char *mnt_dir, incfs_uuid_t id, bool use_ioctl)
322 {
323 char *path = get_index_filename(mnt_dir, id);
324 int cmd_fd = open_commands_file(mnt_dir);
325 int fd = open(path, O_RDWR | O_CLOEXEC);
326 struct incfs_permit_fill permit_fill = {
327 .file_descriptor = fd,
328 };
329 int error = 0;
330
331 if (fd < 0) {
332 print_error("Can't open file by id.");
333 error = -errno;
334 goto out;
335 }
336
337 if (use_ioctl && ioctl(cmd_fd, INCFS_IOC_PERMIT_FILL, &permit_fill)) {
338 print_error("Failed to call PERMIT_FILL");
339 error = -errno;
340 goto out;
341 }
342
343 if (ioctl(fd, INCFS_IOC_PERMIT_FILL, &permit_fill) != -1) {
344 print_error(
345 "Successfully called PERMIT_FILL on non pending_read file");
346 return -errno;
347 goto out;
348 }
349
350 out:
351 free(path);
352 close(cmd_fd);
353
354 if (error) {
355 close(fd);
356 return error;
357 }
358
359 return fd;
360 }
361
get_file_attr(const char * mnt_dir,incfs_uuid_t id,char * value,int size)362 int get_file_attr(const char *mnt_dir, incfs_uuid_t id, char *value, int size)
363 {
364 char *path = get_index_filename(mnt_dir, id);
365 int res;
366
367 res = getxattr(path, INCFS_XATTR_METADATA_NAME, value, size);
368 if (res < 0)
369 res = -errno;
370
371 free(path);
372 return res;
373 }
374
same_id(incfs_uuid_t * id1,incfs_uuid_t * id2)375 static bool same_id(incfs_uuid_t *id1, incfs_uuid_t *id2)
376 {
377 return !memcmp(id1->bytes, id2->bytes, sizeof(id1->bytes));
378 }
379
ZSTD_compress_default(char * data,char * comp_data,size_t data_size,size_t comp_size)380 ssize_t ZSTD_compress_default(char *data, char *comp_data, size_t data_size,
381 size_t comp_size)
382 {
383 return ZSTD_compress(comp_data, comp_size, data, data_size, 1);
384 }
385
emit_test_blocks(const char * mnt_dir,struct test_file * file,int blocks[],int count)386 static int emit_test_blocks(const char *mnt_dir, struct test_file *file,
387 int blocks[], int count)
388 {
389 uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE];
390 uint8_t comp_data[2 * INCFS_DATA_FILE_BLOCK_SIZE];
391 int block_count = (count > 32) ? 32 : count;
392 int data_buf_size = 2 * INCFS_DATA_FILE_BLOCK_SIZE * block_count;
393 uint8_t *data_buf = malloc(data_buf_size);
394 uint8_t *current_data = data_buf;
395 uint8_t *data_end = data_buf + data_buf_size;
396 struct incfs_fill_block *block_buf =
397 calloc(block_count, sizeof(struct incfs_fill_block));
398 struct incfs_fill_blocks fill_blocks = {
399 .count = block_count,
400 .fill_blocks = ptr_to_u64(block_buf),
401 };
402 ssize_t write_res = 0;
403 int fd = -1;
404 int error = 0;
405 int i = 0;
406 int blocks_written = 0;
407
408 for (i = 0; i < block_count; i++) {
409 int block_index = blocks[i];
410 bool compress_zstd = (file->index + block_index) % 4 == 2;
411 bool compress_lz4 = (file->index + block_index) % 4 == 0;
412 int seed = get_file_block_seed(file->index, block_index);
413 off_t block_offset =
414 ((off_t)block_index) * INCFS_DATA_FILE_BLOCK_SIZE;
415 size_t block_size = 0;
416
417 if (block_offset > file->size) {
418 error = -EINVAL;
419 break;
420 }
421 if (file->size - block_offset >
422 INCFS_DATA_FILE_BLOCK_SIZE)
423 block_size = INCFS_DATA_FILE_BLOCK_SIZE;
424 else
425 block_size = file->size - block_offset;
426
427 rnd_buf(data, block_size, seed);
428 if (compress_lz4) {
429 size_t comp_size = LZ4_compress_default((char *)data,
430 (char *)comp_data, block_size,
431 ARRAY_SIZE(comp_data));
432
433 if (comp_size <= 0) {
434 error = -EBADMSG;
435 break;
436 }
437 if (current_data + comp_size > data_end) {
438 error = -ENOMEM;
439 break;
440 }
441 memcpy(current_data, comp_data, comp_size);
442 block_size = comp_size;
443 block_buf[i].compression = COMPRESSION_LZ4;
444 } else if (compress_zstd) {
445 size_t comp_size = ZSTD_compress(comp_data,
446 ARRAY_SIZE(comp_data), data, block_size,
447 1);
448
449 if (comp_size <= 0) {
450 error = -EBADMSG;
451 break;
452 }
453 if (current_data + comp_size > data_end) {
454 error = -ENOMEM;
455 break;
456 }
457 memcpy(current_data, comp_data, comp_size);
458 block_size = comp_size;
459 block_buf[i].compression = COMPRESSION_ZSTD;
460 } else {
461 if (current_data + block_size > data_end) {
462 error = -ENOMEM;
463 break;
464 }
465 memcpy(current_data, data, block_size);
466 block_buf[i].compression = COMPRESSION_NONE;
467 }
468
469 block_buf[i].block_index = block_index;
470 block_buf[i].data_len = block_size;
471 block_buf[i].data = ptr_to_u64(current_data);
472 current_data += block_size;
473 }
474
475 if (!error) {
476 fd = open_file_by_id(mnt_dir, file->id, false);
477 if (fd < 0) {
478 error = -errno;
479 goto out;
480 }
481 write_res = ioctl(fd, INCFS_IOC_FILL_BLOCKS, &fill_blocks);
482 if (write_res >= 0) {
483 ksft_print_msg("Wrote to file via normal fd error\n");
484 error = -EPERM;
485 goto out;
486 }
487
488 close(fd);
489 fd = open_file_by_id(mnt_dir, file->id, true);
490 if (fd < 0) {
491 error = -errno;
492 goto out;
493 }
494 write_res = ioctl(fd, INCFS_IOC_FILL_BLOCKS, &fill_blocks);
495 if (write_res < 0)
496 error = -errno;
497 else
498 blocks_written = write_res;
499 }
500 if (error) {
501 ksft_print_msg(
502 "Writing data block error. Write returned: %d. Error:%s\n",
503 write_res, strerror(-error));
504 }
505
506 out:
507 free(block_buf);
508 free(data_buf);
509 close(fd);
510 return (error < 0) ? error : blocks_written;
511 }
512
emit_test_block(const char * mnt_dir,struct test_file * file,int block_index)513 static int emit_test_block(const char *mnt_dir, struct test_file *file,
514 int block_index)
515 {
516 int res = emit_test_blocks(mnt_dir, file, &block_index, 1);
517
518 if (res == 0)
519 return -EINVAL;
520 if (res == 1)
521 return 0;
522 return res;
523 }
524
shuffle(int array[],int count,unsigned int seed)525 static void shuffle(int array[], int count, unsigned int seed)
526 {
527 int i;
528
529 for (i = 0; i < count - 1; i++) {
530 int items_left = count - i;
531 int shuffle_index;
532 int v;
533
534 seed = 1103515245 * seed + 12345;
535 shuffle_index = i + seed % items_left;
536
537 v = array[shuffle_index];
538 array[shuffle_index] = array[i];
539 array[i] = v;
540 }
541 }
542
emit_test_file_data(const char * mount_dir,struct test_file * file)543 static int emit_test_file_data(const char *mount_dir, struct test_file *file)
544 {
545 int i;
546 int block_cnt = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
547 int *block_indexes = NULL;
548 int result = 0;
549 int blocks_written = 0;
550
551 if (file->size == 0)
552 return 0;
553
554 block_indexes = calloc(block_cnt, sizeof(*block_indexes));
555 for (i = 0; i < block_cnt; i++)
556 block_indexes[i] = i;
557 shuffle(block_indexes, block_cnt, file->index);
558
559 for (i = 0; i < block_cnt; i += blocks_written) {
560 blocks_written = emit_test_blocks(mount_dir, file,
561 block_indexes + i, block_cnt - i);
562 if (blocks_written < 0) {
563 result = blocks_written;
564 goto out;
565 }
566 if (blocks_written == 0) {
567 result = -EIO;
568 goto out;
569 }
570 }
571 out:
572 free(block_indexes);
573 return result;
574 }
575
read_whole_file(const char * filename)576 static loff_t read_whole_file(const char *filename)
577 {
578 int fd = -1;
579 loff_t result;
580 loff_t bytes_read = 0;
581 uint8_t buff[16 * 1024];
582
583 fd = open(filename, O_RDONLY | O_CLOEXEC);
584 if (fd <= 0)
585 return fd;
586
587 while (1) {
588 int read_result = read(fd, buff, ARRAY_SIZE(buff));
589
590 if (read_result < 0) {
591 print_error("Error during reading from a file.");
592 result = -errno;
593 goto cleanup;
594 } else if (read_result == 0)
595 break;
596
597 bytes_read += read_result;
598 }
599 result = bytes_read;
600
601 cleanup:
602 close(fd);
603 return result;
604 }
605
read_test_file(uint8_t * buf,size_t len,char * filename,int block_idx)606 static int read_test_file(uint8_t *buf, size_t len, char *filename,
607 int block_idx)
608 {
609 int fd = -1;
610 int result;
611 int bytes_read = 0;
612 size_t bytes_to_read = len;
613 off_t offset = ((off_t)block_idx) * INCFS_DATA_FILE_BLOCK_SIZE;
614
615 fd = open(filename, O_RDONLY | O_CLOEXEC);
616 if (fd <= 0)
617 return fd;
618
619 if (lseek(fd, offset, SEEK_SET) != offset) {
620 print_error("Seek error");
621 return -errno;
622 }
623
624 while (bytes_read < bytes_to_read) {
625 int read_result =
626 read(fd, buf + bytes_read, bytes_to_read - bytes_read);
627 if (read_result < 0) {
628 result = -errno;
629 goto cleanup;
630 } else if (read_result == 0)
631 break;
632
633 bytes_read += read_result;
634 }
635 result = bytes_read;
636
637 cleanup:
638 close(fd);
639 return result;
640 }
641
create_backing_dir(const char * mount_dir)642 static char *create_backing_dir(const char *mount_dir)
643 {
644 struct stat st;
645 char backing_dir_name[255];
646
647 snprintf(backing_dir_name, ARRAY_SIZE(backing_dir_name), "%s-src",
648 mount_dir);
649
650 if (stat(backing_dir_name, &st) == 0) {
651 if (S_ISDIR(st.st_mode)) {
652 int error = delete_dir_tree(backing_dir_name);
653
654 if (error) {
655 ksft_print_msg(
656 "Can't delete existing backing dir. %d\n",
657 error);
658 return NULL;
659 }
660 } else {
661 if (unlink(backing_dir_name)) {
662 print_error("Can't clear backing dir");
663 return NULL;
664 }
665 }
666 }
667
668 if (mkdir(backing_dir_name, 0777)) {
669 if (errno != EEXIST) {
670 print_error("Can't open/create backing dir");
671 return NULL;
672 }
673 }
674
675 return strdup(backing_dir_name);
676 }
677
validate_test_file_content_with_seed(const char * mount_dir,struct test_file * file,unsigned int shuffle_seed)678 static int validate_test_file_content_with_seed(const char *mount_dir,
679 struct test_file *file,
680 unsigned int shuffle_seed)
681 {
682 int error = -1;
683 char *filename = concat_file_name(mount_dir, file->name);
684 off_t size = file->size;
685 loff_t actual_size = get_file_size(filename);
686 int block_cnt = 1 + (size - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
687 int *block_indexes = NULL;
688 int i;
689
690 block_indexes = alloca(sizeof(int) * block_cnt);
691 for (i = 0; i < block_cnt; i++)
692 block_indexes[i] = i;
693
694 if (shuffle_seed != 0)
695 shuffle(block_indexes, block_cnt, shuffle_seed);
696
697 if (actual_size != size) {
698 ksft_print_msg(
699 "File size doesn't match. name: %s expected size:%ld actual size:%ld\n",
700 filename, size, actual_size);
701 error = -1;
702 goto failure;
703 }
704
705 for (i = 0; i < block_cnt; i++) {
706 int block_idx = block_indexes[i];
707 uint8_t expected_block[INCFS_DATA_FILE_BLOCK_SIZE];
708 uint8_t actual_block[INCFS_DATA_FILE_BLOCK_SIZE];
709 int seed = get_file_block_seed(file->index, block_idx);
710 size_t bytes_to_compare = min(
711 (off_t)INCFS_DATA_FILE_BLOCK_SIZE,
712 size - ((off_t)block_idx) * INCFS_DATA_FILE_BLOCK_SIZE);
713 int read_result =
714 read_test_file(actual_block, INCFS_DATA_FILE_BLOCK_SIZE,
715 filename, block_idx);
716 if (read_result < 0) {
717 ksft_print_msg(
718 "Error reading block %d from file %s. Error: %s\n",
719 block_idx, filename, strerror(-read_result));
720 error = read_result;
721 goto failure;
722 }
723 rnd_buf(expected_block, INCFS_DATA_FILE_BLOCK_SIZE, seed);
724 if (memcmp(expected_block, actual_block, bytes_to_compare)) {
725 ksft_print_msg(
726 "File contents don't match. name: %s block:%d\n",
727 file->name, block_idx);
728 error = -2;
729 goto failure;
730 }
731 }
732 free(filename);
733 return 0;
734
735 failure:
736 free(filename);
737 return error;
738 }
739
validate_test_file_content(const char * mount_dir,struct test_file * file)740 static int validate_test_file_content(const char *mount_dir,
741 struct test_file *file)
742 {
743 return validate_test_file_content_with_seed(mount_dir, file, 0);
744 }
745
data_producer(const char * mount_dir,struct test_files_set * test_set)746 static int data_producer(const char *mount_dir, struct test_files_set *test_set)
747 {
748 int ret = 0;
749 int timeout_ms = 1000;
750 struct incfs_pending_read_info prs[100] = {};
751 int prs_size = ARRAY_SIZE(prs);
752 int fd = open_commands_file(mount_dir);
753
754 if (fd < 0)
755 return -errno;
756
757 while ((ret = wait_for_pending_reads(fd, timeout_ms, prs, prs_size)) >
758 0) {
759 int read_count = ret;
760 int i;
761
762 for (i = 0; i < read_count; i++) {
763 int j = 0;
764 struct test_file *file = NULL;
765
766 for (j = 0; j < test_set->files_count; j++) {
767 bool same = same_id(&(test_set->files[j].id),
768 &(prs[i].file_id));
769
770 if (same) {
771 file = &test_set->files[j];
772 break;
773 }
774 }
775 if (!file) {
776 ksft_print_msg(
777 "Unknown file in pending reads.\n");
778 break;
779 }
780
781 ret = emit_test_block(mount_dir, file,
782 prs[i].block_index);
783 if (ret < 0) {
784 ksft_print_msg("Emitting test data error: %s\n",
785 strerror(-ret));
786 break;
787 }
788 }
789 }
790 close(fd);
791 return ret;
792 }
793
data_producer2(const char * mount_dir,struct test_files_set * test_set)794 static int data_producer2(const char *mount_dir,
795 struct test_files_set *test_set)
796 {
797 int ret = 0;
798 int timeout_ms = 1000;
799 struct incfs_pending_read_info2 prs[100] = {};
800 int prs_size = ARRAY_SIZE(prs);
801 int fd = open_commands_file(mount_dir);
802
803 if (fd < 0)
804 return -errno;
805
806 while ((ret = wait_for_pending_reads2(fd, timeout_ms, prs, prs_size)) >
807 0) {
808 int read_count = ret;
809 int i;
810
811 for (i = 0; i < read_count; i++) {
812 int j = 0;
813 struct test_file *file = NULL;
814
815 for (j = 0; j < test_set->files_count; j++) {
816 bool same = same_id(&(test_set->files[j].id),
817 &(prs[i].file_id));
818
819 if (same) {
820 file = &test_set->files[j];
821 break;
822 }
823 }
824 if (!file) {
825 ksft_print_msg(
826 "Unknown file in pending reads.\n");
827 break;
828 }
829
830 ret = emit_test_block(mount_dir, file,
831 prs[i].block_index);
832 if (ret < 0) {
833 ksft_print_msg("Emitting test data error: %s\n",
834 strerror(-ret));
835 break;
836 }
837 }
838 }
839 close(fd);
840 return ret;
841 }
842
build_mtree(struct test_file * file)843 static int build_mtree(struct test_file *file)
844 {
845 char data[INCFS_DATA_FILE_BLOCK_SIZE] = {};
846 const int digest_size = SHA256_DIGEST_SIZE;
847 const int hash_per_block = INCFS_DATA_FILE_BLOCK_SIZE / digest_size;
848 int block_count = 0;
849 int hash_block_count = 0;
850 int total_tree_block_count = 0;
851 int tree_lvl_index[INCFS_MAX_MTREE_LEVELS] = {};
852 int tree_lvl_count[INCFS_MAX_MTREE_LEVELS] = {};
853 int levels_count = 0;
854 int i, level;
855
856 if (file->size == 0)
857 return 0;
858
859 block_count = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
860 hash_block_count = block_count;
861 for (i = 0; hash_block_count > 1; i++) {
862 hash_block_count = (hash_block_count + hash_per_block - 1)
863 / hash_per_block;
864 tree_lvl_count[i] = hash_block_count;
865 total_tree_block_count += hash_block_count;
866 }
867 levels_count = i;
868
869 for (i = 0; i < levels_count; i++) {
870 int prev_lvl_base = (i == 0) ? total_tree_block_count :
871 tree_lvl_index[i - 1];
872
873 tree_lvl_index[i] = prev_lvl_base - tree_lvl_count[i];
874 }
875
876 file->mtree_block_count = total_tree_block_count;
877 if (block_count == 1) {
878 int seed = get_file_block_seed(file->index, 0);
879
880 memset(data, 0, INCFS_DATA_FILE_BLOCK_SIZE);
881 rnd_buf((uint8_t *)data, file->size, seed);
882 sha256(data, INCFS_DATA_FILE_BLOCK_SIZE, file->root_hash);
883 return 0;
884 }
885
886 file->mtree = calloc(total_tree_block_count, sizeof(*file->mtree));
887 /* Build level 0 hashes. */
888 for (i = 0; i < block_count; i++) {
889 off_t offset = i * INCFS_DATA_FILE_BLOCK_SIZE;
890 size_t block_size = INCFS_DATA_FILE_BLOCK_SIZE;
891 int block_index = tree_lvl_index[0] +
892 i / hash_per_block;
893 int block_off = (i % hash_per_block) * digest_size;
894 int seed = get_file_block_seed(file->index, i);
895 char *hash_ptr = file->mtree[block_index].data + block_off;
896
897 if (file->size - offset < block_size) {
898 block_size = file->size - offset;
899 memset(data, 0, INCFS_DATA_FILE_BLOCK_SIZE);
900 }
901
902 rnd_buf((uint8_t *)data, block_size, seed);
903 sha256(data, INCFS_DATA_FILE_BLOCK_SIZE, hash_ptr);
904 }
905
906 /* Build higher levels of hash tree. */
907 for (level = 1; level < levels_count; level++) {
908 int prev_lvl_base = tree_lvl_index[level - 1];
909 int prev_lvl_count = tree_lvl_count[level - 1];
910
911 for (i = 0; i < prev_lvl_count; i++) {
912 int block_index =
913 i / hash_per_block + tree_lvl_index[level];
914 int block_off = (i % hash_per_block) * digest_size;
915 char *hash_ptr =
916 file->mtree[block_index].data + block_off;
917
918 sha256(file->mtree[i + prev_lvl_base].data,
919 INCFS_DATA_FILE_BLOCK_SIZE, hash_ptr);
920 }
921 }
922
923 /* Calculate root hash from the top block */
924 sha256(file->mtree[0].data,
925 INCFS_DATA_FILE_BLOCK_SIZE, file->root_hash);
926
927 return 0;
928 }
929
load_hash_tree(const char * mount_dir,struct test_file * file)930 static int load_hash_tree(const char *mount_dir, struct test_file *file)
931 {
932 int err;
933 int i;
934 int fd;
935 struct incfs_fill_blocks fill_blocks = {
936 .count = file->mtree_block_count,
937 };
938 struct incfs_fill_block *fill_block_array =
939 calloc(fill_blocks.count, sizeof(struct incfs_fill_block));
940
941 if (fill_blocks.count == 0)
942 return 0;
943
944 if (!fill_block_array)
945 return -ENOMEM;
946 fill_blocks.fill_blocks = ptr_to_u64(fill_block_array);
947
948 for (i = 0; i < fill_blocks.count; i++) {
949 fill_block_array[i] = (struct incfs_fill_block){
950 .block_index = i,
951 .data_len = INCFS_DATA_FILE_BLOCK_SIZE,
952 .data = ptr_to_u64(file->mtree[i].data),
953 .flags = INCFS_BLOCK_FLAGS_HASH
954 };
955 }
956
957 fd = open_file_by_id(mount_dir, file->id, false);
958 if (fd < 0) {
959 err = errno;
960 goto failure;
961 }
962
963 err = ioctl(fd, INCFS_IOC_FILL_BLOCKS, &fill_blocks);
964 close(fd);
965 if (err >= 0) {
966 err = -EPERM;
967 goto failure;
968 }
969
970 fd = open_file_by_id(mount_dir, file->id, true);
971 if (fd < 0) {
972 err = errno;
973 goto failure;
974 }
975
976 err = ioctl(fd, INCFS_IOC_FILL_BLOCKS, &fill_blocks);
977 close(fd);
978 if (err < fill_blocks.count)
979 err = errno;
980 else
981 err = 0;
982
983 failure:
984 free(fill_block_array);
985 return err;
986 }
987
cant_touch_index_test(const char * mount_dir)988 static int cant_touch_index_test(const char *mount_dir)
989 {
990 char *file_name = "test_file";
991 int file_size = 123;
992 incfs_uuid_t file_id;
993 char *index_path = concat_file_name(mount_dir, ".index");
994 char *subdir = concat_file_name(index_path, "subdir");
995 char *dst_name = concat_file_name(mount_dir, "something");
996 char *filename_in_index = NULL;
997 char *file_path = concat_file_name(mount_dir, file_name);
998 char *backing_dir;
999 int cmd_fd = -1;
1000 int err;
1001
1002 backing_dir = create_backing_dir(mount_dir);
1003 if (!backing_dir)
1004 goto failure;
1005
1006 /* Mount FS and release the backing file. */
1007 if (mount_fs(mount_dir, backing_dir, 50) != 0)
1008 goto failure;
1009 free(backing_dir);
1010
1011 cmd_fd = open_commands_file(mount_dir);
1012 if (cmd_fd < 0)
1013 goto failure;
1014
1015
1016 err = mkdir(subdir, 0777);
1017 if (err == 0 || errno != EBUSY) {
1018 print_error("Shouldn't be able to crate subdir in index\n");
1019 goto failure;
1020 }
1021
1022 err = rmdir(index_path);
1023 if (err == 0 || errno != EBUSY) {
1024 print_error(".index directory should not be removed\n");
1025 goto failure;
1026 }
1027
1028 err = emit_file(cmd_fd, ".index", file_name, &file_id,
1029 file_size, NULL);
1030 if (err != -EBUSY) {
1031 print_error("Shouldn't be able to crate a file in index\n");
1032 goto failure;
1033 }
1034
1035 err = emit_file(cmd_fd, NULL, file_name, &file_id,
1036 file_size, NULL);
1037 if (err < 0)
1038 goto failure;
1039 filename_in_index = get_index_filename(mount_dir, file_id);
1040
1041 err = unlink(filename_in_index);
1042 if (err == 0 || errno != EBUSY) {
1043 print_error("Shouldn't be delete from index\n");
1044 goto failure;
1045 }
1046
1047
1048 err = rename(filename_in_index, dst_name);
1049 if (err == 0 || errno != EBUSY) {
1050 print_error("Shouldn't be able to move from index\n");
1051 goto failure;
1052 }
1053
1054 free(filename_in_index);
1055 filename_in_index = concat_file_name(index_path, "abc");
1056 err = link(file_path, filename_in_index);
1057 if (err == 0 || errno != EBUSY) {
1058 print_error("Shouldn't be able to link inside index\n");
1059 goto failure;
1060 }
1061
1062 err = rename(index_path, dst_name);
1063 if (err == 0 || errno != EBUSY) {
1064 print_error("Shouldn't rename .index directory\n");
1065 goto failure;
1066 }
1067
1068 close(cmd_fd);
1069 free(subdir);
1070 free(index_path);
1071 free(dst_name);
1072 free(filename_in_index);
1073 if (umount(mount_dir) != 0) {
1074 print_error("Can't unmout FS");
1075 goto failure;
1076 }
1077
1078 return TEST_SUCCESS;
1079
1080 failure:
1081 free(subdir);
1082 free(dst_name);
1083 free(index_path);
1084 free(filename_in_index);
1085 close(cmd_fd);
1086 umount(mount_dir);
1087 return TEST_FAILURE;
1088 }
1089
iterate_directory(const char * dir_to_iterate,bool root,int file_count)1090 static bool iterate_directory(const char *dir_to_iterate, bool root,
1091 int file_count)
1092 {
1093 struct expected_name {
1094 const char *name;
1095 bool root_only;
1096 bool found;
1097 } names[] = {
1098 {INCFS_LOG_FILENAME, true, false},
1099 {INCFS_PENDING_READS_FILENAME, true, false},
1100 {INCFS_BLOCKS_WRITTEN_FILENAME, true, false},
1101 {".index", true, false},
1102 {".incomplete", true, false},
1103 {"..", false, false},
1104 {".", false, false},
1105 };
1106
1107 bool pass = true, found;
1108 int i;
1109
1110 /* Test directory iteration */
1111 int fd = open(dir_to_iterate, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
1112
1113 if (fd < 0) {
1114 print_error("Can't open directory\n");
1115 return false;
1116 }
1117
1118 for (;;) {
1119 /* Enough space for one dirent - no name over 30 */
1120 char buf[sizeof(struct linux_dirent64) + NAME_MAX];
1121 struct linux_dirent64 *dirent = (struct linux_dirent64 *) buf;
1122 int nread;
1123 int i;
1124
1125 for (i = 0; i < NAME_MAX; ++i) {
1126 nread = syscall(__NR_getdents64, fd, buf,
1127 sizeof(struct linux_dirent64) + i);
1128
1129 if (nread >= 0)
1130 break;
1131 if (errno != EINVAL)
1132 break;
1133 }
1134
1135 if (nread == 0)
1136 break;
1137 if (nread < 0) {
1138 print_error("Error iterating directory\n");
1139 pass = false;
1140 goto failure;
1141 }
1142
1143 /* Expected size is rounded up to 8 byte boundary. Not sure if
1144 * this is universal truth or just happenstance, but useful test
1145 * for the moment
1146 */
1147 if (nread != (((sizeof(struct linux_dirent64)
1148 + strlen(dirent->d_name) + 1) + 7) & ~7)) {
1149 print_error("Wrong dirent size");
1150 pass = false;
1151 goto failure;
1152 }
1153
1154 found = false;
1155 for (i = 0; i < sizeof(names) / sizeof(*names); ++i)
1156 if (!strcmp(dirent->d_name, names[i].name)) {
1157 if (names[i].root_only && !root) {
1158 print_error("Root file error");
1159 pass = false;
1160 goto failure;
1161 }
1162
1163 if (names[i].found) {
1164 print_error("File appears twice");
1165 pass = false;
1166 goto failure;
1167 }
1168
1169 names[i].found = true;
1170 found = true;
1171 break;
1172 }
1173
1174 if (!found)
1175 --file_count;
1176 }
1177
1178 for (i = 0; i < sizeof(names) / sizeof(*names); ++i) {
1179 if (!names[i].found)
1180 if (root || !names[i].root_only) {
1181 print_error("Expected file not present");
1182 pass = false;
1183 goto failure;
1184 }
1185 }
1186
1187 if (file_count) {
1188 print_error("Wrong number of files\n");
1189 pass = false;
1190 goto failure;
1191 }
1192
1193 failure:
1194 close(fd);
1195 return pass;
1196 }
1197
basic_file_ops_test(const char * mount_dir)1198 static int basic_file_ops_test(const char *mount_dir)
1199 {
1200 struct test_files_set test = get_test_files_set();
1201 const int file_num = test.files_count;
1202 char *subdir1 = concat_file_name(mount_dir, "subdir1");
1203 char *subdir2 = concat_file_name(mount_dir, "subdir2");
1204 char *backing_dir;
1205 int cmd_fd = -1;
1206 int i, err;
1207
1208 backing_dir = create_backing_dir(mount_dir);
1209 if (!backing_dir)
1210 goto failure;
1211
1212 /* Mount FS and release the backing file. */
1213 if (mount_fs(mount_dir, backing_dir, 50) != 0)
1214 goto failure;
1215 free(backing_dir);
1216
1217 cmd_fd = open_commands_file(mount_dir);
1218 if (cmd_fd < 0)
1219 goto failure;
1220
1221 err = mkdir(subdir1, 0777);
1222 if (err < 0 && errno != EEXIST) {
1223 print_error("Can't create subdir1\n");
1224 goto failure;
1225 }
1226
1227 err = mkdir(subdir2, 0777);
1228 if (err < 0 && errno != EEXIST) {
1229 print_error("Can't create subdir2\n");
1230 goto failure;
1231 }
1232
1233 /* Create all test files in subdir1 directory */
1234 for (i = 0; i < file_num; i++) {
1235 struct test_file *file = &test.files[i];
1236 loff_t size;
1237 char *file_path = concat_file_name(subdir1, file->name);
1238
1239 err = emit_file(cmd_fd, "subdir1", file->name, &file->id,
1240 file->size, NULL);
1241 if (err < 0)
1242 goto failure;
1243
1244 size = get_file_size(file_path);
1245 free(file_path);
1246 if (size != file->size) {
1247 ksft_print_msg("Wrong size %lld of %s.\n",
1248 size, file->name);
1249 goto failure;
1250 }
1251 }
1252
1253 if (!iterate_directory(subdir1, false, file_num))
1254 goto failure;
1255
1256 /* Link the files to subdir2 */
1257 for (i = 0; i < file_num; i++) {
1258 struct test_file *file = &test.files[i];
1259 char *src_name = concat_file_name(subdir1, file->name);
1260 char *dst_name = concat_file_name(subdir2, file->name);
1261 loff_t size;
1262
1263 err = link(src_name, dst_name);
1264 if (err < 0) {
1265 print_error("Can't move file\n");
1266 goto failure;
1267 }
1268
1269 size = get_file_size(dst_name);
1270 if (size != file->size) {
1271 ksft_print_msg("Wrong size %lld of %s.\n",
1272 size, file->name);
1273 goto failure;
1274 }
1275 free(src_name);
1276 free(dst_name);
1277 }
1278
1279 /* Move the files from subdir2 to the mount dir */
1280 for (i = 0; i < file_num; i++) {
1281 struct test_file *file = &test.files[i];
1282 char *src_name = concat_file_name(subdir2, file->name);
1283 char *dst_name = concat_file_name(mount_dir, file->name);
1284 loff_t size;
1285
1286 err = rename(src_name, dst_name);
1287 if (err < 0) {
1288 print_error("Can't move file\n");
1289 goto failure;
1290 }
1291
1292 size = get_file_size(dst_name);
1293 if (size != file->size) {
1294 ksft_print_msg("Wrong size %lld of %s.\n",
1295 size, file->name);
1296 goto failure;
1297 }
1298 free(src_name);
1299 free(dst_name);
1300 }
1301
1302 /* +2 because there are 2 subdirs */
1303 if (!iterate_directory(mount_dir, true, file_num + 2))
1304 goto failure;
1305
1306 /* Open and close all files from the mount dir */
1307 for (i = 0; i < file_num; i++) {
1308 struct test_file *file = &test.files[i];
1309 char *path = concat_file_name(mount_dir, file->name);
1310 int fd;
1311
1312 fd = open(path, O_RDWR | O_CLOEXEC);
1313 free(path);
1314 if (fd <= 0) {
1315 print_error("Can't open file");
1316 goto failure;
1317 }
1318 if (close(fd)) {
1319 print_error("Can't close file");
1320 goto failure;
1321 }
1322 }
1323
1324 /* Delete all files from the mount dir */
1325 for (i = 0; i < file_num; i++) {
1326 struct test_file *file = &test.files[i];
1327 char *path = concat_file_name(mount_dir, file->name);
1328
1329 err = unlink(path);
1330 free(path);
1331 if (err < 0) {
1332 print_error("Can't unlink file");
1333 goto failure;
1334 }
1335 }
1336
1337 err = delete_dir_tree(subdir1);
1338 if (err) {
1339 ksft_print_msg("Error deleting subdir1 %d", err);
1340 goto failure;
1341 }
1342
1343 err = rmdir(subdir2);
1344 if (err) {
1345 print_error("Error deleting subdir2");
1346 goto failure;
1347 }
1348
1349 close(cmd_fd);
1350 cmd_fd = -1;
1351 if (umount(mount_dir) != 0) {
1352 print_error("Can't unmout FS");
1353 goto failure;
1354 }
1355
1356 return TEST_SUCCESS;
1357
1358 failure:
1359 close(cmd_fd);
1360 umount(mount_dir);
1361 return TEST_FAILURE;
1362 }
1363
dynamic_files_and_data_test(const char * mount_dir)1364 static int dynamic_files_and_data_test(const char *mount_dir)
1365 {
1366 struct test_files_set test = get_test_files_set();
1367 const int file_num = test.files_count;
1368 const int missing_file_idx = 5;
1369 int cmd_fd = -1;
1370 char *backing_dir;
1371 int i;
1372
1373 backing_dir = create_backing_dir(mount_dir);
1374 if (!backing_dir)
1375 goto failure;
1376
1377 /* Mount FS and release the backing file. */
1378 if (mount_fs(mount_dir, backing_dir, 50) != 0)
1379 goto failure;
1380 free(backing_dir);
1381
1382 cmd_fd = open_commands_file(mount_dir);
1383 if (cmd_fd < 0)
1384 goto failure;
1385
1386 /* Check that test files don't exist in the filesystem. */
1387 for (i = 0; i < file_num; i++) {
1388 struct test_file *file = &test.files[i];
1389 char *filename = concat_file_name(mount_dir, file->name);
1390
1391 if (access(filename, F_OK) != -1) {
1392 ksft_print_msg(
1393 "File %s somehow already exists in a clean FS.\n",
1394 filename);
1395 goto failure;
1396 }
1397 free(filename);
1398 }
1399
1400 /* Write test data into the command file. */
1401 for (i = 0; i < file_num; i++) {
1402 struct test_file *file = &test.files[i];
1403 int res;
1404
1405 res = emit_file(cmd_fd, NULL, file->name, &file->id,
1406 file->size, NULL);
1407 if (res < 0) {
1408 ksft_print_msg("Error %s emiting file %s.\n",
1409 strerror(-res), file->name);
1410 goto failure;
1411 }
1412
1413 /* Skip writing data to one file so we can check */
1414 /* that it's missing later. */
1415 if (i == missing_file_idx)
1416 continue;
1417
1418 res = emit_test_file_data(mount_dir, file);
1419 if (res) {
1420 ksft_print_msg("Error %s emiting data for %s.\n",
1421 strerror(-res), file->name);
1422 goto failure;
1423 }
1424 }
1425
1426 /* Validate contents of the FS */
1427 for (i = 0; i < file_num; i++) {
1428 struct test_file *file = &test.files[i];
1429
1430 if (i == missing_file_idx) {
1431 /* No data has been written to this file. */
1432 /* Check for read error; */
1433 uint8_t buf;
1434 char *filename =
1435 concat_file_name(mount_dir, file->name);
1436 int res = read_test_file(&buf, 1, filename, 0);
1437
1438 free(filename);
1439 if (res > 0) {
1440 ksft_print_msg(
1441 "Data present, even though never writtern.\n");
1442 goto failure;
1443 }
1444 if (res != -ETIME) {
1445 ksft_print_msg("Wrong error code: %d.\n", res);
1446 goto failure;
1447 }
1448 } else {
1449 if (validate_test_file_content(mount_dir, file) < 0)
1450 goto failure;
1451 }
1452 }
1453
1454 close(cmd_fd);
1455 cmd_fd = -1;
1456 if (umount(mount_dir) != 0) {
1457 print_error("Can't unmout FS");
1458 goto failure;
1459 }
1460
1461 return TEST_SUCCESS;
1462
1463 failure:
1464 close(cmd_fd);
1465 umount(mount_dir);
1466 return TEST_FAILURE;
1467 }
1468
concurrent_reads_and_writes_test(const char * mount_dir)1469 static int concurrent_reads_and_writes_test(const char *mount_dir)
1470 {
1471 struct test_files_set test = get_test_files_set();
1472 const int file_num = test.files_count;
1473 /* Validate each file from that many child processes. */
1474 const int child_multiplier = 3;
1475 int cmd_fd = -1;
1476 char *backing_dir;
1477 int status;
1478 int i;
1479 pid_t producer_pid;
1480 pid_t *child_pids = alloca(child_multiplier * file_num * sizeof(pid_t));
1481
1482 backing_dir = create_backing_dir(mount_dir);
1483 if (!backing_dir)
1484 goto failure;
1485
1486 /* Mount FS and release the backing file. */
1487 if (mount_fs(mount_dir, backing_dir, 500) != 0)
1488 goto failure;
1489 free(backing_dir);
1490
1491 cmd_fd = open_commands_file(mount_dir);
1492 if (cmd_fd < 0)
1493 goto failure;
1494
1495 /* Tell FS about the files, without actually providing the data. */
1496 for (i = 0; i < file_num; i++) {
1497 struct test_file *file = &test.files[i];
1498 int res;
1499
1500 res = emit_file(cmd_fd, NULL, file->name, &file->id,
1501 file->size, NULL);
1502 if (res)
1503 goto failure;
1504 }
1505
1506 /* Start child processes acessing data in the files */
1507 for (i = 0; i < file_num * child_multiplier; i++) {
1508 struct test_file *file = &test.files[i / child_multiplier];
1509 pid_t child_pid = flush_and_fork();
1510
1511 if (child_pid == 0) {
1512 /* This is a child process, do the data validation. */
1513 int ret = validate_test_file_content_with_seed(
1514 mount_dir, file, i);
1515 if (ret >= 0) {
1516 /* Zero exit status if data is valid. */
1517 exit(0);
1518 }
1519
1520 /* Positive status if validation error found. */
1521 exit(-ret);
1522 } else if (child_pid > 0) {
1523 child_pids[i] = child_pid;
1524 } else {
1525 print_error("Fork error");
1526 goto failure;
1527 }
1528 }
1529
1530 producer_pid = flush_and_fork();
1531 if (producer_pid == 0) {
1532 int ret;
1533 /*
1534 * This is a child that should provide data to
1535 * pending reads.
1536 */
1537
1538 ret = data_producer(mount_dir, &test);
1539 exit(-ret);
1540 } else {
1541 status = wait_for_process(producer_pid);
1542 if (status != 0) {
1543 ksft_print_msg("Data produces failed. %d(%s) ", status,
1544 strerror(status));
1545 goto failure;
1546 }
1547 }
1548
1549 /* Check that all children has finished with 0 exit status */
1550 for (i = 0; i < file_num * child_multiplier; i++) {
1551 struct test_file *file = &test.files[i / child_multiplier];
1552
1553 status = wait_for_process(child_pids[i]);
1554 if (status != 0) {
1555 ksft_print_msg(
1556 "Validation for the file %s failed with code %d (%s)\n",
1557 file->name, status, strerror(status));
1558 goto failure;
1559 }
1560 }
1561
1562 /* Check that there are no pending reads left */
1563 {
1564 struct incfs_pending_read_info prs[1] = {};
1565 int timeout = 0;
1566 int read_count = wait_for_pending_reads(cmd_fd, timeout, prs,
1567 ARRAY_SIZE(prs));
1568
1569 if (read_count) {
1570 ksft_print_msg(
1571 "Pending reads pending when all data written\n");
1572 goto failure;
1573 }
1574 }
1575
1576 close(cmd_fd);
1577 cmd_fd = -1;
1578 if (umount(mount_dir) != 0) {
1579 print_error("Can't unmout FS");
1580 goto failure;
1581 }
1582
1583 return TEST_SUCCESS;
1584
1585 failure:
1586 close(cmd_fd);
1587 umount(mount_dir);
1588 return TEST_FAILURE;
1589 }
1590
work_after_remount_test(const char * mount_dir)1591 static int work_after_remount_test(const char *mount_dir)
1592 {
1593 struct test_files_set test = get_test_files_set();
1594 const int file_num = test.files_count;
1595 const int file_num_stage1 = file_num / 2;
1596 const int file_num_stage2 = file_num;
1597 char *backing_dir = NULL;
1598 int i = 0;
1599 int cmd_fd = -1;
1600
1601 backing_dir = create_backing_dir(mount_dir);
1602 if (!backing_dir)
1603 goto failure;
1604
1605 /* Mount FS and release the backing file. */
1606 if (mount_fs(mount_dir, backing_dir, 50) != 0)
1607 goto failure;
1608
1609 cmd_fd = open_commands_file(mount_dir);
1610 if (cmd_fd < 0)
1611 goto failure;
1612
1613 /* Write first half of the data into the command file. (stage 1) */
1614 for (i = 0; i < file_num_stage1; i++) {
1615 struct test_file *file = &test.files[i];
1616
1617 if (emit_file(cmd_fd, NULL, file->name, &file->id,
1618 file->size, NULL))
1619 goto failure;
1620
1621 if (emit_test_file_data(mount_dir, file))
1622 goto failure;
1623 }
1624
1625 /* Unmount and mount again, to see that data is persistent. */
1626 close(cmd_fd);
1627 cmd_fd = -1;
1628 if (umount(mount_dir) != 0) {
1629 print_error("Can't unmout FS");
1630 goto failure;
1631 }
1632
1633 if (mount_fs(mount_dir, backing_dir, 50) != 0)
1634 goto failure;
1635
1636 cmd_fd = open_commands_file(mount_dir);
1637 if (cmd_fd < 0)
1638 goto failure;
1639
1640 /* Write the second half of the data into the command file. (stage 2) */
1641 for (; i < file_num_stage2; i++) {
1642 struct test_file *file = &test.files[i];
1643 int res = emit_file(cmd_fd, NULL, file->name, &file->id,
1644 file->size, NULL);
1645
1646 if (res)
1647 goto failure;
1648
1649 if (emit_test_file_data(mount_dir, file))
1650 goto failure;
1651 }
1652
1653 /* Validate contents of the FS */
1654 for (i = 0; i < file_num_stage2; i++) {
1655 struct test_file *file = &test.files[i];
1656
1657 if (validate_test_file_content(mount_dir, file) < 0)
1658 goto failure;
1659 }
1660
1661 /* Delete all files */
1662 for (i = 0; i < file_num; i++) {
1663 struct test_file *file = &test.files[i];
1664 char *filename = concat_file_name(mount_dir, file->name);
1665 char *filename_in_index = get_index_filename(mount_dir,
1666 file->id);
1667
1668 if (access(filename, F_OK) != 0) {
1669 ksft_print_msg("File %s is not visible.\n", filename);
1670 goto failure;
1671 }
1672
1673 if (access(filename_in_index, F_OK) != 0) {
1674 ksft_print_msg("File %s is not visible.\n",
1675 filename_in_index);
1676 goto failure;
1677 }
1678
1679 unlink(filename);
1680
1681 if (access(filename, F_OK) != -1) {
1682 ksft_print_msg("File %s is still present.\n", filename);
1683 goto failure;
1684 }
1685
1686 if (access(filename_in_index, F_OK) != -1) {
1687 ksft_print_msg("File %s is still present.\n",
1688 filename_in_index);
1689 goto failure;
1690 }
1691 free(filename);
1692 free(filename_in_index);
1693 }
1694
1695 /* Unmount and mount again, to see that deleted files stay deleted. */
1696 close(cmd_fd);
1697 cmd_fd = -1;
1698 if (umount(mount_dir) != 0) {
1699 print_error("Can't unmout FS");
1700 goto failure;
1701 }
1702
1703 if (mount_fs(mount_dir, backing_dir, 50) != 0)
1704 goto failure;
1705
1706 cmd_fd = open_commands_file(mount_dir);
1707 if (cmd_fd < 0)
1708 goto failure;
1709
1710 /* Validate all deleted files are still deleted. */
1711 for (i = 0; i < file_num; i++) {
1712 struct test_file *file = &test.files[i];
1713 char *filename = concat_file_name(mount_dir, file->name);
1714
1715 if (access(filename, F_OK) != -1) {
1716 ksft_print_msg("File %s is still visible.\n", filename);
1717 goto failure;
1718 }
1719 free(filename);
1720 }
1721
1722 /* Final unmount */
1723 close(cmd_fd);
1724 free(backing_dir);
1725 cmd_fd = -1;
1726 if (umount(mount_dir) != 0) {
1727 print_error("Can't unmout FS");
1728 goto failure;
1729 }
1730
1731 return TEST_SUCCESS;
1732
1733 failure:
1734 close(cmd_fd);
1735 free(backing_dir);
1736 umount(mount_dir);
1737 return TEST_FAILURE;
1738 }
1739
attribute_test(const char * mount_dir)1740 static int attribute_test(const char *mount_dir)
1741 {
1742 char file_attr[] = "metadata123123";
1743 char attr_buf[INCFS_MAX_FILE_ATTR_SIZE] = {};
1744 int cmd_fd = -1;
1745 incfs_uuid_t file_id;
1746 int attr_res = 0;
1747 char *backing_dir;
1748
1749
1750 backing_dir = create_backing_dir(mount_dir);
1751 if (!backing_dir)
1752 goto failure;
1753
1754 /* Mount FS and release the backing file. */
1755 if (mount_fs(mount_dir, backing_dir, 50) != 0)
1756 goto failure;
1757
1758
1759 cmd_fd = open_commands_file(mount_dir);
1760 if (cmd_fd < 0)
1761 goto failure;
1762
1763 if (emit_file(cmd_fd, NULL, "file", &file_id, 12, file_attr))
1764 goto failure;
1765
1766 /* Test attribute values */
1767 attr_res = get_file_attr(mount_dir, file_id, attr_buf,
1768 ARRAY_SIZE(attr_buf));
1769 if (attr_res != strlen(file_attr)) {
1770 ksft_print_msg("Get file attr error: %d\n", attr_res);
1771 goto failure;
1772 }
1773 if (strcmp(attr_buf, file_attr) != 0) {
1774 ksft_print_msg("Incorrect file attr value: '%s'", attr_buf);
1775 goto failure;
1776 }
1777
1778 /* Unmount and mount again, to see that attributes are persistent. */
1779 close(cmd_fd);
1780 cmd_fd = -1;
1781 if (umount(mount_dir) != 0) {
1782 print_error("Can't unmout FS");
1783 goto failure;
1784 }
1785
1786 if (mount_fs(mount_dir, backing_dir, 50) != 0)
1787 goto failure;
1788
1789 cmd_fd = open_commands_file(mount_dir);
1790 if (cmd_fd < 0)
1791 goto failure;
1792
1793 /* Test attribute values again after remount*/
1794 attr_res = get_file_attr(mount_dir, file_id, attr_buf,
1795 ARRAY_SIZE(attr_buf));
1796 if (attr_res != strlen(file_attr)) {
1797 ksft_print_msg("Get dir attr error: %d\n", attr_res);
1798 goto failure;
1799 }
1800 if (strcmp(attr_buf, file_attr) != 0) {
1801 ksft_print_msg("Incorrect file attr value: '%s'", attr_buf);
1802 goto failure;
1803 }
1804
1805 /* Final unmount */
1806 close(cmd_fd);
1807 free(backing_dir);
1808 cmd_fd = -1;
1809 if (umount(mount_dir) != 0) {
1810 print_error("Can't unmout FS");
1811 goto failure;
1812 }
1813
1814 return TEST_SUCCESS;
1815
1816 failure:
1817 close(cmd_fd);
1818 free(backing_dir);
1819 umount(mount_dir);
1820 return TEST_FAILURE;
1821 }
1822
child_procs_waiting_for_data_test(const char * mount_dir)1823 static int child_procs_waiting_for_data_test(const char *mount_dir)
1824 {
1825 struct test_files_set test = get_test_files_set();
1826 const int file_num = test.files_count;
1827 int cmd_fd = -1;
1828 int i;
1829 pid_t *child_pids = alloca(file_num * sizeof(pid_t));
1830 char *backing_dir;
1831
1832 backing_dir = create_backing_dir(mount_dir);
1833 if (!backing_dir)
1834 goto failure;
1835
1836 /* Mount FS and release the backing file. (10s wait time) */
1837 if (mount_fs(mount_dir, backing_dir, 10000) != 0)
1838 goto failure;
1839
1840
1841 cmd_fd = open_commands_file(mount_dir);
1842 if (cmd_fd < 0)
1843 goto failure;
1844
1845 /* Tell FS about the files, without actually providing the data. */
1846 for (i = 0; i < file_num; i++) {
1847 struct test_file *file = &test.files[i];
1848
1849 emit_file(cmd_fd, NULL, file->name, &file->id,
1850 file->size, NULL);
1851 }
1852
1853 /* Start child processes acessing data in the files */
1854 for (i = 0; i < file_num; i++) {
1855 struct test_file *file = &test.files[i];
1856 pid_t child_pid = flush_and_fork();
1857
1858 if (child_pid == 0) {
1859 /* This is a child process, do the data validation. */
1860 int ret = validate_test_file_content(mount_dir, file);
1861
1862 if (ret >= 0) {
1863 /* Zero exit status if data is valid. */
1864 exit(0);
1865 }
1866
1867 /* Positive status if validation error found. */
1868 exit(-ret);
1869 } else if (child_pid > 0) {
1870 child_pids[i] = child_pid;
1871 } else {
1872 print_error("Fork error");
1873 goto failure;
1874 }
1875 }
1876
1877 /* Write test data into the command file. */
1878 for (i = 0; i < file_num; i++) {
1879 struct test_file *file = &test.files[i];
1880
1881 if (emit_test_file_data(mount_dir, file))
1882 goto failure;
1883 }
1884
1885 /* Check that all children has finished with 0 exit status */
1886 for (i = 0; i < file_num; i++) {
1887 struct test_file *file = &test.files[i];
1888 int status = wait_for_process(child_pids[i]);
1889
1890 if (status != 0) {
1891 ksft_print_msg(
1892 "Validation for the file %s failed with code %d (%s)\n",
1893 file->name, status, strerror(status));
1894 goto failure;
1895 }
1896 }
1897
1898 close(cmd_fd);
1899 free(backing_dir);
1900 cmd_fd = -1;
1901 if (umount(mount_dir) != 0) {
1902 print_error("Can't unmout FS");
1903 goto failure;
1904 }
1905
1906 return TEST_SUCCESS;
1907
1908 failure:
1909 close(cmd_fd);
1910 free(backing_dir);
1911 umount(mount_dir);
1912 return TEST_FAILURE;
1913 }
1914
multiple_providers_test(const char * mount_dir)1915 static int multiple_providers_test(const char *mount_dir)
1916 {
1917 struct test_files_set test = get_test_files_set();
1918 const int file_num = test.files_count;
1919 const int producer_count = 5;
1920 int cmd_fd = -1;
1921 int status;
1922 int i;
1923 pid_t *producer_pids = alloca(producer_count * sizeof(pid_t));
1924 char *backing_dir;
1925
1926 backing_dir = create_backing_dir(mount_dir);
1927 if (!backing_dir)
1928 goto failure;
1929
1930 /* Mount FS and release the backing file. (10s wait time) */
1931 if (mount_fs_opt(mount_dir, backing_dir,
1932 "read_timeout_ms=10000,report_uid", false) != 0)
1933 goto failure;
1934
1935 cmd_fd = open_commands_file(mount_dir);
1936 if (cmd_fd < 0)
1937 goto failure;
1938
1939 /* Tell FS about the files, without actually providing the data. */
1940 for (i = 0; i < file_num; i++) {
1941 struct test_file *file = &test.files[i];
1942
1943 if (emit_file(cmd_fd, NULL, file->name, &file->id,
1944 file->size, NULL) < 0)
1945 goto failure;
1946 }
1947
1948 /* Start producer processes */
1949 for (i = 0; i < producer_count; i++) {
1950 pid_t producer_pid = flush_and_fork();
1951
1952 if (producer_pid == 0) {
1953 int ret;
1954 /*
1955 * This is a child that should provide data to
1956 * pending reads.
1957 */
1958
1959 ret = data_producer2(mount_dir, &test);
1960 exit(-ret);
1961 } else if (producer_pid > 0) {
1962 producer_pids[i] = producer_pid;
1963 } else {
1964 print_error("Fork error");
1965 goto failure;
1966 }
1967 }
1968
1969 /* Validate FS content */
1970 for (i = 0; i < file_num; i++) {
1971 struct test_file *file = &test.files[i];
1972 char *filename = concat_file_name(mount_dir, file->name);
1973 loff_t read_result = read_whole_file(filename);
1974
1975 free(filename);
1976 if (read_result != file->size) {
1977 ksft_print_msg(
1978 "Error validating file %s. Result: %ld\n",
1979 file->name, read_result);
1980 goto failure;
1981 }
1982 }
1983
1984 /* Check that all producers has finished with 0 exit status */
1985 for (i = 0; i < producer_count; i++) {
1986 status = wait_for_process(producer_pids[i]);
1987 if (status != 0) {
1988 ksft_print_msg("Producer %d failed with code (%s)\n", i,
1989 strerror(status));
1990 goto failure;
1991 }
1992 }
1993
1994 close(cmd_fd);
1995 free(backing_dir);
1996 cmd_fd = -1;
1997 if (umount(mount_dir) != 0) {
1998 print_error("Can't unmout FS");
1999 goto failure;
2000 }
2001
2002 return TEST_SUCCESS;
2003
2004 failure:
2005 close(cmd_fd);
2006 free(backing_dir);
2007 umount(mount_dir);
2008 return TEST_FAILURE;
2009 }
2010
validate_hash_tree(const char * mount_dir,struct test_file * file)2011 static int validate_hash_tree(const char *mount_dir, struct test_file *file)
2012 {
2013 int result = TEST_FAILURE;
2014 char *filename = NULL;
2015 int fd = -1;
2016 unsigned char *buf;
2017 int i, err;
2018
2019 TEST(filename = concat_file_name(mount_dir, file->name), filename);
2020 TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
2021 TEST(buf = malloc(INCFS_DATA_FILE_BLOCK_SIZE * 8), buf);
2022
2023 for (i = 0; i < file->mtree_block_count; ) {
2024 int blocks_to_read = i % 7 + 1;
2025 struct fsverity_read_metadata_arg args = {
2026 .metadata_type = FS_VERITY_METADATA_TYPE_MERKLE_TREE,
2027 .offset = i * INCFS_DATA_FILE_BLOCK_SIZE,
2028 .length = blocks_to_read * INCFS_DATA_FILE_BLOCK_SIZE,
2029 .buf_ptr = ptr_to_u64(buf),
2030 };
2031
2032 TEST(err = ioctl(fd, FS_IOC_READ_VERITY_METADATA, &args),
2033 err == min(args.length, (file->mtree_block_count - i) *
2034 INCFS_DATA_FILE_BLOCK_SIZE));
2035 TESTEQUAL(memcmp(buf, file->mtree[i].data, err), 0);
2036
2037 i += blocks_to_read;
2038 }
2039
2040 result = TEST_SUCCESS;
2041
2042 out:
2043 free(buf);
2044 close(fd);
2045 free(filename);
2046 return result;
2047 }
2048
hash_tree_test(const char * mount_dir)2049 static int hash_tree_test(const char *mount_dir)
2050 {
2051 int result = TEST_FAILURE;
2052 char *backing_dir;
2053 struct test_files_set test = get_test_files_set();
2054 const int file_num = test.files_count;
2055 const int corrupted_file_idx = 5;
2056 int i = 0;
2057 int cmd_fd = -1;
2058
2059 backing_dir = create_backing_dir(mount_dir);
2060 if (!backing_dir)
2061 goto failure;
2062
2063 /* Mount FS and release the backing file. */
2064 if (mount_fs(mount_dir, backing_dir, 50) != 0)
2065 goto failure;
2066
2067 cmd_fd = open_commands_file(mount_dir);
2068 if (cmd_fd < 0)
2069 goto failure;
2070
2071 /* Write hashes and data. */
2072 for (i = 0; i < file_num; i++) {
2073 struct test_file *file = &test.files[i];
2074 int res;
2075
2076 build_mtree(file);
2077 res = crypto_emit_file(cmd_fd, NULL, file->name, &file->id,
2078 file->size, file->root_hash,
2079 file->sig.add_data);
2080
2081 if (i == corrupted_file_idx) {
2082 /* Corrupt third blocks hash */
2083 file->mtree[0].data[2 * SHA256_DIGEST_SIZE] ^= 0xff;
2084 }
2085 if (emit_test_file_data(mount_dir, file))
2086 goto failure;
2087
2088 res = load_hash_tree(mount_dir, file);
2089 if (res) {
2090 ksft_print_msg("Can't load hashes for %s. error: %s\n",
2091 file->name, strerror(-res));
2092 goto failure;
2093 }
2094 }
2095
2096 /* Validate data */
2097 for (i = 0; i < file_num; i++) {
2098 struct test_file *file = &test.files[i];
2099
2100 if (i == corrupted_file_idx) {
2101 uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE];
2102 char *filename =
2103 concat_file_name(mount_dir, file->name);
2104 int res;
2105
2106 res = read_test_file(data, INCFS_DATA_FILE_BLOCK_SIZE,
2107 filename, 2);
2108 free(filename);
2109 if (res != -EBADMSG) {
2110 ksft_print_msg("Hash violation missed1. %d\n",
2111 res);
2112 goto failure;
2113 }
2114 } else if (validate_test_file_content(mount_dir, file) < 0)
2115 goto failure;
2116 else if (validate_hash_tree(mount_dir, file) < 0)
2117 goto failure;
2118 }
2119
2120 /* Unmount and mount again, to that hashes are persistent. */
2121 close(cmd_fd);
2122 cmd_fd = -1;
2123 if (umount(mount_dir) != 0) {
2124 print_error("Can't unmout FS");
2125 goto failure;
2126 }
2127 if (mount_fs(mount_dir, backing_dir, 50) != 0)
2128 goto failure;
2129
2130 cmd_fd = open_commands_file(mount_dir);
2131 if (cmd_fd < 0)
2132 goto failure;
2133
2134 /* Validate data again */
2135 for (i = 0; i < file_num; i++) {
2136 struct test_file *file = &test.files[i];
2137
2138 if (i == corrupted_file_idx) {
2139 uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE];
2140 char *filename =
2141 concat_file_name(mount_dir, file->name);
2142 int res;
2143
2144 res = read_test_file(data, INCFS_DATA_FILE_BLOCK_SIZE,
2145 filename, 2);
2146 free(filename);
2147 if (res != -EBADMSG) {
2148 ksft_print_msg("Hash violation missed2. %d\n",
2149 res);
2150 goto failure;
2151 }
2152 } else if (validate_test_file_content(mount_dir, file) < 0)
2153 goto failure;
2154 }
2155 result = TEST_SUCCESS;
2156
2157 failure:
2158 for (i = 0; i < file_num; i++) {
2159 struct test_file *file = &test.files[i];
2160
2161 free(file->mtree);
2162 }
2163
2164 close(cmd_fd);
2165 free(backing_dir);
2166 umount(mount_dir);
2167 return result;
2168 }
2169
2170 enum expected_log { FULL_LOG, NO_LOG, PARTIAL_LOG };
2171
validate_logs(const char * mount_dir,int log_fd,struct test_file * file,enum expected_log expected_log,bool report_uid,bool expect_data)2172 static int validate_logs(const char *mount_dir, int log_fd,
2173 struct test_file *file,
2174 enum expected_log expected_log,
2175 bool report_uid, bool expect_data)
2176 {
2177 int result = TEST_FAILURE;
2178 uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE];
2179 struct incfs_pending_read_info prs[2048] = {};
2180 struct incfs_pending_read_info2 prs2[2048] = {};
2181 struct incfs_pending_read_info *previous_record = NULL;
2182 int prs_size = ARRAY_SIZE(prs);
2183 int block_count = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
2184 int expected_read_count, read_count, block_index, read_index;
2185 char *filename = NULL;
2186 int fd = -1;
2187
2188 TEST(filename = concat_file_name(mount_dir, file->name), filename);
2189 TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
2190
2191 if (block_count > prs_size)
2192 block_count = prs_size;
2193 expected_read_count = block_count;
2194
2195 for (block_index = 0; block_index < block_count; block_index++) {
2196 int result = pread(fd, data, sizeof(data),
2197 INCFS_DATA_FILE_BLOCK_SIZE * block_index);
2198
2199 /* Make some read logs of type SAME_FILE_NEXT_BLOCK */
2200 if (block_index % 100 == 10)
2201 usleep(20000);
2202
2203 /* Skip some blocks to make logs of type SAME_FILE */
2204 if (block_index % 10 == 5) {
2205 ++block_index;
2206 --expected_read_count;
2207 }
2208
2209 if (expect_data)
2210 TESTCOND(result > 0);
2211
2212 if (!expect_data)
2213 TESTEQUAL(result, -1);
2214 }
2215
2216 if (report_uid)
2217 read_count = wait_for_pending_reads2(log_fd,
2218 expected_log == NO_LOG ? 10 : 0,
2219 prs2, prs_size);
2220 else
2221 read_count = wait_for_pending_reads(log_fd,
2222 expected_log == NO_LOG ? 10 : 0,
2223 prs, prs_size);
2224
2225 if (expected_log == NO_LOG)
2226 TESTEQUAL(read_count, 0);
2227
2228 if (expected_log == PARTIAL_LOG)
2229 TESTCOND(read_count > 0 &&
2230 read_count <= expected_read_count);
2231
2232 if (expected_log == FULL_LOG)
2233 TESTEQUAL(read_count, expected_read_count);
2234
2235 /* If read less than expected, advance block_index appropriately */
2236 for (block_index = 0, read_index = 0;
2237 read_index < expected_read_count - read_count;
2238 block_index++, read_index++)
2239 if (block_index % 10 == 5)
2240 ++block_index;
2241
2242 for (read_index = 0; read_index < read_count;
2243 block_index++, read_index++) {
2244 struct incfs_pending_read_info *record = report_uid ?
2245 (struct incfs_pending_read_info *) &prs2[read_index] :
2246 &prs[read_index];
2247
2248 TESTCOND(same_id(&record->file_id, &file->id));
2249 TESTEQUAL(record->block_index, block_index);
2250 TESTNE(record->timestamp_us, 0);
2251 if (previous_record)
2252 TESTEQUAL(record->serial_number,
2253 previous_record->serial_number + 1);
2254
2255 previous_record = record;
2256 if (block_index % 10 == 5)
2257 ++block_index;
2258 }
2259
2260 result = TEST_SUCCESS;
2261 out:
2262 close(fd);
2263 free(filename);
2264 return result;
2265 }
2266
read_log_test(const char * mount_dir)2267 static int read_log_test(const char *mount_dir)
2268 {
2269 int result = TEST_FAILURE;
2270 struct test_files_set test = get_test_files_set();
2271 const int file_num = test.files_count;
2272 int i = 0;
2273 int cmd_fd = -1, log_fd = -1;
2274 char *backing_dir = NULL;
2275
2276 /* Create files */
2277 TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
2278 TESTEQUAL(mount_fs_opt(mount_dir, backing_dir,
2279 "readahead=0,report_uid,read_timeout_ms=0",
2280 false), 0);
2281 TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
2282 for (i = 0; i < file_num; i++) {
2283 struct test_file *file = &test.files[i];
2284
2285 TESTEQUAL(emit_file(cmd_fd, NULL, file->name, &file->id,
2286 file->size, NULL), 0);
2287 }
2288 close(cmd_fd);
2289 cmd_fd = -1;
2290
2291 /* Validate logs */
2292 TEST(log_fd = open_log_file(mount_dir), log_fd != -1);
2293 for (i = 0; i < file_num; i++)
2294 TESTEQUAL(validate_logs(mount_dir, log_fd, &test.files[i],
2295 FULL_LOG, true, false), 0);
2296
2297 /* Unmount and mount again without report_uid */
2298 close(log_fd);
2299 log_fd = -1;
2300 TESTEQUAL(umount(mount_dir), 0);
2301 TESTEQUAL(mount_fs_opt(mount_dir, backing_dir,
2302 "readahead=0,read_timeout_ms=0", false), 0);
2303
2304 TEST(log_fd = open_log_file(mount_dir), log_fd != -1);
2305 for (i = 0; i < file_num; i++)
2306 TESTEQUAL(validate_logs(mount_dir, log_fd, &test.files[i],
2307 FULL_LOG, false, false), 0);
2308
2309 /* No read log to make sure poll doesn't crash */
2310 close(log_fd);
2311 log_fd = -1;
2312 TESTEQUAL(umount(mount_dir), 0);
2313 TESTEQUAL(mount_fs_opt(mount_dir, backing_dir,
2314 "readahead=0,rlog_pages=0,read_timeout_ms=0",
2315 false), 0);
2316
2317 TEST(log_fd = open_log_file(mount_dir), log_fd != -1);
2318 for (i = 0; i < file_num; i++)
2319 TESTEQUAL(validate_logs(mount_dir, log_fd, &test.files[i],
2320 NO_LOG, false, false), 0);
2321
2322 /* Remount and check that logs start working again */
2323 TESTEQUAL(mount_fs_opt(mount_dir, backing_dir,
2324 "readahead=0,rlog_pages=1,read_timeout_ms=0",
2325 true), 0);
2326 for (i = 0; i < file_num; i++)
2327 TESTEQUAL(validate_logs(mount_dir, log_fd, &test.files[i],
2328 PARTIAL_LOG, false, false), 0);
2329
2330 /* Remount and check that logs continue working */
2331 TESTEQUAL(mount_fs_opt(mount_dir, backing_dir,
2332 "readahead=0,rlog_pages=4,read_timeout_ms=0",
2333 true), 0);
2334 for (i = 0; i < file_num; i++)
2335 TESTEQUAL(validate_logs(mount_dir, log_fd, &test.files[i],
2336 FULL_LOG, false, false), 0);
2337
2338 /* Check logs work with data */
2339 for (i = 0; i < file_num; i++) {
2340 TESTEQUAL(emit_test_file_data(mount_dir, &test.files[i]), 0);
2341 TESTEQUAL(validate_logs(mount_dir, log_fd, &test.files[i],
2342 FULL_LOG, false, true), 0);
2343 }
2344
2345 /* Final unmount */
2346 close(log_fd);
2347 log_fd = -1;
2348 TESTEQUAL(umount(mount_dir), 0);
2349
2350 result = TEST_SUCCESS;
2351 out:
2352 close(cmd_fd);
2353 close(log_fd);
2354 free(backing_dir);
2355 umount(mount_dir);
2356 return result;
2357 }
2358
emit_partial_test_file_data(const char * mount_dir,struct test_file * file)2359 static int emit_partial_test_file_data(const char *mount_dir,
2360 struct test_file *file)
2361 {
2362 int i, j;
2363 int block_cnt = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
2364 int *block_indexes = NULL;
2365 int result = 0;
2366 int blocks_written = 0;
2367 int bw_fd = -1;
2368 char buffer[20];
2369 struct pollfd pollfd;
2370 long blocks_written_total, blocks_written_new_total;
2371
2372 if (file->size == 0)
2373 return 0;
2374
2375 bw_fd = open_blocks_written_file(mount_dir);
2376 if (bw_fd == -1)
2377 return -errno;
2378
2379 result = read(bw_fd, buffer, sizeof(buffer));
2380 if (result <= 0) {
2381 result = -EIO;
2382 goto out;
2383 }
2384
2385 buffer[result] = 0;
2386 blocks_written_total = strtol(buffer, NULL, 10);
2387 result = 0;
2388
2389 pollfd = (struct pollfd) {
2390 .fd = bw_fd,
2391 .events = POLLIN,
2392 };
2393
2394 result = poll(&pollfd, 1, 0);
2395 if (result) {
2396 result = -EIO;
2397 goto out;
2398 }
2399
2400 /* Emit 2 blocks, skip 2 blocks etc*/
2401 block_indexes = calloc(block_cnt, sizeof(*block_indexes));
2402 for (i = 0, j = 0; i < block_cnt; ++i)
2403 if ((i & 2) == 0) {
2404 block_indexes[j] = i;
2405 ++j;
2406 }
2407
2408 for (i = 0; i < j; i += blocks_written) {
2409 blocks_written = emit_test_blocks(mount_dir, file,
2410 block_indexes + i, j - i);
2411 if (blocks_written < 0) {
2412 result = blocks_written;
2413 goto out;
2414 }
2415 if (blocks_written == 0) {
2416 result = -EIO;
2417 goto out;
2418 }
2419
2420 result = poll(&pollfd, 1, 0);
2421 if (result != 1 || pollfd.revents != POLLIN) {
2422 result = -EIO;
2423 goto out;
2424 }
2425
2426 result = read(bw_fd, buffer, sizeof(buffer));
2427 buffer[result] = 0;
2428 blocks_written_new_total = strtol(buffer, NULL, 10);
2429
2430 if (blocks_written_new_total - blocks_written_total
2431 != blocks_written) {
2432 result = -EIO;
2433 goto out;
2434 }
2435
2436 blocks_written_total = blocks_written_new_total;
2437 result = 0;
2438 }
2439 out:
2440 free(block_indexes);
2441 close(bw_fd);
2442 return result;
2443 }
2444
validate_ranges(const char * mount_dir,struct test_file * file)2445 static int validate_ranges(const char *mount_dir, struct test_file *file)
2446 {
2447 int block_cnt = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
2448 char *filename = concat_file_name(mount_dir, file->name);
2449 int fd;
2450 struct incfs_filled_range ranges[128];
2451 struct incfs_get_filled_blocks_args fba = {
2452 .range_buffer = ptr_to_u64(ranges),
2453 .range_buffer_size = sizeof(ranges),
2454 };
2455 int error = TEST_SUCCESS;
2456 int i;
2457 int range_cnt;
2458 int cmd_fd = -1;
2459 struct incfs_permit_fill permit_fill;
2460
2461 fd = open(filename, O_RDONLY | O_CLOEXEC);
2462 free(filename);
2463 if (fd <= 0)
2464 return TEST_FAILURE;
2465
2466 error = ioctl(fd, INCFS_IOC_GET_FILLED_BLOCKS, &fba);
2467 if (error != -1 || errno != EPERM) {
2468 ksft_print_msg("INCFS_IOC_GET_FILLED_BLOCKS not blocked\n");
2469 error = -EPERM;
2470 goto out;
2471 }
2472
2473 cmd_fd = open_commands_file(mount_dir);
2474 permit_fill.file_descriptor = fd;
2475 if (ioctl(cmd_fd, INCFS_IOC_PERMIT_FILL, &permit_fill)) {
2476 print_error("INCFS_IOC_PERMIT_FILL failed");
2477 return -EPERM;
2478 goto out;
2479 }
2480
2481 error = ioctl(fd, INCFS_IOC_GET_FILLED_BLOCKS, &fba);
2482 if (error && errno != ERANGE)
2483 goto out;
2484
2485 if (error && errno == ERANGE && block_cnt < 509)
2486 goto out;
2487
2488 if (!error && block_cnt >= 509) {
2489 error = -ERANGE;
2490 goto out;
2491 }
2492
2493 if (fba.total_blocks_out != block_cnt) {
2494 error = -EINVAL;
2495 goto out;
2496 }
2497
2498 if (fba.data_blocks_out != block_cnt) {
2499 error = -EINVAL;
2500 goto out;
2501 }
2502
2503 range_cnt = (block_cnt + 3) / 4;
2504 if (range_cnt > 128)
2505 range_cnt = 128;
2506 if (range_cnt != fba.range_buffer_size_out / sizeof(*ranges)) {
2507 error = -ERANGE;
2508 goto out;
2509 }
2510
2511 error = TEST_SUCCESS;
2512 for (i = 0; i < fba.range_buffer_size_out / sizeof(*ranges) - 1; ++i)
2513 if (ranges[i].begin != i * 4 || ranges[i].end != i * 4 + 2) {
2514 error = -EINVAL;
2515 goto out;
2516 }
2517
2518 if (ranges[i].begin != i * 4 ||
2519 (ranges[i].end != i * 4 + 1 && ranges[i].end != i * 4 + 2)) {
2520 error = -EINVAL;
2521 goto out;
2522 }
2523
2524 for (i = 0; i < 64; ++i) {
2525 fba.start_index = i * 2;
2526 fba.end_index = i * 2 + 2;
2527 error = ioctl(fd, INCFS_IOC_GET_FILLED_BLOCKS, &fba);
2528 if (error)
2529 goto out;
2530
2531 if (fba.total_blocks_out != block_cnt) {
2532 error = -EINVAL;
2533 goto out;
2534 }
2535
2536 if (fba.start_index >= block_cnt) {
2537 if (fba.index_out != fba.start_index) {
2538 error = -EINVAL;
2539 goto out;
2540 }
2541
2542 break;
2543 }
2544
2545 if (i % 2) {
2546 if (fba.range_buffer_size_out != 0) {
2547 error = -EINVAL;
2548 goto out;
2549 }
2550 } else {
2551 if (fba.range_buffer_size_out != sizeof(*ranges)) {
2552 error = -EINVAL;
2553 goto out;
2554 }
2555
2556 if (ranges[0].begin != i * 2) {
2557 error = -EINVAL;
2558 goto out;
2559 }
2560
2561 if (ranges[0].end != i * 2 + 1 &&
2562 ranges[0].end != i * 2 + 2) {
2563 error = -EINVAL;
2564 goto out;
2565 }
2566 }
2567 }
2568
2569 out:
2570 close(fd);
2571 close(cmd_fd);
2572 return error;
2573 }
2574
get_blocks_test(const char * mount_dir)2575 static int get_blocks_test(const char *mount_dir)
2576 {
2577 char *backing_dir;
2578 int cmd_fd = -1;
2579 int i;
2580 struct test_files_set test = get_test_files_set();
2581 const int file_num = test.files_count;
2582
2583 backing_dir = create_backing_dir(mount_dir);
2584 if (!backing_dir)
2585 goto failure;
2586
2587 if (mount_fs_opt(mount_dir, backing_dir, "readahead=0", false) != 0)
2588 goto failure;
2589
2590 cmd_fd = open_commands_file(mount_dir);
2591 if (cmd_fd < 0)
2592 goto failure;
2593
2594 /* Write data. */
2595 for (i = 0; i < file_num; i++) {
2596 struct test_file *file = &test.files[i];
2597
2598 if (emit_file(cmd_fd, NULL, file->name, &file->id, file->size,
2599 NULL))
2600 goto failure;
2601
2602 if (emit_partial_test_file_data(mount_dir, file))
2603 goto failure;
2604 }
2605
2606 for (i = 0; i < file_num; i++) {
2607 struct test_file *file = &test.files[i];
2608
2609 if (validate_ranges(mount_dir, file))
2610 goto failure;
2611
2612 /*
2613 * The smallest files are filled completely, so this checks that
2614 * the fast get_filled_blocks path is not causing issues
2615 */
2616 if (validate_ranges(mount_dir, file))
2617 goto failure;
2618 }
2619
2620 close(cmd_fd);
2621 umount(mount_dir);
2622 free(backing_dir);
2623 return TEST_SUCCESS;
2624
2625 failure:
2626 close(cmd_fd);
2627 umount(mount_dir);
2628 free(backing_dir);
2629 return TEST_FAILURE;
2630 }
2631
emit_partial_test_file_hash(const char * mount_dir,struct test_file * file)2632 static int emit_partial_test_file_hash(const char *mount_dir,
2633 struct test_file *file)
2634 {
2635 int err;
2636 int fd;
2637 struct incfs_fill_blocks fill_blocks = {
2638 .count = 1,
2639 };
2640 struct incfs_fill_block *fill_block_array =
2641 calloc(fill_blocks.count, sizeof(struct incfs_fill_block));
2642 uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE];
2643
2644 if (file->size <= 4096 / 32 * 4096)
2645 return 0;
2646
2647 if (!fill_block_array)
2648 return -ENOMEM;
2649 fill_blocks.fill_blocks = ptr_to_u64(fill_block_array);
2650
2651 rnd_buf(data, sizeof(data), 0);
2652
2653 fill_block_array[0] =
2654 (struct incfs_fill_block){ .block_index = 1,
2655 .data_len =
2656 INCFS_DATA_FILE_BLOCK_SIZE,
2657 .data = ptr_to_u64(data),
2658 .flags = INCFS_BLOCK_FLAGS_HASH };
2659
2660 fd = open_file_by_id(mount_dir, file->id, true);
2661 if (fd < 0) {
2662 err = errno;
2663 goto failure;
2664 }
2665
2666 err = ioctl(fd, INCFS_IOC_FILL_BLOCKS, &fill_blocks);
2667 close(fd);
2668 if (err < fill_blocks.count)
2669 err = errno;
2670 else
2671 err = 0;
2672
2673 failure:
2674 free(fill_block_array);
2675 return err;
2676 }
2677
validate_hash_ranges(const char * mount_dir,struct test_file * file)2678 static int validate_hash_ranges(const char *mount_dir, struct test_file *file)
2679 {
2680 int block_cnt = 1 + (file->size - 1) / INCFS_DATA_FILE_BLOCK_SIZE;
2681 char *filename = concat_file_name(mount_dir, file->name);
2682 int fd;
2683 struct incfs_filled_range ranges[128];
2684 struct incfs_get_filled_blocks_args fba = {
2685 .range_buffer = ptr_to_u64(ranges),
2686 .range_buffer_size = sizeof(ranges),
2687 };
2688 int error = TEST_SUCCESS;
2689 int file_blocks = (file->size + INCFS_DATA_FILE_BLOCK_SIZE - 1) /
2690 INCFS_DATA_FILE_BLOCK_SIZE;
2691 int cmd_fd = -1;
2692 struct incfs_permit_fill permit_fill;
2693
2694 if (file->size <= 4096 / 32 * 4096)
2695 return 0;
2696
2697 fd = open(filename, O_RDONLY | O_CLOEXEC);
2698 free(filename);
2699 if (fd <= 0)
2700 return TEST_FAILURE;
2701
2702 error = ioctl(fd, INCFS_IOC_GET_FILLED_BLOCKS, &fba);
2703 if (error != -1 || errno != EPERM) {
2704 ksft_print_msg("INCFS_IOC_GET_FILLED_BLOCKS not blocked\n");
2705 error = -EPERM;
2706 goto out;
2707 }
2708
2709 cmd_fd = open_commands_file(mount_dir);
2710 permit_fill.file_descriptor = fd;
2711 if (ioctl(cmd_fd, INCFS_IOC_PERMIT_FILL, &permit_fill)) {
2712 print_error("INCFS_IOC_PERMIT_FILL failed");
2713 return -EPERM;
2714 goto out;
2715 }
2716
2717 error = ioctl(fd, INCFS_IOC_GET_FILLED_BLOCKS, &fba);
2718 if (error)
2719 goto out;
2720
2721 if (fba.total_blocks_out <= block_cnt) {
2722 error = -EINVAL;
2723 goto out;
2724 }
2725
2726 if (fba.data_blocks_out != block_cnt) {
2727 error = -EINVAL;
2728 goto out;
2729 }
2730
2731 if (fba.range_buffer_size_out != sizeof(struct incfs_filled_range)) {
2732 error = -EINVAL;
2733 goto out;
2734 }
2735
2736 if (ranges[0].begin != file_blocks + 1 ||
2737 ranges[0].end != file_blocks + 2) {
2738 error = -EINVAL;
2739 goto out;
2740 }
2741
2742 out:
2743 close(cmd_fd);
2744 close(fd);
2745 return error;
2746 }
2747
get_hash_blocks_test(const char * mount_dir)2748 static int get_hash_blocks_test(const char *mount_dir)
2749 {
2750 char *backing_dir;
2751 int cmd_fd = -1;
2752 int i;
2753 struct test_files_set test = get_test_files_set();
2754 const int file_num = test.files_count;
2755
2756 backing_dir = create_backing_dir(mount_dir);
2757 if (!backing_dir)
2758 goto failure;
2759
2760 if (mount_fs_opt(mount_dir, backing_dir, "readahead=0", false) != 0)
2761 goto failure;
2762
2763 cmd_fd = open_commands_file(mount_dir);
2764 if (cmd_fd < 0)
2765 goto failure;
2766
2767 for (i = 0; i < file_num; i++) {
2768 struct test_file *file = &test.files[i];
2769
2770 if (crypto_emit_file(cmd_fd, NULL, file->name, &file->id,
2771 file->size, file->root_hash,
2772 file->sig.add_data))
2773 goto failure;
2774
2775 if (emit_partial_test_file_hash(mount_dir, file))
2776 goto failure;
2777 }
2778
2779 for (i = 0; i < file_num; i++) {
2780 struct test_file *file = &test.files[i];
2781
2782 if (validate_hash_ranges(mount_dir, file))
2783 goto failure;
2784 }
2785
2786 close(cmd_fd);
2787 umount(mount_dir);
2788 free(backing_dir);
2789 return TEST_SUCCESS;
2790
2791 failure:
2792 close(cmd_fd);
2793 umount(mount_dir);
2794 free(backing_dir);
2795 return TEST_FAILURE;
2796 }
2797
2798 #define THREE_GB (3LL * 1024 * 1024 * 1024)
2799 #define FOUR_GB (4LL * 1024 * 1024 * 1024) /* Have 1GB of margin */
large_file_test(const char * mount_dir)2800 static int large_file_test(const char *mount_dir)
2801 {
2802 char *backing_dir;
2803 int cmd_fd = -1;
2804 int i;
2805 int result = TEST_FAILURE, ret;
2806 uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE] = {};
2807 int block_count = THREE_GB / INCFS_DATA_FILE_BLOCK_SIZE;
2808 struct incfs_fill_block *block_buf =
2809 calloc(block_count, sizeof(struct incfs_fill_block));
2810 struct incfs_fill_blocks fill_blocks = {
2811 .count = block_count,
2812 .fill_blocks = ptr_to_u64(block_buf),
2813 };
2814 incfs_uuid_t id;
2815 int fd = -1;
2816 struct statvfs svfs;
2817 unsigned long long free_disksz;
2818
2819 ret = statvfs(mount_dir, &svfs);
2820 if (ret) {
2821 ksft_print_msg("Can't get disk size. Skipping %s...\n", __func__);
2822 return TEST_SKIP;
2823 }
2824
2825 free_disksz = (unsigned long long)svfs.f_bavail * svfs.f_bsize;
2826
2827 if (FOUR_GB > free_disksz) {
2828 ksft_print_msg("Not enough free disk space (%lldMB). Skipping %s...\n",
2829 free_disksz >> 20, __func__);
2830 return TEST_SKIP;
2831 }
2832
2833 backing_dir = create_backing_dir(mount_dir);
2834 if (!backing_dir)
2835 goto failure;
2836
2837 if (mount_fs_opt(mount_dir, backing_dir, "readahead=0", false) != 0)
2838 goto failure;
2839
2840 cmd_fd = open_commands_file(mount_dir);
2841 if (cmd_fd < 0)
2842 goto failure;
2843
2844 if (emit_file(cmd_fd, NULL, "very_large_file", &id,
2845 (uint64_t)block_count * INCFS_DATA_FILE_BLOCK_SIZE,
2846 NULL) < 0)
2847 goto failure;
2848
2849 for (i = 0; i < block_count; i++) {
2850 block_buf[i].compression = COMPRESSION_NONE;
2851 block_buf[i].block_index = i;
2852 block_buf[i].data_len = INCFS_DATA_FILE_BLOCK_SIZE;
2853 block_buf[i].data = ptr_to_u64(data);
2854 }
2855
2856 fd = open_file_by_id(mount_dir, id, true);
2857 if (fd < 0)
2858 goto failure;
2859
2860 if (ioctl(fd, INCFS_IOC_FILL_BLOCKS, &fill_blocks) != block_count)
2861 goto failure;
2862
2863 if (emit_file(cmd_fd, NULL, "very_very_large_file", &id, 1LL << 40,
2864 NULL) < 0)
2865 goto failure;
2866
2867 result = TEST_SUCCESS;
2868
2869 failure:
2870 close(fd);
2871 close(cmd_fd);
2872 unlink("very_large_file");
2873 umount(mount_dir);
2874 free(backing_dir);
2875 return result;
2876 }
2877
validate_mapped_file(const char * orig_name,const char * name,size_t size,size_t offset)2878 static int validate_mapped_file(const char *orig_name, const char *name,
2879 size_t size, size_t offset)
2880 {
2881 struct stat st;
2882 int orig_fd = -1, fd = -1;
2883 size_t block;
2884 int result = TEST_FAILURE;
2885
2886 if (stat(name, &st)) {
2887 ksft_print_msg("Failed to stat %s with error %s\n",
2888 name, strerror(errno));
2889 goto failure;
2890 }
2891
2892 if (size != st.st_size) {
2893 ksft_print_msg("Mismatched file sizes for file %s - expected %llu, got %llu\n",
2894 name, size, st.st_size);
2895 goto failure;
2896 }
2897
2898 fd = open(name, O_RDONLY | O_CLOEXEC);
2899 if (fd == -1) {
2900 ksft_print_msg("Failed to open %s with error %s\n", name,
2901 strerror(errno));
2902 goto failure;
2903 }
2904
2905 orig_fd = open(orig_name, O_RDONLY | O_CLOEXEC);
2906 if (orig_fd == -1) {
2907 ksft_print_msg("Failed to open %s with error %s\n", orig_name,
2908 strerror(errno));
2909 goto failure;
2910 }
2911
2912 for (block = 0; block < size; block += INCFS_DATA_FILE_BLOCK_SIZE) {
2913 uint8_t orig_data[INCFS_DATA_FILE_BLOCK_SIZE];
2914 uint8_t data[INCFS_DATA_FILE_BLOCK_SIZE];
2915 ssize_t orig_read, mapped_read;
2916
2917 orig_read = pread(orig_fd, orig_data,
2918 INCFS_DATA_FILE_BLOCK_SIZE, block + offset);
2919 mapped_read = pread(fd, data, INCFS_DATA_FILE_BLOCK_SIZE,
2920 block);
2921
2922 if (orig_read < mapped_read ||
2923 mapped_read != min(size - block,
2924 INCFS_DATA_FILE_BLOCK_SIZE)) {
2925 ksft_print_msg("Failed to read enough data: %llu %llu %llu %lld %lld\n",
2926 block, size, offset, orig_read,
2927 mapped_read);
2928 goto failure;
2929 }
2930
2931 if (memcmp(orig_data, data, mapped_read)) {
2932 ksft_print_msg("Data doesn't match: %llu %llu %llu %lld %lld\n",
2933 block, size, offset, orig_read,
2934 mapped_read);
2935 goto failure;
2936 }
2937 }
2938
2939 result = TEST_SUCCESS;
2940
2941 failure:
2942 close(orig_fd);
2943 close(fd);
2944 return result;
2945 }
2946
mapped_file_test(const char * mount_dir)2947 static int mapped_file_test(const char *mount_dir)
2948 {
2949 char *backing_dir;
2950 int result = TEST_FAILURE;
2951 int cmd_fd = -1;
2952 int i;
2953 struct test_files_set test = get_test_files_set();
2954 const int file_num = test.files_count;
2955
2956 backing_dir = create_backing_dir(mount_dir);
2957 if (!backing_dir)
2958 goto failure;
2959
2960 if (mount_fs_opt(mount_dir, backing_dir, "readahead=0", false) != 0)
2961 goto failure;
2962
2963 cmd_fd = open_commands_file(mount_dir);
2964 if (cmd_fd < 0)
2965 goto failure;
2966
2967 for (i = 0; i < file_num; ++i) {
2968 struct test_file *file = &test.files[i];
2969 size_t blocks = file->size / INCFS_DATA_FILE_BLOCK_SIZE;
2970 size_t mapped_offset = blocks / 4 *
2971 INCFS_DATA_FILE_BLOCK_SIZE;
2972 size_t mapped_size = file->size / 4 * 3 - mapped_offset;
2973 struct incfs_create_mapped_file_args mfa;
2974 char mapped_file_name[FILENAME_MAX];
2975 char orig_file_path[PATH_MAX];
2976 char mapped_file_path[PATH_MAX];
2977
2978 if (emit_file(cmd_fd, NULL, file->name, &file->id, file->size,
2979 NULL) < 0)
2980 goto failure;
2981
2982 if (emit_test_file_data(mount_dir, file))
2983 goto failure;
2984
2985 if (snprintf(mapped_file_name, ARRAY_SIZE(mapped_file_name),
2986 "%s.mapped", file->name) < 0)
2987 goto failure;
2988
2989 mfa = (struct incfs_create_mapped_file_args) {
2990 .size = mapped_size,
2991 .mode = 0664,
2992 .file_name = ptr_to_u64(mapped_file_name),
2993 .source_file_id = file->id,
2994 .source_offset = mapped_offset,
2995 };
2996
2997 result = ioctl(cmd_fd, INCFS_IOC_CREATE_MAPPED_FILE, &mfa);
2998 if (result) {
2999 ksft_print_msg(
3000 "Failed to create mapped file with error %d\n",
3001 result);
3002 goto failure;
3003 }
3004
3005 result = snprintf(orig_file_path,
3006 ARRAY_SIZE(orig_file_path), "%s/%s",
3007 mount_dir, file->name);
3008
3009 if (result < 0 || result >= ARRAY_SIZE(mapped_file_path)) {
3010 result = TEST_FAILURE;
3011 goto failure;
3012 }
3013
3014 result = snprintf(mapped_file_path,
3015 ARRAY_SIZE(mapped_file_path), "%s/%s",
3016 mount_dir, mapped_file_name);
3017
3018 if (result < 0 || result >= ARRAY_SIZE(mapped_file_path)) {
3019 result = TEST_FAILURE;
3020 goto failure;
3021 }
3022
3023 result = validate_mapped_file(orig_file_path, mapped_file_path,
3024 mapped_size, mapped_offset);
3025 if (result)
3026 goto failure;
3027 }
3028
3029 failure:
3030 close(cmd_fd);
3031 umount(mount_dir);
3032 free(backing_dir);
3033 return result;
3034 }
3035
3036 static const char v1_file[] = {
3037 /* Header */
3038 /* 0x00: Magic number */
3039 0x49, 0x4e, 0x43, 0x46, 0x53, 0x00, 0x00, 0x00,
3040 /* 0x08: Version */
3041 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3042 /* 0x10: Header size */
3043 0x38, 0x00,
3044 /* 0x12: Block size */
3045 0x00, 0x10,
3046 /* 0x14: Flags */
3047 0x00, 0x00, 0x00, 0x00,
3048 /* 0x18: First md offset */
3049 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3050 /* 0x20: File size */
3051 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3052 /* 0x28: UUID */
3053 0x8c, 0x7d, 0xd9, 0x22, 0xad, 0x47, 0x49, 0x4f,
3054 0xc0, 0x2c, 0x38, 0x8e, 0x12, 0xc0, 0x0e, 0xac,
3055
3056 /* 0x38: Attribute */
3057 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
3058 0x31, 0x32, 0x33, 0x31, 0x32, 0x33,
3059
3060 /* Attribute md record */
3061 /* 0x46: Type */
3062 0x02,
3063 /* 0x47: Size */
3064 0x25, 0x00,
3065 /* 0x49: CRC */
3066 0x9a, 0xef, 0xef, 0x72,
3067 /* 0x4d: Next md offset */
3068 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3069 /* 0x55: Prev md offset */
3070 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3071 /* 0x5d: fa_offset */
3072 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3073 /* 0x65: fa_size */
3074 0x0e, 0x00,
3075 /* 0x67: fa_crc */
3076 0xfb, 0x5e, 0x72, 0x89,
3077
3078 /* Blockmap table */
3079 /* 0x6b: First 10-byte entry */
3080 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3081
3082 /* Blockmap md record */
3083 /* 0x75: Type */
3084 0x01,
3085 /* 0x76: Size */
3086 0x23, 0x00,
3087 /* 0x78: CRC */
3088 0x74, 0x45, 0xd3, 0xb9,
3089 /* 0x7c: Next md offset */
3090 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3091 /* 0x84: Prev md offset */
3092 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3093 /* 0x8c: blockmap offset */
3094 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
3095 /* 0x94: blockmap count */
3096 0x01, 0x00, 0x00, 0x00,
3097 };
3098
compatibility_test(const char * mount_dir)3099 static int compatibility_test(const char *mount_dir)
3100 {
3101 static const char *name = "file";
3102 int result = TEST_FAILURE;
3103 char *backing_dir = NULL;
3104 char *filename = NULL;
3105 int fd = -1;
3106 uint64_t size = 0x0c;
3107
3108 TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
3109 TEST(filename = concat_file_name(backing_dir, name), filename);
3110 TEST(fd = open(filename, O_CREAT | O_WRONLY | O_CLOEXEC, 0777),
3111 fd != -1);
3112 TESTEQUAL(write(fd, v1_file, sizeof(v1_file)), sizeof(v1_file));
3113 TESTEQUAL(fsetxattr(fd, INCFS_XATTR_SIZE_NAME, &size, sizeof(size), 0),
3114 0);
3115 TESTEQUAL(mount_fs(mount_dir, backing_dir, 50), 0);
3116 free(filename);
3117 TEST(filename = concat_file_name(mount_dir, name), filename);
3118 close(fd);
3119 TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
3120
3121 result = TEST_SUCCESS;
3122 out:
3123 close(fd);
3124 umount(mount_dir);
3125 free(backing_dir);
3126 free(filename);
3127 return result;
3128 }
3129
zero_blocks_written_count(int fd,uint32_t data_blocks_written,uint32_t hash_blocks_written)3130 static int zero_blocks_written_count(int fd, uint32_t data_blocks_written,
3131 uint32_t hash_blocks_written)
3132 {
3133 int test_result = TEST_FAILURE;
3134 uint64_t offset;
3135 uint8_t type;
3136 uint32_t bw;
3137
3138 /* Get first md record */
3139 TESTEQUAL(pread(fd, &offset, sizeof(offset), 24), sizeof(offset));
3140
3141 /* Find status md record */
3142 for (;;) {
3143 TESTNE(offset, 0);
3144 TESTEQUAL(pread(fd, &type, sizeof(type), le64_to_cpu(offset)),
3145 sizeof(type));
3146 if (type == 4)
3147 break;
3148 TESTEQUAL(pread(fd, &offset, sizeof(offset),
3149 le64_to_cpu(offset) + 7),
3150 sizeof(offset));
3151 }
3152
3153 /* Read blocks_written */
3154 offset = le64_to_cpu(offset);
3155 TESTEQUAL(pread(fd, &bw, sizeof(bw), offset + 23), sizeof(bw));
3156 TESTEQUAL(le32_to_cpu(bw), data_blocks_written);
3157 TESTEQUAL(pread(fd, &bw, sizeof(bw), offset + 27), sizeof(bw));
3158 TESTEQUAL(le32_to_cpu(bw), hash_blocks_written);
3159
3160 /* Write out zero */
3161 bw = 0;
3162 TESTEQUAL(pwrite(fd, &bw, sizeof(bw), offset + 23), sizeof(bw));
3163 TESTEQUAL(pwrite(fd, &bw, sizeof(bw), offset + 27), sizeof(bw));
3164
3165 test_result = TEST_SUCCESS;
3166 out:
3167 return test_result;
3168 }
3169
validate_block_count(const char * mount_dir,const char * backing_dir,struct test_file * file,int total_data_blocks,int filled_data_blocks,int total_hash_blocks,int filled_hash_blocks)3170 static int validate_block_count(const char *mount_dir, const char *backing_dir,
3171 struct test_file *file,
3172 int total_data_blocks, int filled_data_blocks,
3173 int total_hash_blocks, int filled_hash_blocks)
3174 {
3175 char *filename = NULL;
3176 char *backing_filename = NULL;
3177 int fd = -1;
3178 struct incfs_get_block_count_args bca = {};
3179 int test_result = TEST_FAILURE;
3180 struct incfs_filled_range ranges[128];
3181 struct incfs_get_filled_blocks_args fba = {
3182 .range_buffer = ptr_to_u64(ranges),
3183 .range_buffer_size = sizeof(ranges),
3184 };
3185 int cmd_fd = -1;
3186 struct incfs_permit_fill permit_fill;
3187
3188 TEST(filename = concat_file_name(mount_dir, file->name), filename);
3189 TEST(backing_filename = concat_file_name(backing_dir, file->name),
3190 backing_filename);
3191 TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
3192
3193 TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0);
3194 TESTEQUAL(bca.total_data_blocks_out, total_data_blocks);
3195 TESTEQUAL(bca.filled_data_blocks_out, filled_data_blocks);
3196 TESTEQUAL(bca.total_hash_blocks_out, total_hash_blocks);
3197 TESTEQUAL(bca.filled_hash_blocks_out, filled_hash_blocks);
3198
3199 close(fd);
3200 TESTEQUAL(umount(mount_dir), 0);
3201 TEST(fd = open(backing_filename, O_RDWR | O_CLOEXEC), fd != -1);
3202 TESTEQUAL(zero_blocks_written_count(fd, filled_data_blocks,
3203 filled_hash_blocks),
3204 TEST_SUCCESS);
3205 close(fd);
3206 fd = -1;
3207 TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "readahead=0", false),
3208 0);
3209 TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
3210
3211 TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0);
3212 TESTEQUAL(bca.total_data_blocks_out, total_data_blocks);
3213 TESTEQUAL(bca.filled_data_blocks_out, 0);
3214 TESTEQUAL(bca.total_hash_blocks_out, total_hash_blocks);
3215 TESTEQUAL(bca.filled_hash_blocks_out, 0);
3216
3217 TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
3218 permit_fill.file_descriptor = fd;
3219 TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_PERMIT_FILL, &permit_fill), 0);
3220 do {
3221 ioctl(fd, INCFS_IOC_GET_FILLED_BLOCKS, &fba);
3222 fba.start_index = fba.index_out + 1;
3223 } while (fba.index_out < fba.total_blocks_out);
3224
3225 TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0);
3226 TESTEQUAL(bca.total_data_blocks_out, total_data_blocks);
3227 TESTEQUAL(bca.filled_data_blocks_out, filled_data_blocks);
3228 TESTEQUAL(bca.total_hash_blocks_out, total_hash_blocks);
3229 TESTEQUAL(bca.filled_hash_blocks_out, filled_hash_blocks);
3230
3231 test_result = TEST_SUCCESS;
3232 out:
3233 close(cmd_fd);
3234 close(fd);
3235 free(filename);
3236 free(backing_filename);
3237 return test_result;
3238 }
3239
3240
3241
validate_data_block_count(const char * mount_dir,const char * backing_dir,struct test_file * file)3242 static int validate_data_block_count(const char *mount_dir,
3243 const char *backing_dir,
3244 struct test_file *file)
3245 {
3246 const int total_data_blocks = 1 + (file->size - 1) /
3247 INCFS_DATA_FILE_BLOCK_SIZE;
3248 const int filled_data_blocks = (total_data_blocks + 1) / 2;
3249
3250 int test_result = TEST_FAILURE;
3251 char *filename = NULL;
3252 char *incomplete_filename = NULL;
3253 struct stat stat_buf_incomplete, stat_buf_file;
3254 int fd = -1;
3255 struct incfs_get_block_count_args bca = {};
3256 int i;
3257
3258 TEST(filename = concat_file_name(mount_dir, file->name), filename);
3259 TEST(incomplete_filename = get_incomplete_filename(mount_dir, file->id),
3260 incomplete_filename);
3261
3262 TESTEQUAL(stat(filename, &stat_buf_file), 0);
3263 TESTEQUAL(stat(incomplete_filename, &stat_buf_incomplete), 0);
3264 TESTEQUAL(stat_buf_file.st_ino, stat_buf_incomplete.st_ino);
3265 TESTEQUAL(stat_buf_file.st_nlink, 3);
3266
3267 TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
3268 TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0);
3269 TESTEQUAL(bca.total_data_blocks_out, total_data_blocks);
3270 TESTEQUAL(bca.filled_data_blocks_out, 0);
3271 TESTEQUAL(bca.total_hash_blocks_out, 0);
3272 TESTEQUAL(bca.filled_hash_blocks_out, 0);
3273
3274 for (i = 0; i < total_data_blocks; i += 2)
3275 TESTEQUAL(emit_test_block(mount_dir, file, i), 0);
3276
3277 TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0);
3278 TESTEQUAL(bca.total_data_blocks_out, total_data_blocks);
3279 TESTEQUAL(bca.filled_data_blocks_out, filled_data_blocks);
3280 TESTEQUAL(bca.total_hash_blocks_out, 0);
3281 TESTEQUAL(bca.filled_hash_blocks_out, 0);
3282 close(fd);
3283 fd = -1;
3284
3285 TESTEQUAL(validate_block_count(mount_dir, backing_dir, file,
3286 total_data_blocks, filled_data_blocks,
3287 0, 0),
3288 0);
3289
3290 for (i = 1; i < total_data_blocks; i += 2)
3291 TESTEQUAL(emit_test_block(mount_dir, file, i), 0);
3292
3293 TESTEQUAL(stat(incomplete_filename, &stat_buf_incomplete), -1);
3294 TESTEQUAL(errno, ENOENT);
3295
3296 test_result = TEST_SUCCESS;
3297 out:
3298 close(fd);
3299 free(incomplete_filename);
3300 free(filename);
3301 return test_result;
3302 }
3303
data_block_count_test(const char * mount_dir)3304 static int data_block_count_test(const char *mount_dir)
3305 {
3306 int result = TEST_FAILURE;
3307 char *backing_dir;
3308 int cmd_fd = -1;
3309 int i;
3310 struct test_files_set test = get_test_files_set();
3311
3312 TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
3313 TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "readahead=0", false),
3314 0);
3315
3316 for (i = 0; i < test.files_count; ++i) {
3317 struct test_file *file = &test.files[i];
3318
3319 TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
3320 TESTEQUAL(emit_file(cmd_fd, NULL, file->name, &file->id,
3321 file->size, NULL),
3322 0);
3323 close(cmd_fd);
3324 cmd_fd = -1;
3325
3326 TESTEQUAL(validate_data_block_count(mount_dir, backing_dir,
3327 file),
3328 0);
3329 }
3330
3331 result = TEST_SUCCESS;
3332 out:
3333 close(cmd_fd);
3334 umount(mount_dir);
3335 free(backing_dir);
3336 return result;
3337 }
3338
validate_hash_block_count(const char * mount_dir,const char * backing_dir,struct test_file * file)3339 static int validate_hash_block_count(const char *mount_dir,
3340 const char *backing_dir,
3341 struct test_file *file)
3342 {
3343 const int digest_size = SHA256_DIGEST_SIZE;
3344 const int hash_per_block = INCFS_DATA_FILE_BLOCK_SIZE / digest_size;
3345 const int total_data_blocks = 1 + (file->size - 1) /
3346 INCFS_DATA_FILE_BLOCK_SIZE;
3347
3348 int result = TEST_FAILURE;
3349 int hash_layer = total_data_blocks;
3350 int total_hash_blocks = 0;
3351 int filled_hash_blocks;
3352 char *filename = NULL;
3353 int fd = -1;
3354 struct incfs_get_block_count_args bca = {};
3355
3356 while (hash_layer > 1) {
3357 hash_layer = (hash_layer + hash_per_block - 1) / hash_per_block;
3358 total_hash_blocks += hash_layer;
3359 }
3360 filled_hash_blocks = total_hash_blocks > 1 ? 1 : 0;
3361
3362 TEST(filename = concat_file_name(mount_dir, file->name), filename);
3363 TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
3364
3365 TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0);
3366 TESTEQUAL(bca.total_data_blocks_out, total_data_blocks);
3367 TESTEQUAL(bca.filled_data_blocks_out, 0);
3368 TESTEQUAL(bca.total_hash_blocks_out, total_hash_blocks);
3369 TESTEQUAL(bca.filled_hash_blocks_out, 0);
3370
3371 TESTEQUAL(emit_partial_test_file_hash(mount_dir, file), 0);
3372
3373 TESTEQUAL(ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &bca), 0);
3374 TESTEQUAL(bca.total_data_blocks_out, total_data_blocks);
3375 TESTEQUAL(bca.filled_data_blocks_out, 0);
3376 TESTEQUAL(bca.total_hash_blocks_out, total_hash_blocks);
3377 TESTEQUAL(bca.filled_hash_blocks_out, filled_hash_blocks);
3378 close(fd);
3379 fd = -1;
3380
3381 if (filled_hash_blocks)
3382 TESTEQUAL(validate_block_count(mount_dir, backing_dir, file,
3383 total_data_blocks, 0,
3384 total_hash_blocks, filled_hash_blocks),
3385 0);
3386
3387 result = TEST_SUCCESS;
3388 out:
3389 close(fd);
3390 free(filename);
3391 return result;
3392 }
3393
hash_block_count_test(const char * mount_dir)3394 static int hash_block_count_test(const char *mount_dir)
3395 {
3396 int result = TEST_FAILURE;
3397 char *backing_dir;
3398 int cmd_fd = -1;
3399 int i;
3400 struct test_files_set test = get_test_files_set();
3401
3402 TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
3403 TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "readahead=0", false),
3404 0);
3405
3406 for (i = 0; i < test.files_count; i++) {
3407 struct test_file *file = &test.files[i];
3408
3409 TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
3410 TESTEQUAL(crypto_emit_file(cmd_fd, NULL, file->name, &file->id,
3411 file->size, file->root_hash,
3412 file->sig.add_data),
3413 0);
3414 close(cmd_fd);
3415 cmd_fd = -1;
3416
3417 TESTEQUAL(validate_hash_block_count(mount_dir, backing_dir,
3418 &test.files[i]),
3419 0);
3420 }
3421
3422 result = TEST_SUCCESS;
3423 out:
3424 close(cmd_fd);
3425 umount(mount_dir);
3426 free(backing_dir);
3427 return result;
3428 }
3429
is_close(struct timespec * start,int expected_ms)3430 static int is_close(struct timespec *start, int expected_ms)
3431 {
3432 const int allowed_variance = 100;
3433 int result = TEST_FAILURE;
3434 struct timespec finish;
3435 int diff;
3436
3437 TESTEQUAL(clock_gettime(CLOCK_MONOTONIC, &finish), 0);
3438 diff = (finish.tv_sec - start->tv_sec) * 1000 +
3439 (finish.tv_nsec - start->tv_nsec) / 1000000;
3440
3441 TESTCOND(diff >= expected_ms - allowed_variance);
3442 TESTCOND(diff <= expected_ms + allowed_variance);
3443 result = TEST_SUCCESS;
3444 out:
3445 return result;
3446 }
3447
per_uid_read_timeouts_test(const char * mount_dir)3448 static int per_uid_read_timeouts_test(const char *mount_dir)
3449 {
3450 struct test_file file = {
3451 .name = "file",
3452 .size = 16 * INCFS_DATA_FILE_BLOCK_SIZE
3453 };
3454
3455 int result = TEST_FAILURE;
3456 char *backing_dir = NULL;
3457 int pid = -1;
3458 int cmd_fd = -1;
3459 char *filename = NULL;
3460 int fd = -1;
3461 struct timespec start;
3462 char buffer[4096];
3463 struct incfs_per_uid_read_timeouts purt_get[1];
3464 struct incfs_get_read_timeouts_args grt = {
3465 ptr_to_u64(purt_get),
3466 sizeof(purt_get)
3467 };
3468 struct incfs_per_uid_read_timeouts purt_set[] = {
3469 {
3470 .uid = 0,
3471 .min_time_us = 1000000,
3472 .min_pending_time_us = 2000000,
3473 .max_pending_time_us = 3000000,
3474 },
3475 };
3476 struct incfs_set_read_timeouts_args srt = {
3477 ptr_to_u64(purt_set),
3478 sizeof(purt_set)
3479 };
3480 int status;
3481
3482 TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
3483 TESTEQUAL(mount_fs_opt(mount_dir, backing_dir,
3484 "read_timeout_ms=1000,readahead=0", false), 0);
3485
3486 TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
3487 TESTEQUAL(emit_file(cmd_fd, NULL, file.name, &file.id, file.size,
3488 NULL), 0);
3489
3490 TEST(filename = concat_file_name(mount_dir, file.name), filename);
3491 TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
3492 TESTEQUAL(fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC), 0);
3493
3494 /* Default mount options read failure is 1000 */
3495 TESTEQUAL(clock_gettime(CLOCK_MONOTONIC, &start), 0);
3496 TESTEQUAL(pread(fd, buffer, sizeof(buffer), 0), -1);
3497 TESTEQUAL(is_close(&start, 1000), 0);
3498
3499 grt.timeouts_array_size = 0;
3500 TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_GET_READ_TIMEOUTS, &grt), 0);
3501 TESTEQUAL(grt.timeouts_array_size_out, 0);
3502
3503 /* Set it to 3000 */
3504 TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_SET_READ_TIMEOUTS, &srt), 0);
3505 TESTEQUAL(clock_gettime(CLOCK_MONOTONIC, &start), 0);
3506 TESTEQUAL(pread(fd, buffer, sizeof(buffer), 0), -1);
3507 TESTEQUAL(is_close(&start, 3000), 0);
3508 TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_GET_READ_TIMEOUTS, &grt), -1);
3509 TESTEQUAL(errno, E2BIG);
3510 TESTEQUAL(grt.timeouts_array_size_out, sizeof(purt_get));
3511 grt.timeouts_array_size = sizeof(purt_get);
3512 TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_GET_READ_TIMEOUTS, &grt), 0);
3513 TESTEQUAL(grt.timeouts_array_size_out, sizeof(purt_get));
3514 TESTEQUAL(purt_get[0].uid, purt_set[0].uid);
3515 TESTEQUAL(purt_get[0].min_time_us, purt_set[0].min_time_us);
3516 TESTEQUAL(purt_get[0].min_pending_time_us,
3517 purt_set[0].min_pending_time_us);
3518 TESTEQUAL(purt_get[0].max_pending_time_us,
3519 purt_set[0].max_pending_time_us);
3520
3521 /* Still 1000 in UID 2 */
3522 TESTEQUAL(clock_gettime(CLOCK_MONOTONIC, &start), 0);
3523 TEST(pid = fork(), pid != -1);
3524 if (pid == 0) {
3525 TESTEQUAL(setuid(2), 0);
3526 TESTEQUAL(pread(fd, buffer, sizeof(buffer), 0), -1);
3527 exit(0);
3528 }
3529 TESTNE(wait(&status), -1);
3530 TESTEQUAL(WEXITSTATUS(status), 0);
3531 TESTEQUAL(is_close(&start, 1000), 0);
3532
3533 /* Set it to default */
3534 purt_set[0].max_pending_time_us = UINT32_MAX;
3535 TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_SET_READ_TIMEOUTS, &srt), 0);
3536 TESTEQUAL(clock_gettime(CLOCK_MONOTONIC, &start), 0);
3537 TESTEQUAL(pread(fd, buffer, sizeof(buffer), 0), -1);
3538 TESTEQUAL(is_close(&start, 1000), 0);
3539
3540 /* Test min read time */
3541 TESTEQUAL(emit_test_block(mount_dir, &file, 0), 0);
3542 TESTEQUAL(clock_gettime(CLOCK_MONOTONIC, &start), 0);
3543 TESTEQUAL(pread(fd, buffer, sizeof(buffer), 0), sizeof(buffer));
3544 TESTEQUAL(is_close(&start, 1000), 0);
3545
3546 /* Test min pending time */
3547 purt_set[0].uid = 2;
3548 TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_SET_READ_TIMEOUTS, &srt), 0);
3549 TESTEQUAL(clock_gettime(CLOCK_MONOTONIC, &start), 0);
3550 TEST(pid = fork(), pid != -1);
3551 if (pid == 0) {
3552 TESTEQUAL(setuid(2), 0);
3553 TESTEQUAL(pread(fd, buffer, sizeof(buffer), sizeof(buffer)),
3554 sizeof(buffer));
3555 exit(0);
3556 }
3557 sleep(1);
3558 TESTEQUAL(emit_test_block(mount_dir, &file, 1), 0);
3559 TESTNE(wait(&status), -1);
3560 TESTEQUAL(WEXITSTATUS(status), 0);
3561 TESTEQUAL(is_close(&start, 2000), 0);
3562
3563 /* Clear timeouts */
3564 srt.timeouts_array_size = 0;
3565 TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_SET_READ_TIMEOUTS, &srt), 0);
3566 grt.timeouts_array_size = 0;
3567 TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_GET_READ_TIMEOUTS, &grt), 0);
3568 TESTEQUAL(grt.timeouts_array_size_out, 0);
3569
3570 result = TEST_SUCCESS;
3571 out:
3572 close(fd);
3573
3574 if (pid == 0)
3575 exit(result);
3576
3577 free(filename);
3578 close(cmd_fd);
3579 umount(mount_dir);
3580 free(backing_dir);
3581 return result;
3582 }
3583
3584 #define DIRS 3
inotify_test(const char * mount_dir)3585 static int inotify_test(const char *mount_dir)
3586 {
3587 const char *mapped_file_name = "mapped_name";
3588 struct test_file file = {
3589 .name = "file",
3590 .size = 16 * INCFS_DATA_FILE_BLOCK_SIZE
3591 };
3592
3593 int result = TEST_FAILURE;
3594 char *backing_dir = NULL, *index_dir = NULL, *incomplete_dir = NULL;
3595 char *file_name = NULL;
3596 int cmd_fd = -1;
3597 int notify_fd = -1;
3598 int wds[DIRS];
3599 char buffer[DIRS * (sizeof(struct inotify_event) + NAME_MAX + 1)];
3600 char *ptr = buffer;
3601 struct inotify_event *event;
3602 struct inotify_event *events[DIRS] = {};
3603 const char *names[DIRS] = {};
3604 int res;
3605 char id[sizeof(incfs_uuid_t) * 2 + 1];
3606 struct incfs_create_mapped_file_args mfa;
3607
3608 /* File creation triggers inotify events in .index and .incomplete? */
3609 TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
3610 TEST(index_dir = concat_file_name(mount_dir, ".index"), index_dir);
3611 TEST(incomplete_dir = concat_file_name(mount_dir, ".incomplete"),
3612 incomplete_dir);
3613 TESTEQUAL(mount_fs(mount_dir, backing_dir, 50), 0);
3614 TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
3615 TEST(notify_fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC),
3616 notify_fd != -1);
3617 TEST(wds[0] = inotify_add_watch(notify_fd, mount_dir,
3618 IN_CREATE | IN_DELETE),
3619 wds[0] != -1);
3620 TEST(wds[1] = inotify_add_watch(notify_fd, index_dir,
3621 IN_CREATE | IN_DELETE),
3622 wds[1] != -1);
3623 TEST(wds[2] = inotify_add_watch(notify_fd, incomplete_dir,
3624 IN_CREATE | IN_DELETE),
3625 wds[2] != -1);
3626 TESTEQUAL(emit_file(cmd_fd, NULL, file.name, &file.id, file.size,
3627 NULL), 0);
3628 TEST(res = read(notify_fd, buffer, sizeof(buffer)), res != -1);
3629
3630 while (ptr < buffer + res) {
3631 int i;
3632
3633 event = (struct inotify_event *) ptr;
3634 TESTCOND(ptr + sizeof(*event) <= buffer + res);
3635 for (i = 0; i < DIRS; ++i)
3636 if (event->wd == wds[i]) {
3637 TESTEQUAL(events[i], NULL);
3638 events[i] = event;
3639 ptr += sizeof(*event);
3640 names[i] = ptr;
3641 ptr += events[i]->len;
3642 TESTCOND(ptr <= buffer + res);
3643 break;
3644 }
3645 TESTCOND(i < DIRS);
3646 }
3647
3648 TESTNE(events[0], NULL);
3649 TESTNE(events[1], NULL);
3650 TESTNE(events[2], NULL);
3651
3652 bin2hex(id, file.id.bytes, sizeof(incfs_uuid_t));
3653
3654 TESTEQUAL(events[0]->mask, IN_CREATE);
3655 TESTEQUAL(events[1]->mask, IN_CREATE);
3656 TESTEQUAL(events[2]->mask, IN_CREATE);
3657 TESTEQUAL(strcmp(names[0], file.name), 0);
3658 TESTEQUAL(strcmp(names[1], id), 0);
3659 TESTEQUAL(strcmp(names[2], id), 0);
3660
3661 /* Creating a mapped file triggers inotify event */
3662 mfa = (struct incfs_create_mapped_file_args) {
3663 .size = INCFS_DATA_FILE_BLOCK_SIZE,
3664 .mode = 0664,
3665 .file_name = ptr_to_u64(mapped_file_name),
3666 .source_file_id = file.id,
3667 .source_offset = INCFS_DATA_FILE_BLOCK_SIZE,
3668 };
3669
3670 TEST(res = ioctl(cmd_fd, INCFS_IOC_CREATE_MAPPED_FILE, &mfa),
3671 res != -1);
3672 TEST(res = read(notify_fd, buffer, sizeof(buffer)), res != -1);
3673 event = (struct inotify_event *) buffer;
3674 TESTEQUAL(event->wd, wds[0]);
3675 TESTEQUAL(event->mask, IN_CREATE);
3676 TESTEQUAL(strcmp(event->name, mapped_file_name), 0);
3677
3678 /* File completion triggers inotify event in .incomplete? */
3679 TESTEQUAL(emit_test_file_data(mount_dir, &file), 0);
3680 TEST(res = read(notify_fd, buffer, sizeof(buffer)), res != -1);
3681 event = (struct inotify_event *) buffer;
3682 TESTEQUAL(event->wd, wds[2]);
3683 TESTEQUAL(event->mask, IN_DELETE);
3684 TESTEQUAL(strcmp(event->name, id), 0);
3685
3686 /* File unlinking triggers inotify event in .index? */
3687 TEST(file_name = concat_file_name(mount_dir, file.name), file_name);
3688 TESTEQUAL(unlink(file_name), 0);
3689 TEST(res = read(notify_fd, buffer, sizeof(buffer)), res != -1);
3690 memset(events, 0, sizeof(events));
3691 memset(names, 0, sizeof(names));
3692 for (ptr = buffer; ptr < buffer + res;) {
3693 event = (struct inotify_event *) ptr;
3694 int i;
3695
3696 TESTCOND(ptr + sizeof(*event) <= buffer + res);
3697 for (i = 0; i < DIRS; ++i)
3698 if (event->wd == wds[i]) {
3699 TESTEQUAL(events[i], NULL);
3700 events[i] = event;
3701 ptr += sizeof(*event);
3702 names[i] = ptr;
3703 ptr += events[i]->len;
3704 TESTCOND(ptr <= buffer + res);
3705 break;
3706 }
3707 TESTCOND(i < DIRS);
3708 }
3709
3710 TESTNE(events[0], NULL);
3711 TESTNE(events[1], NULL);
3712 TESTEQUAL(events[2], NULL);
3713
3714 TESTEQUAL(events[0]->mask, IN_DELETE);
3715 TESTEQUAL(events[1]->mask, IN_DELETE);
3716 TESTEQUAL(strcmp(names[0], file.name), 0);
3717 TESTEQUAL(strcmp(names[1], id), 0);
3718
3719 result = TEST_SUCCESS;
3720 out:
3721 free(file_name);
3722 close(notify_fd);
3723 close(cmd_fd);
3724 umount(mount_dir);
3725 free(backing_dir);
3726 free(index_dir);
3727 free(incomplete_dir);
3728 return result;
3729 }
3730
create_key(void)3731 static EVP_PKEY *create_key(void)
3732 {
3733 EVP_PKEY *pkey = NULL;
3734 RSA *rsa = NULL;
3735 BIGNUM *bn = NULL;
3736
3737 pkey = EVP_PKEY_new();
3738 if (!pkey)
3739 goto fail;
3740
3741 bn = BN_new();
3742 BN_set_word(bn, RSA_F4);
3743
3744 rsa = RSA_new();
3745 if (!rsa)
3746 goto fail;
3747
3748 RSA_generate_key_ex(rsa, 4096, bn, NULL);
3749 EVP_PKEY_assign_RSA(pkey, rsa);
3750
3751 BN_free(bn);
3752 return pkey;
3753
3754 fail:
3755 BN_free(bn);
3756 EVP_PKEY_free(pkey);
3757 return NULL;
3758 }
3759
get_cert(EVP_PKEY * key)3760 static X509 *get_cert(EVP_PKEY *key)
3761 {
3762 X509 *x509 = NULL;
3763 X509_NAME *name = NULL;
3764
3765 x509 = X509_new();
3766 if (!x509)
3767 return NULL;
3768
3769 ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
3770 X509_gmtime_adj(X509_get_notBefore(x509), 0);
3771 X509_gmtime_adj(X509_get_notAfter(x509), 31536000L);
3772 X509_set_pubkey(x509, key);
3773
3774 name = X509_get_subject_name(x509);
3775 X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC,
3776 (const unsigned char *)"US", -1, -1, 0);
3777 X509_NAME_add_entry_by_txt(name, "ST", MBSTRING_ASC,
3778 (const unsigned char *)"CA", -1, -1, 0);
3779 X509_NAME_add_entry_by_txt(name, "L", MBSTRING_ASC,
3780 (const unsigned char *)"San Jose", -1, -1, 0);
3781 X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC,
3782 (const unsigned char *)"Example", -1, -1, 0);
3783 X509_NAME_add_entry_by_txt(name, "OU", MBSTRING_ASC,
3784 (const unsigned char *)"Org", -1, -1, 0);
3785 X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
3786 (const unsigned char *)"www.example.com", -1, -1, 0);
3787 X509_set_issuer_name(x509, name);
3788
3789 if (!X509_sign(x509, key, EVP_sha256()))
3790 return NULL;
3791
3792 return x509;
3793 }
3794
sign(EVP_PKEY * key,X509 * cert,const char * data,size_t len,unsigned char ** sig,size_t * sig_len)3795 static int sign(EVP_PKEY *key, X509 *cert, const char *data, size_t len,
3796 unsigned char **sig, size_t *sig_len)
3797 {
3798 const int pkcs7_flags = PKCS7_BINARY | PKCS7_NOATTR | PKCS7_PARTIAL |
3799 PKCS7_DETACHED;
3800 const EVP_MD *md = EVP_sha256();
3801
3802 int result = TEST_FAILURE;
3803
3804 BIO *bio = NULL;
3805 PKCS7 *p7 = NULL;
3806 unsigned char *bio_buffer;
3807
3808 TEST(bio = BIO_new_mem_buf(data, len), bio);
3809 TEST(p7 = PKCS7_sign(NULL, NULL, NULL, bio, pkcs7_flags), p7);
3810 TESTNE(PKCS7_sign_add_signer(p7, cert, key, md, pkcs7_flags), 0);
3811 TESTEQUAL(PKCS7_final(p7, bio, pkcs7_flags), 1);
3812 TEST(*sig_len = i2d_PKCS7(p7, NULL), *sig_len);
3813 TEST(bio_buffer = malloc(*sig_len), bio_buffer);
3814 *sig = bio_buffer;
3815 TEST(*sig_len = i2d_PKCS7(p7, &bio_buffer), *sig_len);
3816 TESTEQUAL(PKCS7_verify(p7, NULL, NULL, bio, NULL,
3817 pkcs7_flags | PKCS7_NOVERIFY | PKCS7_NOSIGS), 1);
3818
3819 result = TEST_SUCCESS;
3820 out:
3821 PKCS7_free(p7);
3822 BIO_free(bio);
3823 return result;
3824 }
3825
verity_installed(const char * mount_dir,int cmd_fd,bool * installed)3826 static int verity_installed(const char *mount_dir, int cmd_fd, bool *installed)
3827 {
3828 int result = TEST_FAILURE;
3829 char *filename = NULL;
3830 int fd = -1;
3831 struct test_file *file = &get_test_files_set().files[0];
3832
3833 TESTEQUAL(emit_file(cmd_fd, NULL, file->name, &file->id, file->size,
3834 NULL), 0);
3835 TEST(filename = concat_file_name(mount_dir, file->name), filename);
3836 TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
3837 TESTEQUAL(ioctl(fd, FS_IOC_ENABLE_VERITY, NULL), -1);
3838 *installed = errno != EOPNOTSUPP;
3839
3840 result = TEST_SUCCESS;
3841 out:
3842 close(fd);
3843 if (filename)
3844 remove(filename);
3845 free(filename);
3846 return result;
3847 }
3848
enable_verity(const char * mount_dir,struct test_file * file,EVP_PKEY * key,X509 * cert,bool use_signatures)3849 static int enable_verity(const char *mount_dir, struct test_file *file,
3850 EVP_PKEY *key, X509 *cert, bool use_signatures)
3851 {
3852 int result = TEST_FAILURE;
3853 char *filename = NULL;
3854 int fd = -1;
3855 struct fsverity_enable_arg fear = {
3856 .version = 1,
3857 .hash_algorithm = FS_VERITY_HASH_ALG_SHA256,
3858 .block_size = INCFS_DATA_FILE_BLOCK_SIZE,
3859 .sig_size = 0,
3860 .sig_ptr = 0,
3861 };
3862 struct {
3863 __u8 version; /* must be 1 */
3864 __u8 hash_algorithm; /* Merkle tree hash algorithm */
3865 __u8 log_blocksize; /* log2 of size of data and tree blocks */
3866 __u8 salt_size; /* size of salt in bytes; 0 if none */
3867 __le32 sig_size; /* must be 0 */
3868 __le64 data_size; /* size of file the Merkle tree is built over */
3869 __u8 root_hash[64]; /* Merkle tree root hash */
3870 __u8 salt[32]; /* salt prepended to each hashed block */
3871 __u8 __reserved[144]; /* must be 0's */
3872 } __packed fsverity_descriptor = {
3873 .version = 1,
3874 .hash_algorithm = 1,
3875 .log_blocksize = 12,
3876 .data_size = file->size,
3877 };
3878 struct {
3879 char magic[8]; /* must be "FSVerity" */
3880 __le16 digest_algorithm;
3881 __le16 digest_size;
3882 __u8 digest[32];
3883 } __packed fsverity_signed_digest = {
3884 .digest_algorithm = 1,
3885 .digest_size = 32
3886 };
3887 unsigned char *sig = NULL;
3888 size_t sig_size = 0;
3889 uint64_t flags;
3890 struct statx statxbuf = {};
3891
3892 memcpy(fsverity_signed_digest.magic, "FSVerity", 8);
3893
3894 TEST(filename = concat_file_name(mount_dir, file->name), filename);
3895 TESTEQUAL(syscall(__NR_statx, AT_FDCWD, filename, 0, STATX_ALL,
3896 &statxbuf), 0);
3897 TESTEQUAL(statxbuf.stx_attributes_mask & STATX_ATTR_VERITY,
3898 STATX_ATTR_VERITY);
3899 TESTEQUAL(statxbuf.stx_attributes & STATX_ATTR_VERITY, 0);
3900 TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
3901 TESTEQUAL(ioctl(fd, FS_IOC_GETFLAGS, &flags), 0);
3902 TESTEQUAL(flags & FS_VERITY_FL, 0);
3903
3904 /* First try to enable verity with random digest */
3905 if (key) {
3906 TESTEQUAL(sign(key, cert, (void *)&fsverity_signed_digest,
3907 sizeof(fsverity_signed_digest), &sig, &sig_size),
3908 0);
3909
3910 fear.sig_size = sig_size;
3911 fear.sig_ptr = ptr_to_u64(sig);
3912 TESTEQUAL(ioctl(fd, FS_IOC_ENABLE_VERITY, &fear), -1);
3913 }
3914
3915 /* Now try with correct digest */
3916 memcpy(fsverity_descriptor.root_hash, file->root_hash, 32);
3917 sha256((char *)&fsverity_descriptor, sizeof(fsverity_descriptor),
3918 (char *)fsverity_signed_digest.digest);
3919
3920 if (ioctl(fd, FS_IOC_ENABLE_VERITY, NULL) == -1 &&
3921 errno == EOPNOTSUPP) {
3922 result = TEST_SUCCESS;
3923 goto out;
3924 }
3925
3926 free(sig);
3927 sig = NULL;
3928
3929 if (key)
3930 TESTEQUAL(sign(key, cert, (void *)&fsverity_signed_digest,
3931 sizeof(fsverity_signed_digest),
3932 &sig, &sig_size),
3933 0);
3934
3935 if (use_signatures) {
3936 fear.sig_size = sig_size;
3937 file->verity_sig_size = sig_size;
3938 fear.sig_ptr = ptr_to_u64(sig);
3939 file->verity_sig = sig;
3940 sig = NULL;
3941 } else {
3942 fear.sig_size = 0;
3943 fear.sig_ptr = 0;
3944 }
3945 TESTEQUAL(ioctl(fd, FS_IOC_ENABLE_VERITY, &fear), 0);
3946
3947 result = TEST_SUCCESS;
3948 out:
3949 free(sig);
3950 close(fd);
3951 free(filename);
3952 return result;
3953 }
3954
memzero(const unsigned char * buf,size_t size)3955 static int memzero(const unsigned char *buf, size_t size)
3956 {
3957 size_t i;
3958
3959 for (i = 0; i < size; ++i)
3960 if (buf[i])
3961 return -1;
3962 return 0;
3963 }
3964
validate_verity(const char * mount_dir,struct test_file * file)3965 static int validate_verity(const char *mount_dir, struct test_file *file)
3966 {
3967 int result = TEST_FAILURE;
3968 char *filename = concat_file_name(mount_dir, file->name);
3969 int fd = -1;
3970 uint64_t flags;
3971 struct fsverity_digest *digest;
3972 struct statx statxbuf = {};
3973 struct fsverity_read_metadata_arg frma = {};
3974 uint8_t *buf = NULL;
3975 struct fsverity_descriptor desc;
3976
3977 TEST(digest = malloc(sizeof(struct fsverity_digest) +
3978 INCFS_MAX_HASH_SIZE), digest != NULL);
3979 TEST(filename = concat_file_name(mount_dir, file->name), filename);
3980 TESTEQUAL(syscall(__NR_statx, AT_FDCWD, filename, 0, STATX_ALL,
3981 &statxbuf), 0);
3982 TESTEQUAL(statxbuf.stx_attributes & STATX_ATTR_VERITY,
3983 STATX_ATTR_VERITY);
3984 TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
3985 TESTEQUAL(ioctl(fd, FS_IOC_GETFLAGS, &flags), 0);
3986 TESTEQUAL(flags & FS_VERITY_FL, FS_VERITY_FL);
3987 digest->digest_size = INCFS_MAX_HASH_SIZE;
3988 TESTEQUAL(ioctl(fd, FS_IOC_MEASURE_VERITY, digest), 0);
3989 TESTEQUAL(digest->digest_algorithm, FS_VERITY_HASH_ALG_SHA256);
3990 TESTEQUAL(digest->digest_size, 32);
3991
3992 if (file->verity_sig) {
3993 TEST(buf = malloc(file->verity_sig_size), buf);
3994 frma = (struct fsverity_read_metadata_arg) {
3995 .metadata_type = FS_VERITY_METADATA_TYPE_SIGNATURE,
3996 .length = file->verity_sig_size,
3997 .buf_ptr = ptr_to_u64(buf),
3998 };
3999 TESTEQUAL(ioctl(fd, FS_IOC_READ_VERITY_METADATA, &frma),
4000 file->verity_sig_size);
4001 TESTEQUAL(memcmp(buf, file->verity_sig, file->verity_sig_size),
4002 0);
4003 } else {
4004 frma = (struct fsverity_read_metadata_arg) {
4005 .metadata_type = FS_VERITY_METADATA_TYPE_SIGNATURE,
4006 };
4007 TESTEQUAL(ioctl(fd, FS_IOC_READ_VERITY_METADATA, &frma), -1);
4008 TESTEQUAL(errno, ENODATA);
4009 }
4010
4011 frma = (struct fsverity_read_metadata_arg) {
4012 .metadata_type = FS_VERITY_METADATA_TYPE_DESCRIPTOR,
4013 .length = sizeof(desc),
4014 .buf_ptr = ptr_to_u64(&desc),
4015 };
4016 TESTEQUAL(ioctl(fd, FS_IOC_READ_VERITY_METADATA, &frma),
4017 sizeof(desc));
4018 TESTEQUAL(desc.version, 1);
4019 TESTEQUAL(desc.hash_algorithm, FS_VERITY_HASH_ALG_SHA256);
4020 TESTEQUAL(desc.log_blocksize, ilog2(INCFS_DATA_FILE_BLOCK_SIZE));
4021 TESTEQUAL(desc.salt_size, 0);
4022 TESTEQUAL(desc.__reserved_0x04, 0);
4023 TESTEQUAL(desc.data_size, file->size);
4024 TESTEQUAL(memcmp(desc.root_hash, file->root_hash, SHA256_DIGEST_SIZE),
4025 0);
4026 TESTEQUAL(memzero(desc.root_hash + SHA256_DIGEST_SIZE,
4027 sizeof(desc.root_hash) - SHA256_DIGEST_SIZE), 0);
4028 TESTEQUAL(memzero(desc.salt, sizeof(desc.salt)), 0);
4029 TESTEQUAL(memzero(desc.__reserved, sizeof(desc.__reserved)), 0);
4030
4031 result = TEST_SUCCESS;
4032 out:
4033 free(buf);
4034 close(fd);
4035 free(filename);
4036 free(digest);
4037 return result;
4038 }
4039
verity_test_optional_sigs(const char * mount_dir,bool use_signatures)4040 static int verity_test_optional_sigs(const char *mount_dir, bool use_signatures)
4041 {
4042 int result = TEST_FAILURE;
4043 char *backing_dir = NULL;
4044 bool installed;
4045 int cmd_fd = -1;
4046 int i;
4047 struct test_files_set test = get_test_files_set();
4048 const int file_num = test.files_count;
4049 EVP_PKEY *key = NULL;
4050 X509 *cert = NULL;
4051 BIO *mem = NULL;
4052 long len;
4053 void *ptr;
4054 FILE *proc_key_fd = NULL;
4055 char *line = NULL;
4056 size_t read = 0;
4057 int key_id = -1;
4058
4059 TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
4060 TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "readahead=0", false),
4061 0);
4062 TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
4063 TESTEQUAL(verity_installed(mount_dir, cmd_fd, &installed), 0);
4064 if (!installed) {
4065 result = TEST_SUCCESS;
4066 goto out;
4067 }
4068 TEST(key = create_key(), key);
4069 TEST(cert = get_cert(key), cert);
4070
4071 TEST(proc_key_fd = fopen("/proc/keys", "r"), proc_key_fd != NULL);
4072 while (getline(&line, &read, proc_key_fd) != -1)
4073 if (strstr(line, ".fs-verity"))
4074 key_id = strtol(line, NULL, 16);
4075
4076 TEST(mem = BIO_new(BIO_s_mem()), mem != NULL);
4077 TESTEQUAL(i2d_X509_bio(mem, cert), 1);
4078 TEST(len = BIO_get_mem_data(mem, &ptr), len != 0);
4079 TESTCOND(key_id == -1
4080 || syscall(__NR_add_key, "asymmetric", "test:key", ptr, len,
4081 key_id) != -1);
4082
4083 for (i = 0; i < file_num; i++) {
4084 struct test_file *file = &test.files[i];
4085
4086 build_mtree(file);
4087 TESTEQUAL(crypto_emit_file(cmd_fd, NULL, file->name, &file->id,
4088 file->size, file->root_hash,
4089 file->sig.add_data), 0);
4090
4091 TESTEQUAL(load_hash_tree(mount_dir, file), 0);
4092 TESTEQUAL(enable_verity(mount_dir, file, key, cert,
4093 use_signatures),
4094 0);
4095 }
4096
4097 for (i = 0; i < file_num; i++)
4098 TESTEQUAL(validate_verity(mount_dir, &test.files[i]), 0);
4099
4100 close(cmd_fd);
4101 cmd_fd = -1;
4102 TESTEQUAL(umount(mount_dir), 0);
4103 TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "readahead=0", false),
4104 0);
4105
4106 for (i = 0; i < file_num; i++)
4107 TESTEQUAL(validate_verity(mount_dir, &test.files[i]), 0);
4108
4109 result = TEST_SUCCESS;
4110 out:
4111 for (i = 0; i < file_num; i++) {
4112 struct test_file *file = &test.files[i];
4113
4114 free(file->mtree);
4115 free(file->verity_sig);
4116
4117 file->mtree = NULL;
4118 file->verity_sig = NULL;
4119 }
4120
4121 free(line);
4122 BIO_free(mem);
4123 X509_free(cert);
4124 EVP_PKEY_free(key);
4125 fclose(proc_key_fd);
4126 close(cmd_fd);
4127 umount(mount_dir);
4128 free(backing_dir);
4129 return result;
4130 }
4131
verity_test(const char * mount_dir)4132 static int verity_test(const char *mount_dir)
4133 {
4134 int result = TEST_FAILURE;
4135
4136 TESTEQUAL(verity_test_optional_sigs(mount_dir, true), TEST_SUCCESS);
4137 TESTEQUAL(verity_test_optional_sigs(mount_dir, false), TEST_SUCCESS);
4138 result = TEST_SUCCESS;
4139 out:
4140 return result;
4141 }
4142
verity_file_valid(const char * mount_dir,struct test_file * file)4143 static int verity_file_valid(const char *mount_dir, struct test_file *file)
4144 {
4145 int result = TEST_FAILURE;
4146 char *filename = NULL;
4147 int fd = -1;
4148 uint8_t buffer[INCFS_DATA_FILE_BLOCK_SIZE];
4149 struct incfs_get_file_sig_args gfsa = {
4150 .file_signature = ptr_to_u64(buffer),
4151 .file_signature_buf_size = sizeof(buffer),
4152 };
4153 int i;
4154
4155 TEST(filename = concat_file_name(mount_dir, file->name), filename);
4156 TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
4157 TESTEQUAL(ioctl(fd, INCFS_IOC_READ_FILE_SIGNATURE, &gfsa), 0);
4158 for (i = 0; i < file->size; i += sizeof(buffer))
4159 TESTEQUAL(pread(fd, buffer, sizeof(buffer), i),
4160 file->size - i > sizeof(buffer) ?
4161 sizeof(buffer) : file->size - i);
4162
4163 result = TEST_SUCCESS;
4164 out:
4165 close(fd);
4166 free(filename);
4167 return result;
4168 }
4169
enable_verity_test(const char * mount_dir)4170 static int enable_verity_test(const char *mount_dir)
4171 {
4172 int result = TEST_FAILURE;
4173 char *backing_dir = NULL;
4174 bool installed;
4175 int cmd_fd = -1;
4176 struct test_files_set test = get_test_files_set();
4177 int i;
4178
4179 TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
4180 TESTEQUAL(mount_fs(mount_dir, backing_dir, 0), 0);
4181 TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
4182 TESTEQUAL(verity_installed(mount_dir, cmd_fd, &installed), 0);
4183 if (!installed) {
4184 result = TEST_SUCCESS;
4185 goto out;
4186 }
4187 for (i = 0; i < test.files_count; ++i) {
4188 struct test_file *file = &test.files[i];
4189
4190 TESTEQUAL(emit_file(cmd_fd, NULL, file->name, &file->id,
4191 file->size, NULL), 0);
4192 TESTEQUAL(emit_test_file_data(mount_dir, file), 0);
4193 TESTEQUAL(enable_verity(mount_dir, file, NULL, NULL, false), 0);
4194 }
4195
4196 /* Check files are valid on disk */
4197 close(cmd_fd);
4198 cmd_fd = -1;
4199 TESTEQUAL(umount(mount_dir), 0);
4200 TESTEQUAL(mount_fs(mount_dir, backing_dir, 0), 0);
4201 for (i = 0; i < test.files_count; ++i)
4202 TESTEQUAL(verity_file_valid(mount_dir, &test.files[i]), 0);
4203
4204 result = TEST_SUCCESS;
4205 out:
4206 close(cmd_fd);
4207 umount(mount_dir);
4208 free(backing_dir);
4209 return result;
4210 }
4211
mmap_test(const char * mount_dir)4212 static int mmap_test(const char *mount_dir)
4213 {
4214 int result = TEST_FAILURE;
4215 char *backing_dir = NULL;
4216 int cmd_fd = -1;
4217 /*
4218 * File is big enough to have a two layer tree with two hashes in the
4219 * higher level, so we can corrupt the second one
4220 */
4221 int shas_per_block = INCFS_DATA_FILE_BLOCK_SIZE / SHA256_DIGEST_SIZE;
4222 struct test_file file = {
4223 .name = "file",
4224 .size = INCFS_DATA_FILE_BLOCK_SIZE * shas_per_block * 2,
4225 };
4226 char *filename = NULL;
4227 int fd = -1;
4228 char *addr = (void *)-1;
4229
4230 TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
4231 TESTEQUAL(mount_fs(mount_dir, backing_dir, 0), 0);
4232 TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
4233
4234 TESTEQUAL(build_mtree(&file), 0);
4235 file.mtree[1].data[INCFS_DATA_FILE_BLOCK_SIZE] ^= 0xff;
4236 TESTEQUAL(crypto_emit_file(cmd_fd, NULL, file.name, &file.id,
4237 file.size, file.root_hash,
4238 file.sig.add_data), 0);
4239 TESTEQUAL(emit_test_file_data(mount_dir, &file), 0);
4240 TESTEQUAL(load_hash_tree(mount_dir, &file), 0);
4241 TEST(filename = concat_file_name(mount_dir, file.name), filename);
4242 TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
4243 TEST(addr = mmap(NULL, file.size, PROT_READ, MAP_PRIVATE, fd, 0),
4244 addr != (void *) -1);
4245 TESTEQUAL(mlock(addr, INCFS_DATA_FILE_BLOCK_SIZE), 0);
4246 TESTEQUAL(munlock(addr, INCFS_DATA_FILE_BLOCK_SIZE), 0);
4247 TESTEQUAL(mlock(addr + shas_per_block * INCFS_DATA_FILE_BLOCK_SIZE,
4248 INCFS_DATA_FILE_BLOCK_SIZE), -1);
4249 TESTEQUAL(mlock(addr + (shas_per_block - 1) *
4250 INCFS_DATA_FILE_BLOCK_SIZE,
4251 INCFS_DATA_FILE_BLOCK_SIZE), 0);
4252 TESTEQUAL(munlock(addr + (shas_per_block - 1) *
4253 INCFS_DATA_FILE_BLOCK_SIZE,
4254 INCFS_DATA_FILE_BLOCK_SIZE), 0);
4255 TESTEQUAL(mlock(addr + (shas_per_block - 1) *
4256 INCFS_DATA_FILE_BLOCK_SIZE,
4257 INCFS_DATA_FILE_BLOCK_SIZE * 2), -1);
4258 TESTEQUAL(munmap(addr, file.size), 0);
4259
4260 result = TEST_SUCCESS;
4261 out:
4262 free(file.mtree);
4263 close(fd);
4264 free(filename);
4265 close(cmd_fd);
4266 umount(mount_dir);
4267 free(backing_dir);
4268 return result;
4269 }
4270
truncate_test(const char * mount_dir)4271 static int truncate_test(const char *mount_dir)
4272 {
4273 int result = TEST_FAILURE;
4274 char *backing_dir = NULL;
4275 int cmd_fd = -1;
4276 struct test_file file = {
4277 .name = "file",
4278 .size = INCFS_DATA_FILE_BLOCK_SIZE,
4279 };
4280 char *backing_file = NULL;
4281 int fd = -1;
4282 struct stat st;
4283
4284 TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
4285 TESTEQUAL(mount_fs(mount_dir, backing_dir, 0), 0);
4286 TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
4287 TESTEQUAL(emit_file(cmd_fd, NULL, file.name, &file.id, file.size, NULL),
4288 0);
4289 TEST(backing_file = concat_file_name(backing_dir, file.name),
4290 backing_file);
4291 TEST(fd = open(backing_file, O_RDWR | O_CLOEXEC), fd != -1);
4292 TESTEQUAL(stat(backing_file, &st), 0);
4293 TESTCOND(st.st_blocks < 128);
4294 TESTEQUAL(fallocate(fd, FALLOC_FL_KEEP_SIZE, 0, 1 << 24), 0);
4295 TESTEQUAL(stat(backing_file, &st), 0);
4296 TESTCOND(st.st_blocks > 32768);
4297 TESTEQUAL(emit_test_file_data(mount_dir, &file), 0);
4298 TESTEQUAL(stat(backing_file, &st), 0);
4299 TESTCOND(st.st_blocks < 128);
4300
4301 result = TEST_SUCCESS;
4302 out:
4303 close(fd);
4304 free(backing_file);
4305 close(cmd_fd);
4306 umount(mount_dir);
4307 free(backing_dir);
4308 return result;
4309 }
4310
stat_file_test(const char * mount_dir,int cmd_fd,struct test_file * file)4311 static int stat_file_test(const char *mount_dir, int cmd_fd,
4312 struct test_file *file)
4313 {
4314 int result = TEST_FAILURE;
4315 struct stat st;
4316 char *filename = NULL;
4317
4318 TESTEQUAL(emit_file(cmd_fd, NULL, file->name, &file->id,
4319 file->size, NULL), 0);
4320 TEST(filename = concat_file_name(mount_dir, file->name), filename);
4321 TESTEQUAL(stat(filename, &st), 0);
4322 TESTCOND(st.st_blocks < 32);
4323 TESTEQUAL(emit_test_file_data(mount_dir, file), 0);
4324 TESTEQUAL(stat(filename, &st), 0);
4325 TESTCOND(st.st_blocks > file->size / 512);
4326
4327 result = TEST_SUCCESS;
4328 out:
4329 free(filename);
4330 return result;
4331 }
4332
stat_test(const char * mount_dir)4333 static int stat_test(const char *mount_dir)
4334 {
4335 int result = TEST_FAILURE;
4336 char *backing_dir = NULL;
4337 int cmd_fd = -1;
4338 int i;
4339 struct test_files_set test = get_test_files_set();
4340 const int file_num = test.files_count;
4341
4342 TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
4343 TESTEQUAL(mount_fs(mount_dir, backing_dir, 0), 0);
4344 TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
4345
4346 for (i = 0; i < file_num; i++) {
4347 struct test_file *file = &test.files[i];
4348
4349 TESTEQUAL(stat_file_test(mount_dir, cmd_fd, file), 0);
4350 }
4351
4352 result = TEST_SUCCESS;
4353 out:
4354 close(cmd_fd);
4355 umount(mount_dir);
4356 free(backing_dir);
4357 return result;
4358 }
4359
4360 #define SYSFS_DIR "/sys/fs/incremental-fs/instances/test_node/"
4361
sysfs_test_value(const char * name,uint64_t value)4362 static int sysfs_test_value(const char *name, uint64_t value)
4363 {
4364 int result = TEST_FAILURE;
4365 char *filename = NULL;
4366 FILE *file = NULL;
4367 uint64_t res;
4368
4369 TEST(filename = concat_file_name(SYSFS_DIR, name), filename);
4370 TEST(file = fopen(filename, "re"), file);
4371 TESTEQUAL(fscanf(file, "%lu", &res), 1);
4372 TESTEQUAL(res, value);
4373
4374 result = TEST_SUCCESS;
4375 out:
4376 if (file)
4377 fclose(file);
4378 free(filename);
4379 return result;
4380 }
4381
sysfs_test_value_range(const char * name,uint64_t low,uint64_t high)4382 static int sysfs_test_value_range(const char *name, uint64_t low, uint64_t high)
4383 {
4384 int result = TEST_FAILURE;
4385 char *filename = NULL;
4386 FILE *file = NULL;
4387 uint64_t res;
4388
4389 TEST(filename = concat_file_name(SYSFS_DIR, name), filename);
4390 TEST(file = fopen(filename, "re"), file);
4391 TESTEQUAL(fscanf(file, "%lu", &res), 1);
4392 TESTCOND(res >= low && res <= high);
4393
4394 result = TEST_SUCCESS;
4395 out:
4396 if (file)
4397 fclose(file);
4398 free(filename);
4399 return result;
4400 }
4401
ioctl_test_last_error(int cmd_fd,const incfs_uuid_t * file_id,int page,int error)4402 static int ioctl_test_last_error(int cmd_fd, const incfs_uuid_t *file_id,
4403 int page, int error)
4404 {
4405 int result = TEST_FAILURE;
4406 struct incfs_get_last_read_error_args glre;
4407
4408 TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_GET_LAST_READ_ERROR, &glre), 0);
4409 if (file_id)
4410 TESTEQUAL(memcmp(&glre.file_id_out, file_id, sizeof(*file_id)),
4411 0);
4412
4413 TESTEQUAL(glre.page_out, page);
4414 TESTEQUAL(glre.errno_out, error);
4415 result = TEST_SUCCESS;
4416 out:
4417 return result;
4418 }
4419
sysfs_test(const char * mount_dir)4420 static int sysfs_test(const char *mount_dir)
4421 {
4422 int result = TEST_FAILURE;
4423 char *backing_dir = NULL;
4424 int cmd_fd = -1;
4425 struct test_file file = {
4426 .name = "file",
4427 .size = INCFS_DATA_FILE_BLOCK_SIZE,
4428 };
4429 char *filename = NULL;
4430 int fd = -1;
4431 int pid = -1;
4432 char buffer[32];
4433 char *null_buf = NULL;
4434 int status;
4435 struct incfs_per_uid_read_timeouts purt_set[] = {
4436 {
4437 .uid = 0,
4438 .min_time_us = 1000000,
4439 .min_pending_time_us = 1000000,
4440 .max_pending_time_us = 2000000,
4441 },
4442 };
4443 struct incfs_set_read_timeouts_args srt = {
4444 ptr_to_u64(purt_set),
4445 sizeof(purt_set)
4446 };
4447
4448 TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
4449 TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "sysfs_name=test_node",
4450 false),
4451 0);
4452 TEST(cmd_fd = open_commands_file(mount_dir), cmd_fd != -1);
4453 TESTEQUAL(build_mtree(&file), 0);
4454 file.root_hash[0] ^= 0xff;
4455 TESTEQUAL(crypto_emit_file(cmd_fd, NULL, file.name, &file.id, file.size,
4456 file.root_hash, file.sig.add_data),
4457 0);
4458 TEST(filename = concat_file_name(mount_dir, file.name), filename);
4459 TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
4460 TESTEQUAL(ioctl_test_last_error(cmd_fd, NULL, 0, 0), 0);
4461 TESTEQUAL(sysfs_test_value("reads_failed_timed_out", 0), 0);
4462 TESTEQUAL(read(fd, null_buf, 1), -1);
4463 TESTEQUAL(ioctl_test_last_error(cmd_fd, &file.id, 0, -ETIME), 0);
4464 TESTEQUAL(sysfs_test_value("reads_failed_timed_out", 2), 0);
4465
4466 TESTEQUAL(emit_test_file_data(mount_dir, &file), 0);
4467 TESTEQUAL(sysfs_test_value("reads_failed_hash_verification", 0), 0);
4468 TESTEQUAL(read(fd, null_buf, 1), -1);
4469 TESTEQUAL(sysfs_test_value("reads_failed_hash_verification", 1), 0);
4470 TESTSYSCALL(close(fd));
4471 fd = -1;
4472
4473 TESTSYSCALL(unlink(filename));
4474 TESTEQUAL(mount_fs_opt(mount_dir, backing_dir,
4475 "read_timeout_ms=10000,sysfs_name=test_node",
4476 true),
4477 0);
4478 TESTEQUAL(emit_file(cmd_fd, NULL, file.name, &file.id, file.size, NULL),
4479 0);
4480 TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
4481 TESTSYSCALL(fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC));
4482 TEST(pid = fork(), pid != -1);
4483 if (pid == 0) {
4484 TESTEQUAL(read(fd, buffer, sizeof(buffer)), sizeof(buffer));
4485 exit(0);
4486 }
4487 sleep(1);
4488 TESTEQUAL(sysfs_test_value("reads_delayed_pending", 0), 0);
4489 TESTEQUAL(emit_test_file_data(mount_dir, &file), 0);
4490 TESTNE(wait(&status), -1);
4491 TESTEQUAL(status, 0);
4492 TESTEQUAL(sysfs_test_value("reads_delayed_pending", 1), 0);
4493 /* Allow +/- 10% */
4494 TESTEQUAL(sysfs_test_value_range("reads_delayed_pending_us", 900000, 1100000),
4495 0);
4496
4497 TESTSYSCALL(close(fd));
4498 fd = -1;
4499
4500 TESTSYSCALL(unlink(filename));
4501 TESTEQUAL(ioctl(cmd_fd, INCFS_IOC_SET_READ_TIMEOUTS, &srt), 0);
4502 TESTEQUAL(emit_file(cmd_fd, NULL, file.name, &file.id, file.size, NULL),
4503 0);
4504 TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
4505 TESTEQUAL(sysfs_test_value("reads_delayed_min", 0), 0);
4506 TESTEQUAL(emit_test_file_data(mount_dir, &file), 0);
4507 TESTEQUAL(read(fd, buffer, sizeof(buffer)), sizeof(buffer));
4508 TESTEQUAL(sysfs_test_value("reads_delayed_min", 1), 0);
4509 /* This should be exact */
4510 TESTEQUAL(sysfs_test_value("reads_delayed_min_us", 1000000), 0);
4511
4512 TESTSYSCALL(close(fd));
4513 fd = -1;
4514
4515 TESTSYSCALL(unlink(filename));
4516 TESTEQUAL(emit_file(cmd_fd, NULL, file.name, &file.id, file.size, NULL),
4517 0);
4518 TEST(fd = open(filename, O_RDONLY | O_CLOEXEC), fd != -1);
4519 TESTSYSCALL(fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC));
4520 TEST(pid = fork(), pid != -1);
4521 if (pid == 0) {
4522 TESTEQUAL(read(fd, buffer, sizeof(buffer)), sizeof(buffer));
4523 exit(0);
4524 }
4525 usleep(500000);
4526 TESTEQUAL(sysfs_test_value("reads_delayed_pending", 1), 0);
4527 TESTEQUAL(sysfs_test_value("reads_delayed_min", 1), 0);
4528 TESTEQUAL(emit_test_file_data(mount_dir, &file), 0);
4529 TESTNE(wait(&status), -1);
4530 TESTEQUAL(status, 0);
4531 TESTEQUAL(sysfs_test_value("reads_delayed_pending", 2), 0);
4532 TESTEQUAL(sysfs_test_value("reads_delayed_min", 2), 0);
4533 /* Exact 1000000 plus 500000 +/- 10% */
4534 TESTEQUAL(sysfs_test_value_range("reads_delayed_min_us", 1450000, 1550000), 0);
4535 /* Allow +/- 10% */
4536 TESTEQUAL(sysfs_test_value_range("reads_delayed_pending_us", 1350000, 1650000),
4537 0);
4538
4539 result = TEST_SUCCESS;
4540 out:
4541 if (pid == 0)
4542 exit(result);
4543 free(file.mtree);
4544 free(filename);
4545 close(fd);
4546 close(cmd_fd);
4547 umount(mount_dir);
4548 free(backing_dir);
4549 return result;
4550 }
4551
sysfs_test_directories(bool one_present,bool two_present)4552 static int sysfs_test_directories(bool one_present, bool two_present)
4553 {
4554 int result = TEST_FAILURE;
4555 struct stat st;
4556
4557 TESTEQUAL(stat("/sys/fs/incremental-fs/instances/1", &st),
4558 one_present ? 0 : -1);
4559 if (one_present)
4560 TESTCOND(S_ISDIR(st.st_mode));
4561 else
4562 TESTEQUAL(errno, ENOENT);
4563 TESTEQUAL(stat("/sys/fs/incremental-fs/instances/2", &st),
4564 two_present ? 0 : -1);
4565 if (two_present)
4566 TESTCOND(S_ISDIR(st.st_mode));
4567 else
4568 TESTEQUAL(errno, ENOENT);
4569
4570 result = TEST_SUCCESS;
4571 out:
4572 return result;
4573 }
4574
sysfs_rename_test(const char * mount_dir)4575 static int sysfs_rename_test(const char *mount_dir)
4576 {
4577 int result = TEST_FAILURE;
4578 char *backing_dir = NULL;
4579 char *mount_dir2 = NULL;
4580 int fd = -1;
4581 char c;
4582
4583 /* Mount with no node */
4584 TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
4585 TESTEQUAL(mount_fs(mount_dir, backing_dir, 0), 0);
4586 TESTEQUAL(sysfs_test_directories(false, false), 0);
4587
4588 /* Remount with node */
4589 TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "sysfs_name=1", true),
4590 0);
4591 TESTEQUAL(sysfs_test_directories(true, false), 0);
4592 TEST(fd = open("/sys/fs/incremental-fs/instances/1/reads_delayed_min",
4593 O_RDONLY | O_CLOEXEC), fd != -1);
4594 TESTEQUAL(pread(fd, &c, 1, 0), 1);
4595 TESTEQUAL(c, '0');
4596 TESTEQUAL(pread(fd, &c, 1, 0), 1);
4597 TESTEQUAL(c, '0');
4598
4599 /* Rename node */
4600 TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "sysfs_name=2", true),
4601 0);
4602 TESTEQUAL(sysfs_test_directories(false, true), 0);
4603 TESTEQUAL(pread(fd, &c, 1, 0), -1);
4604
4605 /* Try mounting another instance with same node name */
4606 TEST(mount_dir2 = concat_file_name(backing_dir, "incfs-mount-dir2"),
4607 mount_dir2);
4608 rmdir(mount_dir2); /* In case we crashed before */
4609 TESTSYSCALL(mkdir(mount_dir2, 0777));
4610 TEST(mount_fs_opt(mount_dir2, backing_dir, "sysfs_name=2", false),
4611 -1);
4612
4613 /* Try mounting another instance then remounting with existing name */
4614 TESTEQUAL(mount_fs(mount_dir2, backing_dir, 0), 0);
4615 TESTEQUAL(mount_fs_opt(mount_dir2, backing_dir, "sysfs_name=2", true),
4616 -1);
4617
4618 /* Remount with no node */
4619 TESTEQUAL(mount_fs_opt(mount_dir, backing_dir, "", true),
4620 0);
4621 TESTEQUAL(sysfs_test_directories(false, false), 0);
4622
4623 result = TEST_SUCCESS;
4624 out:
4625 umount(mount_dir2);
4626 rmdir(mount_dir2);
4627 free(mount_dir2);
4628 close(fd);
4629 umount(mount_dir);
4630 free(backing_dir);
4631 return result;
4632 }
4633
stacked_mount_test(const char * mount_dir)4634 static int stacked_mount_test(const char *mount_dir)
4635 {
4636 int result = TEST_FAILURE;
4637 char *backing_dir = NULL;
4638
4639 /* Mount with no node */
4640 TEST(backing_dir = create_backing_dir(mount_dir), backing_dir);
4641 TESTEQUAL(mount_fs(mount_dir, backing_dir, 0), 0);
4642 /* Try mounting another instance with same name */
4643 TESTEQUAL(mount_fs(mount_dir, backing_dir, 0), 0);
4644 /* Try unmounting the first instance */
4645 TESTEQUAL(umount_fs(mount_dir), 0);
4646 /* Try unmounting the second instance */
4647 TESTEQUAL(umount_fs(mount_dir), 0);
4648 result = TEST_SUCCESS;
4649 out:
4650 /* Cleanup */
4651 rmdir(mount_dir);
4652 rmdir(backing_dir);
4653 free(backing_dir);
4654 return result;
4655 }
4656
setup_mount_dir()4657 static char *setup_mount_dir()
4658 {
4659 struct stat st;
4660 char *current_dir = getcwd(NULL, 0);
4661 char *mount_dir = concat_file_name(current_dir, "incfs-mount-dir");
4662
4663 free(current_dir);
4664 if (stat(mount_dir, &st) == 0) {
4665 if (S_ISDIR(st.st_mode))
4666 return mount_dir;
4667
4668 ksft_print_msg("%s is a file, not a dir.\n", mount_dir);
4669 return NULL;
4670 }
4671
4672 if (mkdir(mount_dir, 0777)) {
4673 print_error("Can't create mount dir.");
4674 return NULL;
4675 }
4676
4677 return mount_dir;
4678 }
4679
parse_options(int argc,char * const * argv)4680 int parse_options(int argc, char *const *argv)
4681 {
4682 signed char c;
4683
4684 while ((c = getopt(argc, argv, "f:t:v")) != -1)
4685 switch (c) {
4686 case 'f':
4687 options.file = strtol(optarg, NULL, 10);
4688 break;
4689
4690 case 't':
4691 options.test = strtol(optarg, NULL, 10);
4692 break;
4693
4694 case 'v':
4695 options.verbose = true;
4696 break;
4697
4698 default:
4699 return -EINVAL;
4700 }
4701
4702 return 0;
4703 }
4704
4705 struct test_case {
4706 int (*pfunc)(const char *dir);
4707 const char *name;
4708 };
4709
run_one_test(const char * mount_dir,struct test_case * test_case)4710 void run_one_test(const char *mount_dir, struct test_case *test_case)
4711 {
4712 int ret;
4713
4714 ksft_print_msg("Running %s\n", test_case->name);
4715 ret = test_case->pfunc(mount_dir);
4716
4717 if (ret == TEST_SUCCESS)
4718 ksft_test_result_pass("%s\n", test_case->name);
4719 else if (ret == TEST_SKIP)
4720 ksft_test_result_skip("%s\n", test_case->name);
4721 else
4722 ksft_test_result_fail("%s\n", test_case->name);
4723 }
4724
main(int argc,char * argv[])4725 int main(int argc, char *argv[])
4726 {
4727 char *mount_dir = NULL;
4728 int i;
4729 int fd, count;
4730
4731 if (parse_options(argc, argv))
4732 ksft_exit_fail_msg("Bad options\n");
4733
4734 // Seed randomness pool for testing on QEMU
4735 // NOTE - this abuses the concept of randomness - do *not* ever do this
4736 // on a machine for production use - the device will think it has good
4737 // randomness when it does not.
4738 fd = open("/dev/urandom", O_WRONLY | O_CLOEXEC);
4739 count = 4096;
4740 for (int i = 0; i < 128; ++i)
4741 ioctl(fd, RNDADDTOENTCNT, &count);
4742 close(fd);
4743
4744 ksft_print_header();
4745
4746 if (geteuid() != 0)
4747 ksft_print_msg("Not a root, might fail to mount.\n");
4748
4749 mount_dir = setup_mount_dir();
4750 if (mount_dir == NULL)
4751 ksft_exit_fail_msg("Can't create a mount dir\n");
4752
4753 #define MAKE_TEST(test) \
4754 { \
4755 test, #test \
4756 }
4757 struct test_case cases[] = {
4758 MAKE_TEST(basic_file_ops_test),
4759 MAKE_TEST(cant_touch_index_test),
4760 MAKE_TEST(dynamic_files_and_data_test),
4761 MAKE_TEST(concurrent_reads_and_writes_test),
4762 MAKE_TEST(attribute_test),
4763 MAKE_TEST(work_after_remount_test),
4764 MAKE_TEST(child_procs_waiting_for_data_test),
4765 MAKE_TEST(multiple_providers_test),
4766 MAKE_TEST(hash_tree_test),
4767 MAKE_TEST(read_log_test),
4768 MAKE_TEST(get_blocks_test),
4769 MAKE_TEST(get_hash_blocks_test),
4770 MAKE_TEST(large_file_test),
4771 MAKE_TEST(mapped_file_test),
4772 MAKE_TEST(compatibility_test),
4773 MAKE_TEST(data_block_count_test),
4774 MAKE_TEST(hash_block_count_test),
4775 MAKE_TEST(per_uid_read_timeouts_test),
4776 MAKE_TEST(inotify_test),
4777 MAKE_TEST(verity_test),
4778 MAKE_TEST(enable_verity_test),
4779 MAKE_TEST(mmap_test),
4780 MAKE_TEST(truncate_test),
4781 MAKE_TEST(stat_test),
4782 MAKE_TEST(sysfs_test),
4783 MAKE_TEST(sysfs_rename_test),
4784 MAKE_TEST(stacked_mount_test),
4785 };
4786 #undef MAKE_TEST
4787
4788 if (options.test) {
4789 if (options.test <= 0 || options.test > ARRAY_SIZE(cases))
4790 ksft_exit_fail_msg("Invalid test\n");
4791
4792 ksft_set_plan(1);
4793 run_one_test(mount_dir, &cases[options.test - 1]);
4794 } else {
4795 ksft_set_plan(ARRAY_SIZE(cases));
4796 for (i = 0; i < ARRAY_SIZE(cases); ++i)
4797 run_one_test(mount_dir, &cases[i]);
4798 }
4799
4800 umount2(mount_dir, MNT_FORCE);
4801 rmdir(mount_dir);
4802 return !ksft_get_fail_cnt() ? ksft_exit_pass() : ksft_exit_fail();
4803 }
4804