journal-verify.c revision 369f0589218a874a88bc69c5481d8f90f987b7dd
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering This file is part of systemd.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2012 Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (at your option) any later version.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is distributed in the hope that it will be useful, but
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Lesser General Public License for more details.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
4cee5eede280b7fd48c18a1942616c4ac896a554Lennart Poetteringstatic int journal_file_object_verify(JournalFile *f, Object *o) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering /* This does various superficial tests about the length an
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering * possible field values. It does not follow any references to
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering * other objects. */
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if ((o->object.flags & OBJECT_COMPRESSED) &&
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (le64toh(o->data.entry_offset) <= 0 ||
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (o->object.flags & OBJECT_COMPRESSED) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering le64toh(o->object.size) - offsetof(Object, data.payload),
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload));
cb81cd8073392936882643af0129934bf67e96c4Lennart Poettering if (!VALID64(o->data.next_hash_offset) ||
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (!VALID64(o->field.next_hash_offset) ||
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering !VALID_REALTIME(le64toh(o->entry.realtime)) ||
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering !VALID_MONOTONIC(le64toh(o->entry.monotonic)))
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering for (i = 0; i < journal_file_entry_n_items(o); i++) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (o->entry.items[i].object_offset == 0 ||
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering !VALID64(o->entry.items[i].object_offset))
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering for (i = 0; i < journal_file_hash_table_n_items(o); i++) {
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering if (o->hash_table.items[i].head_hash_offset != 0 &&
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering !VALID64(le64toh(o->hash_table.items[i].head_hash_offset)))
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (o->hash_table.items[i].tail_hash_offset != 0 &&
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset)))
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if ((o->hash_table.items[i].head_hash_offset != 0) !=
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering (o->hash_table.items[i].tail_hash_offset != 0))
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (!VALID64(o->entry_array.next_entry_array_offset))
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering for (i = 0; i < journal_file_entry_array_n_items(o); i++)
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering if (le64toh(o->object.size) != sizeof(TagObject))
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poetteringstatic void draw_progress(uint64_t p, usec_t *last_usec) {
c2ce6a3d82b717c4c1e6245ad8c6ce1173f502d0Lennart Poettering unsigned n, i, j, k;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (x != 0 && x + 40 * USEC_PER_MSEC > z)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering j = (n * (unsigned) p) / 65535ULL;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN_ON, stdout);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering for (i = 0; i < j; i++)
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering for (i = 0; i < k; i++)
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering printf(" %3lu%%", 100LU * (unsigned long) p / 65535LU);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic void flush_progress(void) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering unsigned n, i;
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poettering for (i = 0; i < n + 5; i++)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poetteringstatic int write_uint64(int fd, uint64_t p) {
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poettering if (k != sizeof(p))
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poetteringstatic int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering /* Bisection ... */
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering while (a < b) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering c = (a + b) / 2;
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, c * sizeof(uint64_t), sizeof(uint64_t), (void **) &z);
9030ca462bd13cd6536299814e4a71d5c5e85be9Lennart Poettering if (a + 1 >= b)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Data object references invalid entry at %llu", (unsigned long long) data_p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY, entry_p, &o);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering for (i = 0; i < n; i++)
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering if (le64toh(o->entry.items[i].object_offset) == data_p) {
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering log_error("Data object not referenced by linked entry at %llu", (unsigned long long) data_p);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering /* Check if this entry is also in main entry array. Since the
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering * main entry array has already been verified we can rely on
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering * its consistency.*/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering a = le64toh(f->header->entry_array_offset);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering while (i < n) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering u = MIN(n - i, m);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (entry_p <= le64toh(o->entry_array.items[u-1])) {
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering while (x < y) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering z = (x + y) / 2;
5b12334d35eadf1f45cc3d631fd1a2e72ffaea0aLennart Poettering if (le64toh(o->entry_array.items[z]) == entry_p)
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (x + 1 >= y)
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering if (entry_p < le64toh(o->entry_array.items[z]))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Entry object doesn't exist in main entry array at %llu", (unsigned long long) entry_p);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering a = le64toh(o->entry_array.next_entry_array_offset);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering int entry_array_fd, uint64_t n_entry_arrays) {
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering /* We already checked this earlier */
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering last = q = le64toh(o->data.entry_offset);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering r = entry_points_to_data(f, entry_fd, n_entries, q, p);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering while (i < n) {
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering log_error("Array chain too short at %llu", (unsigned long long) p);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering log_error("Invalid array at %llu", (unsigned long long) p);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering next = le64toh(o->entry_array.next_entry_array_offset);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering log_error("Array chain has cycle at %llu", (unsigned long long) p);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering for (j = 0; i < n && j < m; i++, j++) {
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering log_error("Data object's entry array not sorted at %llu", (unsigned long long) p);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering r = entry_points_to_data(f, entry_fd, n_entries, q, p);
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering /* Pointer might have moved, reposition */
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering int entry_array_fd, uint64_t n_entry_arrays,
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering for (i = 0; i < n; i++) {
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering draw_progress(0xC000 + (0x3FFF * i / n), last_usec);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering p = le64toh(f->data_hash_table[i].head_hash_offset);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering while (p != 0) {
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering log_error("Invalid data object at hash entry %llu of %llu",
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering (unsigned long long) i, (unsigned long long) n);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = journal_file_move_to_object(f, OBJECT_DATA, p, &o);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering next = le64toh(o->data.next_hash_offset);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Hash chain has a cycle in hash entry %llu of %llu",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (unsigned long long) i, (unsigned long long) n);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_error("Hash value mismatch in hash entry %llu of %llu",
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering (unsigned long long) i, (unsigned long long) n);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering r = verify_data(f, o, p, entry_fd, n_entries, entry_array_fd, n_entry_arrays);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering log_error("Tail hash pointer mismatch in hash table");
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poetteringstatic int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) {
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering q = le64toh(f->data_hash_table[h].head_hash_offset);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering while (q != 0) {
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering r = journal_file_move_to_object(f, OBJECT_DATA, q, &o);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering for (i = 0; i < n; i++) {
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering q = le64toh(o->entry.items[i].object_offset);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering if (!contains_uint64(f->mmap, data_fd, n_data, q)) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering log_error("Invalid data object at entry %llu",
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering (unsigned long long) p);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering r = journal_file_move_to_object(f, OBJECT_DATA, q, &u);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering log_error("Hash mismatch for data object at entry %llu",
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering (unsigned long long) p);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering log_error("Data object missing from hash at entry %llu",
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering (unsigned long long) p);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering int entry_array_fd, uint64_t n_entry_arrays,
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering a = le64toh(f->header->entry_array_offset);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering while (i < n) {
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering draw_progress(0x8000 + (0x3FFF * i / n), last_usec);
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering log_error("Array chain too short at %llu of %llu",
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering (unsigned long long) i, (unsigned long long) n);
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering log_error("Invalid array at %llu of %llu",
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering (unsigned long long) i, (unsigned long long) n);
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering next = le64toh(o->entry_array.next_entry_array_offset);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering log_error("Array chain has cycle at %llu of %llu",
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering (unsigned long long) i, (unsigned long long) n);
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering for (j = 0; i < n && j < m; i++, j++) {
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering log_error("Entry array not sorted at %llu of %llu",
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering (unsigned long long) i, (unsigned long long) n);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering log_error("Invalid array entry at %llu of %llu",
5f8cc96a0301c1177b11dd2e89370ef0b2ef577bLennart Poettering (unsigned long long) i, (unsigned long long) n);
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY, p, &o);
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering r = verify_entry(f, o, p, data_fd, n_data);
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering /* Pointer might have moved, reposition */
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &o);
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering usec_t *first_validated, usec_t *last_validated, usec_t *last_contained,
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering uint64_t p = 0, last_tag = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0;
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering 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;
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering char data_path[] = "/var/tmp/journal-data-XXXXXX",
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering entry_path[] = "/var/tmp/journal-entry-XXXXXX",
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering entry_array_path[] = "/var/tmp/journal-entry-array-XXXXXX";
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering r = journal_file_parse_verification_key(f, key);
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering } else if (f->seal)
086821244b5113f00a0ef993b78dc56aae2a8f6cLennart Poettering data_fd = mkostemp(data_path, O_CLOEXEC);
70244d1d25eb80b57e160ea004d0e6bf793d4cafLennart Poettering log_error("Failed to create data file: %m");
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering entry_fd = mkostemp(entry_path, O_CLOEXEC);
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering log_error("Failed to create entry file: %m");
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering entry_array_fd = mkostemp(entry_array_path, O_CLOEXEC);
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering log_error("Failed to create entry array file: %m");
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) != 0)
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering log_error("Cannot verify file with unknown extensions.");
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering for (i = 0; i < sizeof(f->header->reserved); i++)
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering log_error("Reserved field in non-zero.");
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering /* First iteration: we go through all objects, verify the
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering * superficial structure, headers, hashes. */
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering while (p != 0) {
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
70244d1d25eb80b57e160ea004d0e6bf793d4cafLennart Poettering r = journal_file_move_to_object(f, -1, p, &o);
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering log_error("Invalid object at %llu", (unsigned long long) p);
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering if (p > le64toh(f->header->tail_object_offset)) {
1ddb263d21099ae42195c2bc382bdf72a7f24f82Lennart Poettering log_error("Invalid tail object pointer");
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering if (p == le64toh(f->header->tail_object_offset))
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering log_error("Invalid object contents at %llu", (unsigned long long) p);
ebd93cb684806ac0f352139e69ac8f53eb49f5e4Lennart Poettering if ((o->object.flags & OBJECT_COMPRESSED) && !JOURNAL_HEADER_COMPRESSED(f->header)) {
70244d1d25eb80b57e160ea004d0e6bf793d4cafLennart Poettering log_error("Compressed object in file without compression at %llu", (unsigned long long) p);
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) {
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering log_error("First entry before first tag at %llu", (unsigned long long) p);
4cee5eede280b7fd48c18a1942616c4ac896a554Lennart Poettering if (le64toh(o->entry.realtime) < last_tag_realtime) {
4cee5eede280b7fd48c18a1942616c4ac896a554Lennart Poettering log_error("Older entry after newer tag at %llu", (unsigned long long) p);
efe0286285a7432f738fafae840fa4eda51c2986Lennart Poettering le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) {
efe0286285a7432f738fafae840fa4eda51c2986Lennart Poettering log_error("Head entry sequence number incorrect at %llu", (unsigned long long) p);
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering entry_seqnum >= le64toh(o->entry.seqnum)) {
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering log_error("Entry sequence number out of synchronization at %llu", (unsigned long long) p);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering sd_id128_equal(entry_boot_id, o->entry.boot_id) &&
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering entry_monotonic > le64toh(o->entry.monotonic)) {
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering log_error("Entry timestamp out of synchronization at %llu", (unsigned long long) p);
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering entry_monotonic = le64toh(o->entry.monotonic);
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) {
d6ce17c7f02ed3facdb45f65f546e587c2f00950Lennart Poettering log_error("Head entry realtime timestamp incorrect");
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering entry_realtime = le64toh(o->entry.realtime);
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering log_error("More than one data hash table at %llu", (unsigned long long) p);
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering if (le64toh(f->header->data_hash_table_offset) != p + offsetof(HashTableObject, items) ||
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering le64toh(f->header->data_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering log_error("Header fields for data hash table invalid");
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering log_error("More than one field hash table at %llu", (unsigned long long) p);
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) ||
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) {
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering log_error("Header fields for field hash table invalid");
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering if (p == le64toh(f->header->entry_array_offset)) {
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering log_error("More than one main entry array at %llu", (unsigned long long) p);
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering log_error("Tag object in file without sealing at %llu", (unsigned long long) p);
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering if (le64toh(o->tag.seqnum) != n_tags + 1) {
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering log_error("Tag sequence number out of synchronization at %llu", (unsigned long long) p);
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering if (le64toh(o->tag.epoch) < last_epoch) {
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering log_error("Epoch sequence out of synchronization at %llu", (unsigned long long) p);
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering log_debug("Checking tag %llu..", (unsigned long long) le64toh(o->tag.seqnum));
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec;
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering log_error("Tag/entry realtime timestamp out of synchronization at %llu", (unsigned long long) p);
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering /* OK, now we know the epoch. So let's now set
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering * it, and calculate the HMAC for everything
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering * since the last tag. */
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering while (q <= p) {
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering r = journal_file_move_to_object(f, -1, q, &o);
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering r = journal_file_hmac_put_object(f, -1, q);
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering q = q + ALIGN64(le64toh(o->object.size));
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering /* Position might have changed, let's reposition things */
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering r = journal_file_move_to_object(f, -1, p, &o);
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering log_error("Tag failed verification at %llu", (unsigned long long) p);
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering last_tag = p + ALIGN64(le64toh(o->object.size));
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering if (p == le64toh(f->header->tail_object_offset))
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering p = p + ALIGN64(le64toh(o->object.size));
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering if (n_objects != le64toh(f->header->n_objects)) {
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering if (n_entries != le64toh(f->header->n_entries)) {
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering if (JOURNAL_HEADER_CONTAINS(f->header, n_data) &&
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) &&
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering n_fields != le64toh(f->header->n_fields)) {
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) &&
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) &&
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering n_entry_arrays != le64toh(f->header->n_entry_arrays)) {
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering log_error("Entry array number mismatch");
c01ff965b48bb9693dcd77cbc748b5d8676766b0Lennart Poettering entry_seqnum != le64toh(f->header->tail_entry_seqnum)) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering (!sd_id128_equal(entry_boot_id, f->header->boot_id) ||
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering entry_monotonic != le64toh(f->header->tail_entry_monotonic))) {
adacb9575a09981fcf11279f2f661e3fc21e58ffLennart Poettering log_error("Invalid tail monotonic timestamp");
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) {
9b5ed6feda08290edce3bf916fa7362733dd30eaLennart Poettering log_error("Invalid tail realtime timestamp");
3a6fb33c54bc64398e0af1c9d7c74a6b614a849dLennart Poettering /* Second iteration: we follow all objects referenced from the
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering * two entry points: the object hash table and the entry
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering * array. We also check that everything referenced (directly
d04c1fb8e215600b4950c6778c6c16ddafc14024Lennart Poettering * or indirectly) in the data hash table also exists in the
70244d1d25eb80b57e160ea004d0e6bf793d4cafLennart Poettering * entry array, and vice versa. Note that we do not care for
70244d1d25eb80b57e160ea004d0e6bf793d4cafLennart Poettering * unreferenced objects. We only care that everything that is
70244d1d25eb80b57e160ea004d0e6bf793d4cafLennart Poettering * referenced is consistent. */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering mmap_cache_close_fd(f->mmap, entry_array_fd);
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering *first_validated = last_tag_realtime ? le64toh(f->header->head_entry_realtime) : 0;
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering *last_contained = le64toh(f->header->tail_entry_realtime);
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering log_error("File corruption detected at %s:%llu (of %llu, %llu%%).",
6797c324a653f119a3d7133122648aaa4878ddd6Lennart Poettering (unsigned long long) p,
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering (unsigned long long) f->last_stat.st_size,
c335068380fe8c9d843cdb2cf8a00f822cfabed3Lennart Poettering (unsigned long long) (100 * p / f->last_stat.st_size));