]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/journal-verify.c
ad96cca4778ac20bb3c560332b2a87ef3e306560
[thirdparty/systemd.git] / src / journal / journal-verify.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2012 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <unistd.h>
23 #include <sys/mman.h>
24 #include <fcntl.h>
25
26 #include "util.h"
27 #include "macro.h"
28 #include "journal-def.h"
29 #include "journal-file.h"
30 #include "journal-authenticate.h"
31 #include "journal-verify.h"
32 #include "lookup3.h"
33 #include "compress.h"
34
35 /* FIXME:
36 *
37 * - verify FSPRG
38 * - Allow building without libgcrypt
39 * - check with sparse
40 * - 64bit conversions
41 *
42 * */
43
44 static int journal_file_object_verify(JournalFile *f, Object *o) {
45 assert(f);
46 assert(o);
47
48 /* This does various superficial tests about the length an
49 * possible field values. It does not follow any references to
50 * other objects. */
51
52 if ((o->object.flags & OBJECT_COMPRESSED) &&
53 o->object.type != OBJECT_DATA)
54 return -EBADMSG;
55
56 switch (o->object.type) {
57
58 case OBJECT_DATA: {
59 uint64_t h1, h2;
60
61 if (le64toh(o->data.entry_offset) <= 0 ||
62 le64toh(o->data.n_entries) <= 0)
63 return -EBADMSG;
64
65 if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0)
66 return -EBADMSG;
67
68 h1 = le64toh(o->data.hash);
69
70 if (o->object.flags & OBJECT_COMPRESSED) {
71 void *b = NULL;
72 uint64_t alloc = 0, b_size;
73
74 if (!uncompress_blob(o->data.payload,
75 le64toh(o->object.size) - offsetof(Object, data.payload),
76 &b, &alloc, &b_size))
77 return -EBADMSG;
78
79 h2 = hash64(b, b_size);
80 free(b);
81 } else
82 h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
83
84 if (h1 != h2)
85 return -EBADMSG;
86
87 break;
88 }
89
90 case OBJECT_FIELD:
91 if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0)
92 return -EBADMSG;
93 break;
94
95 case OBJECT_ENTRY:
96 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0)
97 return -EBADMSG;
98
99 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0)
100 return -EBADMSG;
101
102 if (le64toh(o->entry.seqnum) <= 0 ||
103 le64toh(o->entry.realtime) <= 0)
104 return -EBADMSG;
105
106 break;
107
108 case OBJECT_DATA_HASH_TABLE:
109 case OBJECT_FIELD_HASH_TABLE:
110 if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0)
111 return -EBADMSG;
112
113 if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0)
114 return -EBADMSG;
115
116 break;
117
118 case OBJECT_ENTRY_ARRAY:
119 if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0)
120 return -EBADMSG;
121
122 if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0)
123 return -EBADMSG;
124
125 break;
126
127 case OBJECT_TAG:
128 if (le64toh(o->object.size) != sizeof(TagObject))
129 return -EBADMSG;
130 break;
131 }
132
133 return 0;
134 }
135
136 static void draw_progress(uint64_t p, usec_t *last_usec) {
137 unsigned n, i, j, k;
138 usec_t z, x;
139
140 if (!isatty(STDOUT_FILENO))
141 return;
142
143 z = now(CLOCK_MONOTONIC);
144 x = *last_usec;
145
146 if (x != 0 && x + 40 * USEC_PER_MSEC > z)
147 return;
148
149 *last_usec = z;
150
151 n = (3 * columns()) / 4;
152 j = (n * (unsigned) p) / 65535ULL;
153 k = n - j;
154
155 fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN_ON, stdout);
156
157 for (i = 0; i < j; i++)
158 fputs("\xe2\x96\x88", stdout);
159
160 fputs(ANSI_HIGHLIGHT_OFF, stdout);
161
162 for (i = 0; i < k; i++)
163 fputs("\xe2\x96\x91", stdout);
164
165 printf(" %3lu%%", 100LU * (unsigned long) p / 65535LU);
166
167 fputs("\r\x1B[?25h", stdout);
168 fflush(stdout);
169 }
170
171 static void flush_progress(void) {
172 unsigned n, i;
173
174 if (!isatty(STDOUT_FILENO))
175 return;
176
177 n = (3 * columns()) / 4;
178
179 putchar('\r');
180
181 for (i = 0; i < n + 5; i++)
182 putchar(' ');
183
184 putchar('\r');
185 fflush(stdout);
186 }
187
188 static int write_uint64(int fd, uint64_t p) {
189 ssize_t k;
190
191 k = write(fd, &p, sizeof(p));
192 if (k < 0)
193 return -errno;
194 if (k != sizeof(p))
195 return -EIO;
196
197 return 0;
198 }
199
200 static int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
201 uint64_t a, b;
202 int r;
203
204 assert(m);
205 assert(fd >= 0);
206
207 /* Bisection ... */
208
209 a = 0; b = n;
210 while (a < b) {
211 uint64_t c, *z;
212
213 c = (a + b) / 2;
214
215 r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, c * sizeof(uint64_t), sizeof(uint64_t), (void **) &z);
216 if (r < 0)
217 return r;
218
219 if (*z == p)
220 return 1;
221
222 if (p < *z)
223 b = c;
224 else
225 a = c;
226 }
227
228 return 0;
229 }
230
231 static int entry_points_to_data(
232 JournalFile *f,
233 int entry_fd,
234 uint64_t n_entries,
235 uint64_t entry_p,
236 uint64_t data_p) {
237
238 int r;
239 uint64_t i, n, a;
240 Object *o;
241 bool found = false;
242
243 assert(f);
244 assert(entry_fd >= 0);
245
246 if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
247 log_error("Data object references invalid entry at %llu", (unsigned long long) data_p);
248 return -EBADMSG;
249 }
250
251 r = journal_file_move_to_object(f, OBJECT_ENTRY, entry_p, &o);
252 if (r < 0)
253 return r;
254
255 n = journal_file_entry_n_items(o);
256 for (i = 0; i < n; i++)
257 if (le64toh(o->entry.items[i].object_offset) == data_p) {
258 found = true;
259 break;
260 }
261
262 if (!found) {
263 log_error("Data object not referenced by linked entry at %llu", (unsigned long long) data_p);
264 return -EBADMSG;
265 }
266
267 /* Check if this entry is also in main entry array. Since the
268 * main entry array has already been verified we can rely on
269 * its consistency.*/
270
271 n = le64toh(f->header->n_entries);
272 a = le64toh(f->header->entry_array_offset);
273 i = 0;
274
275 while (i < n) {
276 uint64_t m, j;
277
278 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
279 if (r < 0)
280 return r;
281
282 m = journal_file_entry_array_n_items(o);
283 for (j = 0; i < n && j < m; i++, j++)
284 if (le64toh(o->entry_array.items[j]) == entry_p)
285 return 0;
286
287 a = le64toh(o->entry_array.next_entry_array_offset);;
288 }
289
290 return 0;
291 }
292
293 static int verify_data(
294 JournalFile *f,
295 Object *o, uint64_t p,
296 int entry_fd, uint64_t n_entries,
297 int entry_array_fd, uint64_t n_entry_arrays) {
298
299 uint64_t i, n, a, last, q;
300 int r;
301
302 assert(f);
303 assert(o);
304 assert(entry_fd >= 0);
305 assert(entry_array_fd >= 0);
306
307 n = le64toh(o->data.n_entries);
308 a = le64toh(o->data.entry_array_offset);
309
310 /* We already checked this earlier */
311 assert(n > 0);
312
313 last = q = le64toh(o->data.entry_offset);
314 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
315 if (r < 0)
316 return r;
317
318 i = 1;
319 while (i < n) {
320 uint64_t next, m, j;
321
322 if (a == 0) {
323 log_error("Array chain too short at %llu.", (unsigned long long) p);
324 return -EBADMSG;
325 }
326
327 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
328 log_error("Invalid array at %llu.", (unsigned long long) p);
329 return -EBADMSG;
330 }
331
332 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
333 if (r < 0)
334 return r;
335
336 next = le64toh(o->entry_array.next_entry_array_offset);
337 if (next != 0 && next <= a) {
338 log_error("Array chain has cycle at %llu.", (unsigned long long) p);
339 return -EBADMSG;
340 }
341
342 m = journal_file_entry_array_n_items(o);
343 for (j = 0; i < n && j < m; i++, j++) {
344
345 q = le64toh(o->entry_array.items[j]);
346 if (q <= last) {
347 log_error("Data object's entry array not sorted at %llu.", (unsigned long long) p);
348 return -EBADMSG;
349 }
350 last = q;
351
352 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
353 if (r < 0)
354 return r;
355
356 /* Pointer might have moved, reposition */
357 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
358 if (r < 0)
359 return r;
360 }
361
362 a = next;
363 }
364
365 return 0;
366 }
367
368 static int verify_hash_table(
369 JournalFile *f,
370 int data_fd, uint64_t n_data,
371 int entry_fd, uint64_t n_entries,
372 int entry_array_fd, uint64_t n_entry_arrays,
373 usec_t *last_usec) {
374
375 uint64_t i, n;
376 int r;
377
378 assert(f);
379 assert(data_fd >= 0);
380 assert(entry_fd >= 0);
381 assert(entry_array_fd >= 0);
382 assert(last_usec);
383
384 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
385 for (i = 0; i < n; i++) {
386 uint64_t last = 0, p;
387
388 draw_progress(0xC000 + (0x3FFF * i / n), last_usec);
389
390 p = le64toh(f->data_hash_table[i].head_hash_offset);
391 while (p != 0) {
392 Object *o;
393 uint64_t next;
394
395 if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
396 log_error("Invalid data object at hash entry %llu of %llu.",
397 (unsigned long long) i, (unsigned long long) n);
398 return -EBADMSG;
399 }
400
401 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
402 if (r < 0)
403 return r;
404
405 next = le64toh(o->data.next_hash_offset);
406 if (next != 0 && next <= p) {
407 log_error("Hash chain has a cycle in hash entry %llu of %llu.",
408 (unsigned long long) i, (unsigned long long) n);
409 return -EBADMSG;
410 }
411
412 if (le64toh(o->data.hash) % n != i) {
413 log_error("Hash value mismatch in hash entry %llu of %llu.",
414 (unsigned long long) i, (unsigned long long) n);
415 return -EBADMSG;
416 }
417
418 r = verify_data(f, o, p, entry_fd, n_entries, entry_array_fd, n_entry_arrays);
419 if (r < 0)
420 return r;
421
422 last = p;
423 p = next;
424 }
425
426 if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) {
427 log_error("Tail hash pointer mismatch in hash table.");
428 return -EBADMSG;
429 }
430 }
431
432 return 0;
433 }
434
435 static int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) {
436 uint64_t n, h, q;
437 int r;
438 assert(f);
439
440 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
441 h = hash % n;
442
443 q = le64toh(f->data_hash_table[h].head_hash_offset);
444 while (q != 0) {
445 Object *o;
446
447 if (p == q)
448 return 1;
449
450 r = journal_file_move_to_object(f, OBJECT_DATA, q, &o);
451 if (r < 0)
452 return r;
453
454 q = le64toh(o->data.next_hash_offset);
455 }
456
457 return 0;
458 }
459
460 static int verify_entry(
461 JournalFile *f,
462 Object *o, uint64_t p,
463 int data_fd, uint64_t n_data) {
464
465 uint64_t i, n;
466 int r;
467
468 assert(f);
469 assert(o);
470 assert(data_fd >= 0);
471
472 n = journal_file_entry_n_items(o);
473 for (i = 0; i < n; i++) {
474 uint64_t q, h;
475 Object *u;
476
477 q = le64toh(o->entry.items[i].object_offset);
478 h = le64toh(o->entry.items[i].hash);
479
480 if (!contains_uint64(f->mmap, data_fd, n_data, q)) {
481 log_error("Invalid data object at entry %llu.",
482 (unsigned long long) o);
483 return -EBADMSG;
484 }
485
486 r = journal_file_move_to_object(f, OBJECT_DATA, q, &u);
487 if (r < 0)
488 return r;
489
490 if (le64toh(u->data.hash) != h) {
491 log_error("Hash mismatch for data object at entry %llu.",
492 (unsigned long long) p);
493 return -EBADMSG;
494 }
495
496 r = data_object_in_hash_table(f, h, q);
497 if (r < 0)
498 return r;
499 if (r == 0) {
500 log_error("Data object missing from hash at entry %llu.",
501 (unsigned long long) p);
502 return -EBADMSG;
503 }
504 }
505
506 return 0;
507 }
508
509 static int verify_entry_array(
510 JournalFile *f,
511 int data_fd, uint64_t n_data,
512 int entry_fd, uint64_t n_entries,
513 int entry_array_fd, uint64_t n_entry_arrays,
514 usec_t *last_usec) {
515
516 uint64_t i = 0, a, n, last = 0;
517 int r;
518
519 assert(f);
520 assert(data_fd >= 0);
521 assert(entry_fd >= 0);
522 assert(entry_array_fd >= 0);
523 assert(last_usec);
524
525 n = le64toh(f->header->n_entries);
526 a = le64toh(f->header->entry_array_offset);
527 while (i < n) {
528 uint64_t next, m, j;
529 Object *o;
530
531 draw_progress(0x8000 + (0x3FFF * i / n), last_usec);
532
533 if (a == 0) {
534 log_error("Array chain too short at %llu of %llu.",
535 (unsigned long long) i, (unsigned long long) n);
536 return -EBADMSG;
537 }
538
539 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
540 log_error("Invalid array at %llu of %llu.",
541 (unsigned long long) i, (unsigned long long) n);
542 return -EBADMSG;
543 }
544
545 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
546 if (r < 0)
547 return r;
548
549 next = le64toh(o->entry_array.next_entry_array_offset);
550 if (next != 0 && next <= a) {
551 log_error("Array chain has cycle at %llu of %llu.",
552 (unsigned long long) i, (unsigned long long) n);
553 return -EBADMSG;
554 }
555
556 m = journal_file_entry_array_n_items(o);
557 for (j = 0; i < n && j < m; i++, j++) {
558 uint64_t p;
559
560 p = le64toh(o->entry_array.items[j]);
561 if (p <= last) {
562 log_error("Entry array not sorted at %llu of %llu.",
563 (unsigned long long) i, (unsigned long long) n);
564 return -EBADMSG;
565 }
566 last = p;
567
568 if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
569 log_error("Invalid array entry at %llu of %llu.",
570 (unsigned long long) i, (unsigned long long) n);
571 return -EBADMSG;
572 }
573
574 r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
575 if (r < 0)
576 return r;
577
578 r = verify_entry(f, o, p, data_fd, n_data);
579 if (r < 0)
580 return r;
581
582 /* Pointer might have moved, reposition */
583 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
584 if (r < 0)
585 return r;
586 }
587
588 a = next;
589 }
590
591 return 0;
592 }
593
594 int journal_file_verify(JournalFile *f, const char *key) {
595 int r;
596 Object *o;
597 uint64_t p = 0;
598 uint64_t tag_seqnum = 0, entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
599 sd_id128_t entry_boot_id;
600 bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
601 uint64_t n_weird = 0, n_objects = 0, n_entries = 0, n_data = 0, n_fields = 0, n_data_hash_tables = 0, n_field_hash_tables = 0, n_entry_arrays = 0;
602 usec_t last_usec = 0;
603 int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
604 char data_path[] = "/var/tmp/journal-data-XXXXXX",
605 entry_path[] = "/var/tmp/journal-entry-XXXXXX",
606 entry_array_path[] = "/var/tmp/journal-entry-array-XXXXXX";
607
608 assert(f);
609
610 data_fd = mkostemp(data_path, O_CLOEXEC);
611 if (data_fd < 0) {
612 log_error("Failed to create data file: %m");
613 goto fail;
614 }
615 unlink(data_path);
616
617 entry_fd = mkostemp(entry_path, O_CLOEXEC);
618 if (entry_fd < 0) {
619 log_error("Failed to create entry file: %m");
620 goto fail;
621 }
622 unlink(entry_path);
623
624 entry_array_fd = mkostemp(entry_array_path, O_CLOEXEC);
625 if (entry_array_fd < 0) {
626 log_error("Failed to create entry array file: %m");
627 goto fail;
628 }
629 unlink(entry_array_path);
630
631 /* First iteration: we go through all objects, verify the
632 * superficial structure, headers, hashes. */
633
634 r = journal_file_hmac_put_header(f);
635 if (r < 0) {
636 log_error("Failed to calculate HMAC of header.");
637 goto fail;
638 }
639
640 p = le64toh(f->header->header_size);
641 while (p != 0) {
642 draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
643
644 r = journal_file_move_to_object(f, -1, p, &o);
645 if (r < 0) {
646 log_error("Invalid object at %llu", (unsigned long long) p);
647 goto fail;
648 }
649
650 if (le64toh(f->header->tail_object_offset) < p) {
651 log_error("Invalid tail object pointer.");
652 r = -EBADMSG;
653 goto fail;
654 }
655
656 n_objects ++;
657
658 r = journal_file_object_verify(f, o);
659 if (r < 0) {
660 log_error("Invalid object contents at %llu", (unsigned long long) p);
661 goto fail;
662 }
663
664 if (o->object.flags & OBJECT_COMPRESSED &&
665 !(le32toh(f->header->incompatible_flags) & HEADER_INCOMPATIBLE_COMPRESSED)) {
666 log_error("Compressed object without compression at %llu", (unsigned long long) p);
667 r = -EBADMSG;
668 goto fail;
669 }
670
671 r = journal_file_hmac_put_object(f, -1, p);
672 if (r < 0) {
673 log_error("Failed to calculate HMAC at %llu", (unsigned long long) p);
674 goto fail;
675 }
676
677 if (o->object.type == OBJECT_TAG) {
678
679 if (!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_AUTHENTICATED)) {
680 log_error("Tag object without authentication at %llu", (unsigned long long) p);
681 r = -EBADMSG;
682 goto fail;
683 }
684
685 if (le64toh(o->tag.seqnum) != tag_seqnum) {
686 log_error("Tag sequence number out of synchronization at %llu", (unsigned long long) p);
687 r = -EBADMSG;
688 goto fail;
689 }
690
691 } else if (o->object.type == OBJECT_ENTRY) {
692
693 r = write_uint64(entry_fd, p);
694 if (r < 0)
695 goto fail;
696
697 if (!entry_seqnum_set &&
698 le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
699 log_error("Head entry sequence number incorrect");
700 r = -EBADMSG;
701 goto fail;
702 }
703
704 if (entry_seqnum_set &&
705 entry_seqnum >= le64toh(o->entry.seqnum)) {
706 log_error("Entry sequence number out of synchronization at %llu", (unsigned long long) p);
707 r = -EBADMSG;
708 goto fail;
709 }
710
711 entry_seqnum = le64toh(o->entry.seqnum);
712 entry_seqnum_set = true;
713
714 if (entry_monotonic_set &&
715 sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
716 entry_monotonic > le64toh(o->entry.monotonic)) {
717 log_error("Entry timestamp out of synchronization at %llu", (unsigned long long) p);
718 r = -EBADMSG;
719 goto fail;
720 }
721
722 entry_monotonic = le64toh(o->entry.monotonic);
723 entry_boot_id = o->entry.boot_id;
724 entry_monotonic_set = true;
725
726 if (!entry_realtime_set &&
727 le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) {
728 log_error("Head entry realtime timestamp incorrect");
729 r = -EBADMSG;
730 goto fail;
731 }
732
733 entry_realtime = le64toh(o->entry.realtime);
734 entry_realtime_set = true;
735
736 n_entries ++;
737 } else if (o->object.type == OBJECT_ENTRY_ARRAY) {
738
739 r = write_uint64(entry_array_fd, p);
740 if (r < 0)
741 goto fail;
742
743 if (p == le64toh(f->header->entry_array_offset)) {
744 if (found_main_entry_array) {
745 log_error("More than one main entry array at %llu", (unsigned long long) p);
746 r = -EBADMSG;
747 goto fail;
748 }
749
750 found_main_entry_array = true;
751 }
752
753 n_entry_arrays++;
754
755 } else if (o->object.type == OBJECT_DATA) {
756
757 r = write_uint64(data_fd, p);
758 if (r < 0)
759 goto fail;
760
761 n_data++;
762
763 } else if (o->object.type == OBJECT_FIELD)
764 n_fields++;
765 else if (o->object.type == OBJECT_DATA_HASH_TABLE) {
766 n_data_hash_tables++;
767
768 if (n_data_hash_tables > 1) {
769 log_error("More than one data hash table at %llu", (unsigned long long) p);
770 r = -EBADMSG;
771 goto fail;
772 }
773
774 if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) ||
775 le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
776 log_error("Header fields for data hash table invalid.");
777 r = -EBADMSG;
778 goto fail;
779 }
780 } else if (o->object.type == OBJECT_FIELD_HASH_TABLE) {
781 n_field_hash_tables++;
782
783 if (n_field_hash_tables > 1) {
784 log_error("More than one field hash table at %llu", (unsigned long long) p);
785 r = -EBADMSG;
786 goto fail;
787 }
788
789 if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) ||
790 le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
791 log_error("Header fields for field hash table invalid.");
792 r = -EBADMSG;
793 goto fail;
794 }
795 } else if (o->object.type >= _OBJECT_TYPE_MAX)
796 n_weird ++;
797
798 if (p == le64toh(f->header->tail_object_offset))
799 p = 0;
800 else
801 p = p + ALIGN64(le64toh(o->object.size));
802 }
803
804 if (n_objects != le64toh(f->header->n_objects)) {
805 log_error("Object number mismatch");
806 r = -EBADMSG;
807 goto fail;
808 }
809
810 if (n_entries != le64toh(f->header->n_entries)) {
811 log_error("Entry number mismatch");
812 r = -EBADMSG;
813 goto fail;
814 }
815
816 if (JOURNAL_HEADER_CONTAINS(f->header, n_data) &&
817 n_data != le64toh(f->header->n_data)) {
818 log_error("Data number mismatch");
819 r = -EBADMSG;
820 goto fail;
821 }
822
823 if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) &&
824 n_fields != le64toh(f->header->n_fields)) {
825 log_error("Field number mismatch");
826 r = -EBADMSG;
827 goto fail;
828 }
829
830 if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) &&
831 tag_seqnum != le64toh(f->header->n_tags)) {
832 log_error("Tag number mismatch");
833 r = -EBADMSG;
834 goto fail;
835 }
836
837 if (n_data_hash_tables != 1) {
838 log_error("Missing data hash table");
839 r = -EBADMSG;
840 goto fail;
841 }
842
843 if (n_field_hash_tables != 1) {
844 log_error("Missing field hash table");
845 r = -EBADMSG;
846 goto fail;
847 }
848
849 if (!found_main_entry_array) {
850 log_error("Missing entry array");
851 r = -EBADMSG;
852 goto fail;
853 }
854
855 if (entry_seqnum_set &&
856 entry_seqnum != le64toh(f->header->tail_entry_seqnum)) {
857 log_error("Invalid tail seqnum");
858 r = -EBADMSG;
859 goto fail;
860 }
861
862 if (entry_monotonic_set &&
863 (!sd_id128_equal(entry_boot_id, f->header->boot_id) ||
864 entry_monotonic != le64toh(f->header->tail_entry_monotonic))) {
865 log_error("Invalid tail monotonic timestamp");
866 r = -EBADMSG;
867 goto fail;
868 }
869
870 if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) {
871 log_error("Invalid tail realtime timestamp");
872 r = -EBADMSG;
873 goto fail;
874 }
875
876 /* Second iteration: we follow all objects referenced from the
877 * two entry points: the object hash table and the entry
878 * array. We also check that everything referenced (directly
879 * or indirectly) in the data hash table also exists in the
880 * entry array, and vice versa. Note that we do not care for
881 * unreferenced objects. We only care that everything that is
882 * referenced is consistent. */
883
884 r = verify_entry_array(f,
885 data_fd, n_data,
886 entry_fd, n_entries,
887 entry_array_fd, n_entry_arrays,
888 &last_usec);
889 if (r < 0)
890 goto fail;
891
892 r = verify_hash_table(f,
893 data_fd, n_data,
894 entry_fd, n_entries,
895 entry_array_fd, n_entry_arrays,
896 &last_usec);
897 if (r < 0)
898 goto fail;
899
900 flush_progress();
901
902 mmap_cache_close_fd(f->mmap, data_fd);
903 mmap_cache_close_fd(f->mmap, entry_fd);
904 mmap_cache_close_fd(f->mmap, entry_array_fd);
905
906 close_nointr_nofail(data_fd);
907 close_nointr_nofail(entry_fd);
908 close_nointr_nofail(entry_array_fd);
909
910 return 0;
911
912 fail:
913 flush_progress();
914
915 log_error("File corruption detected at %s:%llu (of %llu, %llu%%).",
916 f->path,
917 (unsigned long long) p,
918 (unsigned long long) f->last_stat.st_size,
919 (unsigned long long) (100 * p / f->last_stat.st_size));
920
921 if (data_fd >= 0) {
922 mmap_cache_close_fd(f->mmap, data_fd);
923 close_nointr_nofail(data_fd);
924 }
925
926 if (entry_fd >= 0) {
927 mmap_cache_close_fd(f->mmap, entry_fd);
928 close_nointr_nofail(entry_fd);
929 }
930
931 if (entry_array_fd >= 0) {
932 mmap_cache_close_fd(f->mmap, entry_array_fd);
933 close_nointr_nofail(entry_array_fd);
934 }
935
936 return r;
937 }