]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/journal/journal-verify.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / journal / journal-verify.c
index b78ce98b1754e506aaf44a8dc18ada14dd3fc9b0..dc6b21b1e9bac4b6f01fe35d1a5f780223e1f5d2 100644 (file)
@@ -1,5 +1,4 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
+/* SPDX-License-Identifier: LGPL-2.1+ */
 /***
   This file is part of systemd.
 
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <unistd.h>
-#include <sys/mman.h>
 #include <fcntl.h>
 #include <stddef.h>
+#include <sys/mman.h>
+#include <unistd.h>
 
 #include "alloc-util.h"
 #include "compress.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "fs-util.h"
 #include "journal-authenticate.h"
 #include "journal-def.h"
 #include "journal-file.h"
@@ -56,7 +56,9 @@ static void draw_progress(uint64_t p, usec_t *last_usec) {
         j = (n * (unsigned) p) / 65535ULL;
         k = n - j;
 
-        fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN, stdout);
+        fputs("\r", stdout);
+        if (colors_enabled())
+                fputs("\x1B[?25l" ANSI_HIGHLIGHT_GREEN, stdout);
 
         for (i = 0; i < j; i++)
                 fputs("\xe2\x96\x88", stdout);
@@ -68,7 +70,10 @@ static void draw_progress(uint64_t p, usec_t *last_usec) {
 
         printf(" %3"PRIu64"%%", 100U * p / 65535U);
 
-        fputs("\r\x1B[?25h", stdout);
+        fputs("\r", stdout);
+        if (colors_enabled())
+                fputs("\x1B[?25h", stdout);
+
         fflush(stdout);
 }
 
@@ -99,20 +104,25 @@ static void flush_progress(void) {
         fflush(stdout);
 }
 
-#define debug(_offset, _fmt, ...) do                                  \
+#define debug(_offset, _fmt, ...) do {                                  \
                 flush_progress();                                       \
                 log_debug(OFSfmt": " _fmt, _offset, ##__VA_ARGS__);     \
-        } while(0)
+        } while (0)
 
-#define warning(_offset, _fmt, ...) do                                \
+#define warning(_offset, _fmt, ...) do {                                \
                 flush_progress();                                       \
                 log_warning(OFSfmt": " _fmt, _offset, ##__VA_ARGS__);   \
-        } while(0)
+        } while (0)
 
-#define error(_offset, _fmt, ...) do                                  \
+#define error(_offset, _fmt, ...) do {                                  \
                 flush_progress();                                       \
                 log_error(OFSfmt": " _fmt, (uint64_t)_offset, ##__VA_ARGS__); \
-        } while(0)
+        } while (0)
+
+#define error_errno(_offset, error, _fmt, ...) do {               \
+                flush_progress();                                       \
+                log_error_errno(error, OFSfmt": " _fmt, (uint64_t)_offset, ##__VA_ARGS__); \
+        } while (0)
 
 static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o) {
         uint64_t i;
@@ -141,7 +151,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
                         warning(offset, "Unused data (entry_offset==0)");
 
                 if ((le64toh(o->data.entry_offset) == 0) ^ (le64toh(o->data.n_entries) == 0)) {
-                        error(offset, "Bad n_entries: %"PRIu64, o->data.n_entries);
+                        error(offset, "Bad n_entries: %"PRIu64, le64toh(o->data.n_entries));
                         return -EBADMSG;
                 }
 
@@ -164,8 +174,8 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
                                             le64toh(o->object.size) - offsetof(Object, data.payload),
                                             &b, &alloc, &b_size, 0);
                         if (r < 0) {
-                                error(offset, "%s decompression failed: %s",
-                                      object_compressed_to_string(compression), strerror(-r));
+                                error_errno(offset, r, "%s decompression failed: %m",
+                                            object_compressed_to_string(compression));
                                 return r;
                         }
 
@@ -178,15 +188,15 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
                         return -EBADMSG;
                 }
 
-                if (!VALID64(o->data.next_hash_offset) ||
-                    !VALID64(o->data.next_field_offset) ||
-                    !VALID64(o->data.entry_offset) ||
-                    !VALID64(o->data.entry_array_offset)) {
+                if (!VALID64(le64toh(o->data.next_hash_offset)) ||
+                    !VALID64(le64toh(o->data.next_field_offset)) ||
+                    !VALID64(le64toh(o->data.entry_offset)) ||
+                    !VALID64(le64toh(o->data.entry_array_offset))) {
                         error(offset, "Invalid offset (next_hash_offset="OFSfmt", next_field_offset="OFSfmt", entry_offset="OFSfmt", entry_array_offset="OFSfmt,
-                              o->data.next_hash_offset,
-                              o->data.next_field_offset,
-                              o->data.entry_offset,
-                              o->data.entry_array_offset);
+                              le64toh(o->data.next_hash_offset),
+                              le64toh(o->data.next_field_offset),
+                              le64toh(o->data.entry_offset),
+                              le64toh(o->data.entry_array_offset));
                         return -EBADMSG;
                 }
 
@@ -202,12 +212,12 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
                         return -EBADMSG;
                 }
 
-                if (!VALID64(o->field.next_hash_offset) ||
-                    !VALID64(o->field.head_data_offset)) {
+                if (!VALID64(le64toh(o->field.next_hash_offset)) ||
+                    !VALID64(le64toh(o->field.head_data_offset))) {
                         error(offset,
                               "Invalid offset (next_hash_offset="OFSfmt", head_data_offset="OFSfmt,
-                              o->field.next_hash_offset,
-                              o->field.head_data_offset);
+                              le64toh(o->field.next_hash_offset),
+                              le64toh(o->field.head_data_offset));
                         return -EBADMSG;
                 }
                 break;
@@ -250,12 +260,12 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
                 }
 
                 for (i = 0; i < journal_file_entry_n_items(o); i++) {
-                        if (o->entry.items[i].object_offset == 0 ||
-                            !VALID64(o->entry.items[i].object_offset)) {
+                        if (le64toh(o->entry.items[i].object_offset) == 0 ||
+                            !VALID64(le64toh(o->entry.items[i].object_offset))) {
                                 error(offset,
                                       "Invalid entry item (%"PRIu64"/%"PRIu64" offset: "OFSfmt,
                                       i, journal_file_entry_n_items(o),
-                                      o->entry.items[i].object_offset);
+                                      le64toh(o->entry.items[i].object_offset));
                                 return -EBADMSG;
                         }
                 }
@@ -316,10 +326,10 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
                         return -EBADMSG;
                 }
 
-                if (!VALID64(o->entry_array.next_entry_array_offset)) {
+                if (!VALID64(le64toh(o->entry_array.next_entry_array_offset))) {
                         error(offset,
                               "Invalid object entry array next_entry_array_offset: "OFSfmt,
-                              o->entry_array.next_entry_array_offset);
+                              le64toh(o->entry_array.next_entry_array_offset));
                         return -EBADMSG;
                 }
 
@@ -343,10 +353,10 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o
                         return -EBADMSG;
                 }
 
-                if (!VALID_EPOCH(o->tag.epoch)) {
+                if (!VALID_EPOCH(le64toh(o->tag.epoch))) {
                         error(offset,
                               "Invalid object tag epoch: %"PRIu64,
-                              o->tag.epoch);
+                              le64toh(o->tag.epoch));
                         return -EBADMSG;
                 }
 
@@ -368,12 +378,12 @@ static int write_uint64(int fd, uint64_t p) {
         return 0;
 }
 
-static int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
+static int contains_uint64(MMapCache *m, MMapFileDescriptor *f, uint64_t n, uint64_t p) {
         uint64_t a, b;
         int r;
 
         assert(m);
-        assert(fd >= 0);
+        assert(f);
 
         /* Bisection ... */
 
@@ -383,7 +393,7 @@ static int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
 
                 c = (a + b) / 2;
 
-                r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z);
+                r = mmap_cache_get(m, f, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z, NULL);
                 if (r < 0)
                         return r;
 
@@ -404,7 +414,7 @@ static int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
 
 static int entry_points_to_data(
                 JournalFile *f,
-                int entry_fd,
+                MMapFileDescriptor *cache_entry_fd,
                 uint64_t n_entries,
                 uint64_t entry_p,
                 uint64_t data_p) {
@@ -415,9 +425,9 @@ static int entry_points_to_data(
         bool found = false;
 
         assert(f);
-        assert(entry_fd >= 0);
+        assert(cache_entry_fd);
 
-        if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) {
+        if (!contains_uint64(f->mmap, cache_entry_fd, n_entries, entry_p)) {
                 error(data_p, "Data object references invalid entry at "OFSfmt, entry_p);
                 return -EBADMSG;
         }
@@ -491,16 +501,16 @@ static int entry_points_to_data(
 static int verify_data(
                 JournalFile *f,
                 Object *o, uint64_t p,
-                int entry_fd, uint64_t n_entries,
-                int entry_array_fd, uint64_t n_entry_arrays) {
+                MMapFileDescriptor *cache_entry_fd, uint64_t n_entries,
+                MMapFileDescriptor *cache_entry_array_fd, uint64_t n_entry_arrays) {
 
         uint64_t i, n, a, last, q;
         int r;
 
         assert(f);
         assert(o);
-        assert(entry_fd >= 0);
-        assert(entry_array_fd >= 0);
+        assert(cache_entry_fd);
+        assert(cache_entry_array_fd);
 
         n = le64toh(o->data.n_entries);
         a = le64toh(o->data.entry_array_offset);
@@ -518,7 +528,7 @@ static int verify_data(
         assert(o->data.entry_offset);
 
         last = q = le64toh(o->data.entry_offset);
-        r = entry_points_to_data(f, entry_fd, n_entries, q, p);
+        r = entry_points_to_data(f, cache_entry_fd, n_entries, q, p);
         if (r < 0)
                 return r;
 
@@ -531,7 +541,7 @@ static int verify_data(
                         return -EBADMSG;
                 }
 
-                if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
+                if (!contains_uint64(f->mmap, cache_entry_array_fd, n_entry_arrays, a)) {
                         error(p, "Invalid array offset "OFSfmt, a);
                         return -EBADMSG;
                 }
@@ -556,7 +566,7 @@ static int verify_data(
                         }
                         last = q;
 
-                        r = entry_points_to_data(f, entry_fd, n_entries, q, p);
+                        r = entry_points_to_data(f, cache_entry_fd, n_entries, q, p);
                         if (r < 0)
                                 return r;
 
@@ -574,9 +584,9 @@ static int verify_data(
 
 static int verify_hash_table(
                 JournalFile *f,
-                int data_fd, uint64_t n_data,
-                int entry_fd, uint64_t n_entries,
-                int entry_array_fd, uint64_t n_entry_arrays,
+                MMapFileDescriptor *cache_data_fd, uint64_t n_data,
+                MMapFileDescriptor *cache_entry_fd, uint64_t n_entries,
+                MMapFileDescriptor *cache_entry_array_fd, uint64_t n_entry_arrays,
                 usec_t *last_usec,
                 bool show_progress) {
 
@@ -584,9 +594,9 @@ static int verify_hash_table(
         int r;
 
         assert(f);
-        assert(data_fd >= 0);
-        assert(entry_fd >= 0);
-        assert(entry_array_fd >= 0);
+        assert(cache_data_fd);
+        assert(cache_entry_fd);
+        assert(cache_entry_array_fd);
         assert(last_usec);
 
         n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem);
@@ -608,7 +618,7 @@ static int verify_hash_table(
                         Object *o;
                         uint64_t next;
 
-                        if (!contains_uint64(f->mmap, data_fd, n_data, p)) {
+                        if (!contains_uint64(f->mmap, cache_data_fd, n_data, p)) {
                                 error(p, "Invalid data object at hash entry %"PRIu64" of %"PRIu64, i, n);
                                 return -EBADMSG;
                         }
@@ -628,7 +638,7 @@ static int verify_hash_table(
                                 return -EBADMSG;
                         }
 
-                        r = verify_data(f, o, p, entry_fd, n_entries, entry_array_fd, n_entry_arrays);
+                        r = verify_data(f, o, p, cache_entry_fd, n_entries, cache_entry_array_fd, n_entry_arrays);
                         if (r < 0)
                                 return r;
 
@@ -680,14 +690,14 @@ static int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p)
 static int verify_entry(
                 JournalFile *f,
                 Object *o, uint64_t p,
-                int data_fd, uint64_t n_data) {
+                MMapFileDescriptor *cache_data_fd, uint64_t n_data) {
 
         uint64_t i, n;
         int r;
 
         assert(f);
         assert(o);
-        assert(data_fd >= 0);
+        assert(cache_data_fd);
 
         n = journal_file_entry_n_items(o);
         for (i = 0; i < n; i++) {
@@ -697,7 +707,7 @@ static int verify_entry(
                 q = le64toh(o->entry.items[i].object_offset);
                 h = le64toh(o->entry.items[i].hash);
 
-                if (!contains_uint64(f->mmap, data_fd, n_data, q)) {
+                if (!contains_uint64(f->mmap, cache_data_fd, n_data, q)) {
                         error(p, "Invalid data object of entry");
                         return -EBADMSG;
                 }
@@ -725,9 +735,9 @@ static int verify_entry(
 
 static int verify_entry_array(
                 JournalFile *f,
-                int data_fd, uint64_t n_data,
-                int entry_fd, uint64_t n_entries,
-                int entry_array_fd, uint64_t n_entry_arrays,
+                MMapFileDescriptor *cache_data_fd, uint64_t n_data,
+                MMapFileDescriptor *cache_entry_fd, uint64_t n_entries,
+                MMapFileDescriptor *cache_entry_array_fd, uint64_t n_entry_arrays,
                 usec_t *last_usec,
                 bool show_progress) {
 
@@ -735,9 +745,9 @@ static int verify_entry_array(
         int r;
 
         assert(f);
-        assert(data_fd >= 0);
-        assert(entry_fd >= 0);
-        assert(entry_array_fd >= 0);
+        assert(cache_data_fd);
+        assert(cache_entry_fd);
+        assert(cache_entry_array_fd);
         assert(last_usec);
 
         n = le64toh(f->header->n_entries);
@@ -754,7 +764,7 @@ static int verify_entry_array(
                         return -EBADMSG;
                 }
 
-                if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) {
+                if (!contains_uint64(f->mmap, cache_entry_array_fd, n_entry_arrays, a)) {
                         error(a, "Invalid array %"PRIu64" of %"PRIu64, i, n);
                         return -EBADMSG;
                 }
@@ -780,7 +790,7 @@ static int verify_entry_array(
                         }
                         last = p;
 
-                        if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) {
+                        if (!contains_uint64(f->mmap, cache_entry_fd, n_entries, p)) {
                                 error(a, "Invalid array entry at %"PRIu64" of %"PRIu64, i, n);
                                 return -EBADMSG;
                         }
@@ -789,7 +799,7 @@ static int verify_entry_array(
                         if (r < 0)
                                 return r;
 
-                        r = verify_entry(f, o, p, data_fd, n_data);
+                        r = verify_entry(f, o, p, cache_data_fd, n_data);
                         if (r < 0)
                                 return r;
 
@@ -820,15 +830,18 @@ int journal_file_verify(
         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;
         usec_t last_usec = 0;
         int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
+        MMapFileDescriptor *cache_data_fd = NULL, *cache_entry_fd = NULL, *cache_entry_array_fd = NULL;
         unsigned i;
         bool found_last = false;
-#ifdef HAVE_GCRYPT
+        const char *tmp_dir = NULL;
+
+#if HAVE_GCRYPT
         uint64_t last_tag = 0;
 #endif
         assert(f);
 
         if (key) {
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
                 r = journal_file_parse_verification_key(f, key);
                 if (r < 0) {
                         log_error("Failed to parse seed.");
@@ -840,25 +853,49 @@ int journal_file_verify(
         } else if (f->seal)
                 return -ENOKEY;
 
-        data_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
+        r = var_tmp_dir(&tmp_dir);
+        if (r < 0) {
+                log_error_errno(r, "Failed to determine temporary directory: %m");
+                goto fail;
+        }
+
+        data_fd = open_tmpfile_unlinkable(tmp_dir, O_RDWR | O_CLOEXEC);
         if (data_fd < 0) {
-                r = log_error_errno(errno, "Failed to create data file: %m");
+                r = log_error_errno(data_fd, "Failed to create data file: %m");
                 goto fail;
         }
 
-        entry_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
+        entry_fd = open_tmpfile_unlinkable(tmp_dir, O_RDWR | O_CLOEXEC);
         if (entry_fd < 0) {
-                r = log_error_errno(errno, "Failed to create entry file: %m");
+                r = log_error_errno(entry_fd, "Failed to create entry file: %m");
                 goto fail;
         }
 
-        entry_array_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
+        entry_array_fd = open_tmpfile_unlinkable(tmp_dir, O_RDWR | O_CLOEXEC);
         if (entry_array_fd < 0) {
-                r = log_error_errno(errno,
+                r = log_error_errno(entry_array_fd,
                                     "Failed to create entry array file: %m");
                 goto fail;
         }
 
+        cache_data_fd = mmap_cache_add_fd(f->mmap, data_fd);
+        if (!cache_data_fd) {
+                r = log_oom();
+                goto fail;
+        }
+
+        cache_entry_fd = mmap_cache_add_fd(f->mmap, entry_fd);
+        if (!cache_entry_fd) {
+                r = log_oom();
+                goto fail;
+        }
+
+        cache_entry_array_fd = mmap_cache_add_fd(f->mmap, entry_array_fd);
+        if (!cache_entry_array_fd) {
+                r = log_oom();
+                goto fail;
+        }
+
         if (le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SUPPORTED) {
                 log_error("Cannot verify file with unknown extensions.");
                 r = -EOPNOTSUPP;
@@ -896,11 +933,11 @@ int journal_file_verify(
                         goto fail;
                 }
 
-                n_objects ++;
+                n_objects++;
 
                 r = journal_file_object_verify(f, p, o);
                 if (r < 0) {
-                        error(p, "Invalid object contents: %s", strerror(-r));
+                        error_errno(p, r, "Invalid object contents: %m");
                         goto fail;
                 }
 
@@ -993,7 +1030,7 @@ int journal_file_verify(
                         entry_realtime = le64toh(o->entry.realtime);
                         entry_realtime_set = true;
 
-                        n_entries ++;
+                        n_entries++;
                         break;
 
                 case OBJECT_DATA_HASH_TABLE:
@@ -1067,13 +1104,13 @@ int journal_file_verify(
                                 goto fail;
                         }
 
-#ifdef HAVE_GCRYPT
+#if HAVE_GCRYPT
                         if (f->seal) {
                                 uint64_t q, rt;
 
                                 debug(p, "Checking tag %"PRIu64"...", le64toh(o->tag.seqnum));
 
-                                rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec;
+                                rt = f->fss_start_usec + le64toh(o->tag.epoch) * f->fss_interval_usec;
                                 if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
                                         error(p, "tag/entry realtime timestamp out of synchronization");
                                         r = -EBADMSG;
@@ -1133,11 +1170,11 @@ int journal_file_verify(
 
                         last_epoch = le64toh(o->tag.epoch);
 
-                        n_tags ++;
+                        n_tags++;
                         break;
 
                 default:
-                        n_weird ++;
+                        n_weird++;
                 }
 
                 if (p == le64toh(f->header->tail_object_offset)) {
@@ -1230,18 +1267,18 @@ int journal_file_verify(
          * referenced is consistent. */
 
         r = verify_entry_array(f,
-                               data_fd, n_data,
-                               entry_fd, n_entries,
-                               entry_array_fd, n_entry_arrays,
+                               cache_data_fd, n_data,
+                               cache_entry_fd, n_entries,
+                               cache_entry_array_fd, n_entry_arrays,
                                &last_usec,
                                show_progress);
         if (r < 0)
                 goto fail;
 
         r = verify_hash_table(f,
-                              data_fd, n_data,
-                              entry_fd, n_entries,
-                              entry_array_fd, n_entry_arrays,
+                              cache_data_fd, n_data,
+                              cache_entry_fd, n_entries,
+                              cache_entry_array_fd, n_entry_arrays,
                               &last_usec,
                               show_progress);
         if (r < 0)
@@ -1250,9 +1287,9 @@ int journal_file_verify(
         if (show_progress)
                 flush_progress();
 
-        mmap_cache_close_fd(f->mmap, data_fd);
-        mmap_cache_close_fd(f->mmap, entry_fd);
-        mmap_cache_close_fd(f->mmap, entry_array_fd);
+        mmap_cache_free_fd(f->mmap, cache_data_fd);
+        mmap_cache_free_fd(f->mmap, cache_entry_fd);
+        mmap_cache_free_fd(f->mmap, cache_entry_array_fd);
 
         safe_close(data_fd);
         safe_close(entry_fd);
@@ -1277,20 +1314,23 @@ fail:
                   (unsigned long long) f->last_stat.st_size,
                   100 * p / f->last_stat.st_size);
 
-        if (data_fd >= 0) {
-                mmap_cache_close_fd(f->mmap, data_fd);
+        if (data_fd >= 0)
                 safe_close(data_fd);
-        }
 
-        if (entry_fd >= 0) {
-                mmap_cache_close_fd(f->mmap, entry_fd);
+        if (entry_fd >= 0)
                 safe_close(entry_fd);
-        }
 
-        if (entry_array_fd >= 0) {
-                mmap_cache_close_fd(f->mmap, entry_array_fd);
+        if (entry_array_fd >= 0)
                 safe_close(entry_array_fd);
-        }
+
+        if (cache_data_fd)
+                mmap_cache_free_fd(f->mmap, cache_data_fd);
+
+        if (cache_entry_fd)
+                mmap_cache_free_fd(f->mmap, cache_entry_fd);
+
+        if (cache_entry_array_fd)
+                mmap_cache_free_fd(f->mmap, cache_entry_array_fd);
 
         return r;
 }