chiark / gitweb /
journald: add additional simple static tests to verifier
[elogind.git] / src / journal / journal-verify.c
index 598fc9beadf2f86c4f2c8acc317478685a9c28bc..7be0d2e5d76ef1b68f1236f28172a63c19a0dbbf 100644 (file)
@@ -36,8 +36,6 @@
 /* FIXME:
  *
  * - write bit mucking test
- * - tag timestamps should be between entry timestamps
- * - output validated time ranges
  * - evolve key even if nothing happened in regular intervals
  *
  * - Allow building without libgcrypt
@@ -47,6 +45,8 @@
  * */
 
 static int journal_file_object_verify(JournalFile *f, Object *o) {
+        uint64_t i;
+
         assert(f);
         assert(o);
 
@@ -89,12 +89,22 @@ static int journal_file_object_verify(JournalFile *f, Object *o) {
                 if (h1 != h2)
                         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))
+                        return -EBADMSG;
+
                 break;
         }
 
         case OBJECT_FIELD:
                 if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0)
                         return -EBADMSG;
+
+                if (!VALID64(o->field.next_hash_offset) ||
+                    !VALID64(o->field.head_data_offset))
+                        return -EBADMSG;
                 break;
 
         case OBJECT_ENTRY:
@@ -108,6 +118,12 @@ static int journal_file_object_verify(JournalFile *f, Object *o) {
                     le64toh(o->entry.realtime) <= 0)
                         return -EBADMSG;
 
+                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))
+                                return -EBADMSG;
+                }
+
                 break;
 
         case OBJECT_DATA_HASH_TABLE:
@@ -127,6 +143,9 @@ static int journal_file_object_verify(JournalFile *f, Object *o) {
                 if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0)
                         return -EBADMSG;
 
+                if (!VALID64(o->entry_array.next_entry_array_offset))
+                        return -EBADMSG;
+
                 break;
 
         case OBJECT_TAG:
@@ -652,7 +671,10 @@ static int journal_file_parse_verification_key(JournalFile *f, const char *key)
         return 0;
 }
 
-int journal_file_verify(JournalFile *f, const char *key) {
+int journal_file_verify(
+                JournalFile *f,
+                const char *key,
+                usec_t *first_validated, usec_t *last_validated, usec_t *last_contained) {
         int r;
         Object *o;
         uint64_t p = 0, last_tag = 0, last_epoch = 0, last_tag_realtime = 0;
@@ -749,6 +771,12 @@ int journal_file_verify(JournalFile *f, const char *key) {
                         break;
 
                 case OBJECT_ENTRY:
+                        if ((le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED) && n_tags <= 0) {
+                                log_error("First entry before first tag at %llu", (unsigned long long) p);
+                                r = -EBADMSG;
+                                goto fail;
+                        }
+
                         r = write_uint64(entry_fd, p);
                         if (r < 0)
                                 goto fail;
@@ -854,7 +882,7 @@ int journal_file_verify(JournalFile *f, const char *key) {
                         break;
 
                 case OBJECT_TAG: {
-                        uint64_t q;
+                        uint64_t q, rt;
 
                         if (!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED)) {
                                 log_error("Tag object in file without sealing at %llu", (unsigned long long) p);
@@ -876,8 +904,8 @@ int journal_file_verify(JournalFile *f, const char *key) {
                                 goto fail;
                         }
 
-                        last_tag_realtime = (o->tag.epoch + 1) * f->fss_interval_usec + f->fss_start_usec;
-                        if (entry_realtime_set && entry_realtime >= last_tag_realtime) {
+                        rt = (o->tag.epoch + 1) * f->fss_interval_usec + f->fss_start_usec;
+                        if (entry_realtime_set && entry_realtime >= rt) {
                                 log_error("Tag/entry realtime timestamp out of synchronization at %llu", (unsigned long long) p);
                                 r = -EBADMSG;
                                 goto fail;
@@ -929,6 +957,8 @@ int journal_file_verify(JournalFile *f, const char *key) {
                         f->hmac_running = false;
 
                         last_tag = p + ALIGN64(le64toh(o->object.size));
+                        last_tag_realtime = rt;
+
                         n_tags ++;
                         break;
                 }
@@ -1056,6 +1086,13 @@ int journal_file_verify(JournalFile *f, const char *key) {
         close_nointr_nofail(entry_fd);
         close_nointr_nofail(entry_array_fd);
 
+        if (first_validated)
+                *first_validated = le64toh(f->header->head_entry_realtime);
+        if (last_validated)
+                *last_validated = last_tag_realtime;
+        if (last_contained)
+                *last_contained = le64toh(f->header->tail_entry_realtime);
+
         return 0;
 
 fail: