1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
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.
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.
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/>.
29 #include "journal-def.h"
30 #include "journal-file.h"
31 #include "journal-authenticate.h"
32 #include "journal-verify.h"
37 static int journal_file_object_verify(JournalFile *f, Object *o) {
43 /* This does various superficial tests about the length an
44 * possible field values. It does not follow any references to
47 if ((o->object.flags & OBJECT_COMPRESSED) &&
48 o->object.type != OBJECT_DATA)
51 switch (o->object.type) {
56 if (le64toh(o->data.entry_offset) <= 0 ||
57 le64toh(o->data.n_entries) <= 0)
60 if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0)
63 h1 = le64toh(o->data.hash);
65 if (o->object.flags & OBJECT_COMPRESSED) {
67 uint64_t alloc = 0, b_size;
69 if (!uncompress_blob(o->data.payload,
70 le64toh(o->object.size) - offsetof(Object, data.payload),
74 h2 = hash64(b, b_size);
77 h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
82 if (!VALID64(o->data.next_hash_offset) ||
83 !VALID64(o->data.next_field_offset) ||
84 !VALID64(o->data.entry_offset) ||
85 !VALID64(o->data.entry_array_offset))
92 if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0)
95 if (!VALID64(o->field.next_hash_offset) ||
96 !VALID64(o->field.head_data_offset))
101 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0)
104 if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0)
107 if (le64toh(o->entry.seqnum) <= 0 ||
108 !VALID_REALTIME(le64toh(o->entry.realtime)) ||
109 !VALID_MONOTONIC(le64toh(o->entry.monotonic)))
112 for (i = 0; i < journal_file_entry_n_items(o); i++) {
113 if (o->entry.items[i].object_offset == 0 ||
114 !VALID64(o->entry.items[i].object_offset))
120 case OBJECT_DATA_HASH_TABLE:
121 case OBJECT_FIELD_HASH_TABLE:
122 if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0)
125 if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0)
128 for (i = 0; i < journal_file_hash_table_n_items(o); i++) {
129 if (o->hash_table.items[i].head_hash_offset != 0 &&
130 !VALID64(le64toh(o->hash_table.items[i].head_hash_offset)))
132 if (o->hash_table.items[i].tail_hash_offset != 0 &&
133 !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset)))
136 if ((o->hash_table.items[i].head_hash_offset != 0) !=
137 (o->hash_table.items[i].tail_hash_offset != 0))
143 case OBJECT_ENTRY_ARRAY:
144 if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0)
147 if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0)
150 if (!VALID64(o->entry_array.next_entry_array_offset))
153 for (i = 0; i < journal_file_entry_array_n_items(o); i++)
154 if (o->entry_array.items[i] != 0 &&
155 !VALID64(o->entry_array.items[i]))
161 if (le64toh(o->object.size) != sizeof(TagObject))
164 if (!VALID_EPOCH(o->tag.epoch))
173 static void draw_progress(uint64_t p, usec_t *last_usec) {
177 if (!isatty(STDOUT_FILENO))
180 z = now(CLOCK_MONOTONIC);
183 if (x != 0 && x + 40 * USEC_PER_MSEC > z)
188 n = (3 * columns()) / 4;
189 j = (n * (unsigned) p) / 65535ULL;
192 fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN_ON, stdout);
194 for (i = 0; i < j; i++)
195 fputs("\xe2\x96\x88", stdout);
197 fputs(ANSI_HIGHLIGHT_OFF, stdout);
199 for (i = 0; i < k; i++)
200 fputs("\xe2\x96\x91", stdout);
202 printf(" %3lu%%", 100LU * (unsigned long) p / 65535LU);
204 fputs("\r\x1B[?25h", stdout);
208 static void flush_progress(void) {
211 if (!isatty(STDOUT_FILENO))
214 n = (3 * columns()) / 4;
218 for (i = 0; i < n + 5; i++)
225 static int write_uint64(int fd, uint64_t p) {
228 k = write(fd, &p, sizeof(p));
237 static int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
252 r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, c * sizeof(uint64_t), sizeof(uint64_t), (void **) &z);
272 static int entry_points_to_data(
285 assert(entry_fd >= 0);
287 if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
288 log_error("Data object references invalid entry at %llu", (unsigned long long) data_p);
292 r = journal_file_move_to_object(f, OBJECT_ENTRY, entry_p, &o);
296 n = journal_file_entry_n_items(o);
297 for (i = 0; i < n; i++)
298 if (le64toh(o->entry.items[i].object_offset) == data_p) {
304 log_error("Data object not referenced by linked entry at %llu", (unsigned long long) data_p);
308 /* Check if this entry is also in main entry array. Since the
309 * main entry array has already been verified we can rely on
313 n = le64toh(f->header->n_entries);
314 a = le64toh(f->header->entry_array_offset);
319 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
323 m = journal_file_entry_array_n_items(o);
326 if (entry_p <= le64toh(o->entry_array.items[u-1])) {
335 if (le64toh(o->entry_array.items[z]) == entry_p)
341 if (entry_p < le64toh(o->entry_array.items[z]))
347 log_error("Entry object doesn't exist in main entry array at %llu", (unsigned long long) entry_p);
352 a = le64toh(o->entry_array.next_entry_array_offset);
358 static int verify_data(
360 Object *o, uint64_t p,
361 int entry_fd, uint64_t n_entries,
362 int entry_array_fd, uint64_t n_entry_arrays) {
364 uint64_t i, n, a, last, q;
369 assert(entry_fd >= 0);
370 assert(entry_array_fd >= 0);
372 n = le64toh(o->data.n_entries);
373 a = le64toh(o->data.entry_array_offset);
375 /* We already checked this earlier */
378 last = q = le64toh(o->data.entry_offset);
379 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
388 log_error("Array chain too short at %llu", (unsigned long long) p);
392 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
393 log_error("Invalid array at %llu", (unsigned long long) p);
397 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
401 next = le64toh(o->entry_array.next_entry_array_offset);
402 if (next != 0 && next <= a) {
403 log_error("Array chain has cycle at %llu", (unsigned long long) p);
407 m = journal_file_entry_array_n_items(o);
408 for (j = 0; i < n && j < m; i++, j++) {
410 q = le64toh(o->entry_array.items[j]);
412 log_error("Data object's entry array not sorted at %llu", (unsigned long long) p);
417 r = entry_points_to_data(f, entry_fd, n_entries, q, p);
421 /* Pointer might have moved, reposition */
422 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
433 static int verify_hash_table(
435 int data_fd, uint64_t n_data,
436 int entry_fd, uint64_t n_entries,
437 int entry_array_fd, uint64_t n_entry_arrays,
439 bool show_progress) {
445 assert(data_fd >= 0);
446 assert(entry_fd >= 0);
447 assert(entry_array_fd >= 0);
450 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
451 for (i = 0; i < n; i++) {
452 uint64_t last = 0, p;
455 draw_progress(0xC000 + (0x3FFF * i / n), last_usec);
457 p = le64toh(f->data_hash_table[i].head_hash_offset);
462 if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
463 log_error("Invalid data object at hash entry %llu of %llu",
464 (unsigned long long) i, (unsigned long long) n);
468 r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
472 next = le64toh(o->data.next_hash_offset);
473 if (next != 0 && next <= p) {
474 log_error("Hash chain has a cycle in hash entry %llu of %llu",
475 (unsigned long long) i, (unsigned long long) n);
479 if (le64toh(o->data.hash) % n != i) {
480 log_error("Hash value mismatch in hash entry %llu of %llu",
481 (unsigned long long) i, (unsigned long long) n);
485 r = verify_data(f, o, p, entry_fd, n_entries, entry_array_fd, n_entry_arrays);
493 if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) {
494 log_error("Tail hash pointer mismatch in hash table");
502 static int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) {
507 n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
510 q = le64toh(f->data_hash_table[h].head_hash_offset);
517 r = journal_file_move_to_object(f, OBJECT_DATA, q, &o);
521 q = le64toh(o->data.next_hash_offset);
527 static int verify_entry(
529 Object *o, uint64_t p,
530 int data_fd, uint64_t n_data) {
537 assert(data_fd >= 0);
539 n = journal_file_entry_n_items(o);
540 for (i = 0; i < n; i++) {
544 q = le64toh(o->entry.items[i].object_offset);
545 h = le64toh(o->entry.items[i].hash);
547 if (!contains_uint64(f->mmap, data_fd, n_data, q)) {
548 log_error("Invalid data object at entry %llu",
549 (unsigned long long) p);
553 r = journal_file_move_to_object(f, OBJECT_DATA, q, &u);
557 if (le64toh(u->data.hash) != h) {
558 log_error("Hash mismatch for data object at entry %llu",
559 (unsigned long long) p);
563 r = data_object_in_hash_table(f, h, q);
567 log_error("Data object missing from hash at entry %llu",
568 (unsigned long long) p);
576 static int verify_entry_array(
578 int data_fd, uint64_t n_data,
579 int entry_fd, uint64_t n_entries,
580 int entry_array_fd, uint64_t n_entry_arrays,
582 bool show_progress) {
584 uint64_t i = 0, a, n, last = 0;
588 assert(data_fd >= 0);
589 assert(entry_fd >= 0);
590 assert(entry_array_fd >= 0);
593 n = le64toh(f->header->n_entries);
594 a = le64toh(f->header->entry_array_offset);
600 draw_progress(0x8000 + (0x3FFF * i / n), last_usec);
603 log_error("Array chain too short at %llu of %llu",
604 (unsigned long long) i, (unsigned long long) n);
608 if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
609 log_error("Invalid array at %llu of %llu",
610 (unsigned long long) i, (unsigned long long) n);
614 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
618 next = le64toh(o->entry_array.next_entry_array_offset);
619 if (next != 0 && next <= a) {
620 log_error("Array chain has cycle at %llu of %llu",
621 (unsigned long long) i, (unsigned long long) n);
625 m = journal_file_entry_array_n_items(o);
626 for (j = 0; i < n && j < m; i++, j++) {
629 p = le64toh(o->entry_array.items[j]);
631 log_error("Entry array not sorted at %llu of %llu",
632 (unsigned long long) i, (unsigned long long) n);
637 if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
638 log_error("Invalid array entry at %llu of %llu",
639 (unsigned long long) i, (unsigned long long) n);
643 r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
647 r = verify_entry(f, o, p, data_fd, n_data);
651 /* Pointer might have moved, reposition */
652 r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
663 int journal_file_verify(
666 usec_t *first_validated, usec_t *last_validated, usec_t *last_contained,
667 bool show_progress) {
670 uint64_t p = 0, last_tag = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0;
671 uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
672 sd_id128_t entry_boot_id;
673 bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
674 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, n_tags = 0;
675 usec_t last_usec = 0;
676 int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
677 char data_path[] = "/var/tmp/journal-data-XXXXXX",
678 entry_path[] = "/var/tmp/journal-entry-XXXXXX",
679 entry_array_path[] = "/var/tmp/journal-entry-array-XXXXXX";
687 r = journal_file_parse_verification_key(f, key);
689 log_error("Failed to parse seed.");
698 data_fd = mkostemp(data_path, O_CLOEXEC);
700 log_error("Failed to create data file: %m");
706 entry_fd = mkostemp(entry_path, O_CLOEXEC);
708 log_error("Failed to create entry file: %m");
714 entry_array_fd = mkostemp(entry_array_path, O_CLOEXEC);
715 if (entry_array_fd < 0) {
716 log_error("Failed to create entry array file: %m");
720 unlink(entry_array_path);
723 if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) != 0)
725 if (f->header->compatible_flags != 0)
728 log_error("Cannot verify file with unknown extensions.");
733 for (i = 0; i < sizeof(f->header->reserved); i++)
734 if (f->header->reserved[i] != 0) {
735 log_error("Reserved field in non-zero.");
740 /* First iteration: we go through all objects, verify the
741 * superficial structure, headers, hashes. */
743 p = le64toh(f->header->header_size);
746 draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
748 r = journal_file_move_to_object(f, -1, p, &o);
750 log_error("Invalid object at %llu", (unsigned long long) p);
754 if (p > le64toh(f->header->tail_object_offset)) {
755 log_error("Invalid tail object pointer");
760 if (p == le64toh(f->header->tail_object_offset))
765 r = journal_file_object_verify(f, o);
767 log_error("Invalid object contents at %llu", (unsigned long long) p);
771 if ((o->object.flags & OBJECT_COMPRESSED) && !JOURNAL_HEADER_COMPRESSED(f->header)) {
772 log_error("Compressed object in file without compression at %llu", (unsigned long long) p);
777 switch (o->object.type) {
780 r = write_uint64(data_fd, p);
792 if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) {
793 log_error("First entry before first tag at %llu", (unsigned long long) p);
798 r = write_uint64(entry_fd, p);
802 if (le64toh(o->entry.realtime) < last_tag_realtime) {
803 log_error("Older entry after newer tag at %llu", (unsigned long long) p);
808 if (!entry_seqnum_set &&
809 le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
810 log_error("Head entry sequence number incorrect at %llu", (unsigned long long) p);
815 if (entry_seqnum_set &&
816 entry_seqnum >= le64toh(o->entry.seqnum)) {
817 log_error("Entry sequence number out of synchronization at %llu", (unsigned long long) p);
822 entry_seqnum = le64toh(o->entry.seqnum);
823 entry_seqnum_set = true;
825 if (entry_monotonic_set &&
826 sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
827 entry_monotonic > le64toh(o->entry.monotonic)) {
828 log_error("Entry timestamp out of synchronization at %llu", (unsigned long long) p);
833 entry_monotonic = le64toh(o->entry.monotonic);
834 entry_boot_id = o->entry.boot_id;
835 entry_monotonic_set = true;
837 if (!entry_realtime_set &&
838 le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) {
839 log_error("Head entry realtime timestamp incorrect");
844 entry_realtime = le64toh(o->entry.realtime);
845 entry_realtime_set = true;
850 case OBJECT_DATA_HASH_TABLE:
851 if (n_data_hash_tables > 1) {
852 log_error("More than one data hash table at %llu", (unsigned long long) p);
857 if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) ||
858 le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
859 log_error("Header fields for data hash table invalid");
864 n_data_hash_tables++;
867 case OBJECT_FIELD_HASH_TABLE:
868 if (n_field_hash_tables > 1) {
869 log_error("More than one field hash table at %llu", (unsigned long long) p);
874 if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) ||
875 le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
876 log_error("Header fields for field hash table invalid");
881 n_field_hash_tables++;
884 case OBJECT_ENTRY_ARRAY:
885 r = write_uint64(entry_array_fd, p);
889 if (p == le64toh(f->header->entry_array_offset)) {
890 if (found_main_entry_array) {
891 log_error("More than one main entry array at %llu", (unsigned long long) p);
896 found_main_entry_array = true;
903 if (!JOURNAL_HEADER_SEALED(f->header)) {
904 log_error("Tag object in file without sealing at %llu", (unsigned long long) p);
909 if (le64toh(o->tag.seqnum) != n_tags + 1) {
910 log_error("Tag sequence number out of synchronization at %llu", (unsigned long long) p);
915 if (le64toh(o->tag.epoch) < last_epoch) {
916 log_error("Epoch sequence out of synchronization at %llu", (unsigned long long) p);
925 log_debug("Checking tag %llu..", (unsigned long long) le64toh(o->tag.seqnum));
927 rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec;
928 if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
929 log_error("Tag/entry realtime timestamp out of synchronization at %llu", (unsigned long long) p);
934 /* OK, now we know the epoch. So let's now set
935 * it, and calculate the HMAC for everything
936 * since the last tag. */
937 r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
941 r = journal_file_hmac_start(f);
946 r = journal_file_hmac_put_header(f);
950 q = le64toh(f->header->header_size);
955 r = journal_file_move_to_object(f, -1, q, &o);
959 r = journal_file_hmac_put_object(f, -1, q);
963 q = q + ALIGN64(le64toh(o->object.size));
966 /* Position might have changed, let's reposition things */
967 r = journal_file_move_to_object(f, -1, p, &o);
971 if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
972 log_error("Tag failed verification at %llu", (unsigned long long) p);
977 f->hmac_running = false;
978 last_tag_realtime = rt;
979 last_sealed_realtime = entry_realtime;
983 last_tag = p + ALIGN64(le64toh(o->object.size));
984 last_epoch = le64toh(o->tag.epoch);
993 if (p == le64toh(f->header->tail_object_offset))
996 p = p + ALIGN64(le64toh(o->object.size));
1000 log_error("Tail object pointer dead");
1005 if (n_objects != le64toh(f->header->n_objects)) {
1006 log_error("Object number mismatch");
1011 if (n_entries != le64toh(f->header->n_entries)) {
1012 log_error("Entry number mismatch");
1017 if (JOURNAL_HEADER_CONTAINS(f->header, n_data) &&
1018 n_data != le64toh(f->header->n_data)) {
1019 log_error("Data number mismatch");
1024 if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) &&
1025 n_fields != le64toh(f->header->n_fields)) {
1026 log_error("Field number mismatch");
1031 if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) &&
1032 n_tags != le64toh(f->header->n_tags)) {
1033 log_error("Tag number mismatch");
1038 if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) &&
1039 n_entry_arrays != le64toh(f->header->n_entry_arrays)) {
1040 log_error("Entry array number mismatch");
1045 if (n_data_hash_tables != 1) {
1046 log_error("Missing data hash table");
1051 if (n_field_hash_tables != 1) {
1052 log_error("Missing field hash table");
1057 if (!found_main_entry_array) {
1058 log_error("Missing entry array");
1063 if (entry_seqnum_set &&
1064 entry_seqnum != le64toh(f->header->tail_entry_seqnum)) {
1065 log_error("Invalid tail seqnum");
1070 if (entry_monotonic_set &&
1071 (!sd_id128_equal(entry_boot_id, f->header->boot_id) ||
1072 entry_monotonic != le64toh(f->header->tail_entry_monotonic))) {
1073 log_error("Invalid tail monotonic timestamp");
1078 if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) {
1079 log_error("Invalid tail realtime timestamp");
1084 /* Second iteration: we follow all objects referenced from the
1085 * two entry points: the object hash table and the entry
1086 * array. We also check that everything referenced (directly
1087 * or indirectly) in the data hash table also exists in the
1088 * entry array, and vice versa. Note that we do not care for
1089 * unreferenced objects. We only care that everything that is
1090 * referenced is consistent. */
1092 r = verify_entry_array(f,
1094 entry_fd, n_entries,
1095 entry_array_fd, n_entry_arrays,
1101 r = verify_hash_table(f,
1103 entry_fd, n_entries,
1104 entry_array_fd, n_entry_arrays,
1113 mmap_cache_close_fd(f->mmap, data_fd);
1114 mmap_cache_close_fd(f->mmap, entry_fd);
1115 mmap_cache_close_fd(f->mmap, entry_array_fd);
1117 close_nointr_nofail(data_fd);
1118 close_nointr_nofail(entry_fd);
1119 close_nointr_nofail(entry_array_fd);
1121 if (first_validated)
1122 *first_validated = last_tag_realtime ? le64toh(f->header->head_entry_realtime) : 0;
1124 *last_validated = last_sealed_realtime;
1126 *last_contained = le64toh(f->header->tail_entry_realtime);
1134 log_error("File corruption detected at %s:%llu (of %llu, %llu%%).",
1136 (unsigned long long) p,
1137 (unsigned long long) f->last_stat.st_size,
1138 (unsigned long long) (100 * p / f->last_stat.st_size));
1141 mmap_cache_close_fd(f->mmap, data_fd);
1142 close_nointr_nofail(data_fd);
1145 if (entry_fd >= 0) {
1146 mmap_cache_close_fd(f->mmap, entry_fd);
1147 close_nointr_nofail(entry_fd);
1150 if (entry_array_fd >= 0) {
1151 mmap_cache_close_fd(f->mmap, entry_array_fd);
1152 close_nointr_nofail(entry_array_fd);