TAKE_FD(fd); /* Donated to journal_file_open() */
+ journal_file_write_final_tag(f);
r = journal_file_archive(f, NULL);
if (r < 0)
log_debug_errno(r, "Failed to archive journal file '%s', ignoring: %m", full);
if (!JOURNAL_HEADER_SEALED(f->header))
return 0;
- if (!f->hmac_running)
- return 0;
+ if (!f->hmac_running) {
+ r = journal_file_hmac_start(f);
+ if (r < 0)
+ return r;
+ }
assert(f->hmac);
FSPRG_Evolve(f->fsprg_state);
epoch = FSPRG_GetEpoch(f->fsprg_state);
+ if (epoch < goal) {
+ r = journal_file_append_tag(f);
+ if (r < 0)
+ return r;
+ }
}
}
enum {
HEADER_COMPATIBLE_SEALED = 1 << 0,
HEADER_COMPATIBLE_TAIL_ENTRY_BOOT_ID = 1 << 1, /* if set, the last_entry_boot_id field in the header is exclusively refreshed when an entry is appended */
- HEADER_COMPATIBLE_ANY = HEADER_COMPATIBLE_SEALED|
- HEADER_COMPATIBLE_TAIL_ENTRY_BOOT_ID,
+ HEADER_COMPATIBLE_SEALED_CONTINUOUS = 1 << 2,
+ HEADER_COMPATIBLE_ANY = HEADER_COMPATIBLE_SEALED |
+ HEADER_COMPATIBLE_TAIL_ENTRY_BOOT_ID |
+ HEADER_COMPATIBLE_SEALED_CONTINUOUS,
- HEADER_COMPATIBLE_SUPPORTED = (HAVE_GCRYPT ? HEADER_COMPATIBLE_SEALED : 0) |
+ HEADER_COMPATIBLE_SUPPORTED = (HAVE_GCRYPT ? HEADER_COMPATIBLE_SEALED | HEADER_COMPATIBLE_SEALED_CONTINUOUS : 0) |
HEADER_COMPATIBLE_TAIL_ENTRY_BOOT_ID,
};
keyed_hash_requested() * HEADER_INCOMPATIBLE_KEYED_HASH |
compact_mode_requested() * HEADER_INCOMPATIBLE_COMPACT),
.compatible_flags = htole32(
- (seal * HEADER_COMPATIBLE_SEALED) |
+ (seal * (HEADER_COMPATIBLE_SEALED | HEADER_COMPATIBLE_SEALED_CONTINUOUS) ) |
HEADER_COMPATIBLE_TAIL_ENTRY_BOOT_ID),
};
if (compatible) {
if (flags & HEADER_COMPATIBLE_SEALED)
strv[n++] = "sealed";
+ if (flags & HEADER_COMPATIBLE_SEALED_CONTINUOUS)
+ strv[n++] = "sealed-continuous";
} else {
if (flags & HEADER_INCOMPATIBLE_COMPRESSED_XZ)
strv[n++] = "xz-compressed";
"Boot ID: %s\n"
"Sequential number ID: %s\n"
"State: %s\n"
- "Compatible flags:%s%s%s\n"
+ "Compatible flags:%s%s%s%s\n"
"Incompatible flags:%s%s%s%s%s%s\n"
"Header size: %"PRIu64"\n"
"Arena size: %"PRIu64"\n"
f->header->state == STATE_ONLINE ? "ONLINE" :
f->header->state == STATE_ARCHIVED ? "ARCHIVED" : "UNKNOWN",
JOURNAL_HEADER_SEALED(f->header) ? " SEALED" : "",
+ JOURNAL_HEADER_SEALED_CONTINUOUS(f->header) ? " SEALED_CONTINUOUS" : "",
JOURNAL_HEADER_TAIL_ENTRY_BOOT_ID(f->header) ? " TAIL_ENTRY_BOOT_ID" : "",
(le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_ANY) ? " ???" : "",
JOURNAL_HEADER_COMPRESSED_XZ(f->header) ? " COMPRESSED-XZ" : "",
#define JOURNAL_HEADER_SEALED(h) \
FLAGS_SET(le32toh((h)->compatible_flags), HEADER_COMPATIBLE_SEALED)
+#define JOURNAL_HEADER_SEALED_CONTINUOUS(h) \
+ FLAGS_SET(le32toh((h)->compatible_flags), HEADER_COMPATIBLE_SEALED_CONTINUOUS)
+
#define JOURNAL_HEADER_TAIL_ENTRY_BOOT_ID(h) \
FLAGS_SET(le32toh((h)->compatible_flags), HEADER_COMPATIBLE_TAIL_ENTRY_BOOT_ID)
bool show_progress) {
int r;
Object *o;
- uint64_t p = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0;
+ uint64_t p = 0, last_epoch = 0, last_tag_realtime = 0;
uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
usec_t min_entry_realtime = USEC_INFINITY, max_entry_realtime = 0;
goto fail;
}
+ if (!JOURNAL_HEADER_SEALED_CONTINUOUS(f->header))
+ warning(p,
+ "This log file was sealed with an old journald version where the sequence of seals might not be continuous. We cannot guarantee completeness.");
+
/* First iteration: we go through all objects, verify the
* superficial structure, headers, hashes. */
goto fail;
}
- if (le64toh(o->tag.epoch) < last_epoch) {
- error(p,
- "Epoch sequence out of synchronization (%"PRIu64" < %"PRIu64")",
- le64toh(o->tag.epoch),
- last_epoch);
- r = -EBADMSG;
- goto fail;
+ if (JOURNAL_HEADER_SEALED_CONTINUOUS(f->header)) {
+ if (!(n_tags == 0 || (n_tags == 1 && le64toh(o->tag.epoch) == last_epoch)
+ || le64toh(o->tag.epoch) == last_epoch + 1)) {
+ error(p,
+ "Epoch sequence not continuous (%"PRIu64" vs %"PRIu64")",
+ le64toh(o->tag.epoch),
+ last_epoch);
+ r = -EBADMSG;
+ goto fail;
+ }
+ } else {
+ if (le64toh(o->tag.epoch) < last_epoch) {
+ error(p,
+ "Epoch sequence out of synchronization (%"PRIu64" < %"PRIu64")",
+ le64toh(o->tag.epoch),
+ last_epoch);
+ r = -EBADMSG;
+ goto fail;
+ }
}
#if HAVE_GCRYPT
f->hmac_running = false;
last_tag_realtime = rt;
- last_sealed_realtime = entry_realtime;
}
last_tag = p + ALIGN64(le64toh(o->object.size));
if (first_contained)
*first_contained = le64toh(f->header->head_entry_realtime);
+#if HAVE_GCRYPT
if (last_validated)
- *last_validated = last_sealed_realtime;
+ *last_validated = last_tag_realtime + f->fss_interval_usec;
+#endif
if (last_contained)
*last_contained = le64toh(f->header->tail_entry_realtime);
return true;
}
+void journal_file_write_final_tag(JournalFile *f) {
+ assert(f);
+#if HAVE_GCRYPT
+ if (!JOURNAL_HEADER_SEALED(f->header) || !journal_file_writable(f))
+ return;
+
+ int r = journal_file_append_tag(f);
+ if (r < 0)
+ log_debug_errno(r, "Failed to append tag when closing journal: %m");
+#endif
+}
+
JournalFile* journal_file_offline_close(JournalFile *f) {
if (!f)
return NULL;
-#if HAVE_GCRYPT
- /* Write the final tag */
- if (JOURNAL_HEADER_SEALED(f->header) && journal_file_writable(f)) {
- int r;
-
- r = journal_file_append_tag(f);
- if (r < 0)
- log_error_errno(r, "Failed to append tag when closing journal: %m");
- }
-#endif
+ journal_file_write_final_tag(f);
if (sd_event_source_get_enabled(f->post_change_timer, NULL) > 0)
journal_file_post_change(f);
assert(f);
assert(*f);
+ journal_file_write_final_tag(*f);
r = journal_file_archive(*f, &path);
if (r < 0)
return r;
int journal_file_set_offline(JournalFile *f, bool wait);
bool journal_file_is_offlining(JournalFile *f);
+void journal_file_write_final_tag(JournalFile *f);
JournalFile* journal_file_offline_close(JournalFile *f);
DEFINE_TRIVIAL_CLEANUP_FUNC(JournalFile*, journal_file_offline_close);