1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-12 13:18:14 +03:00

journal-file: don't update boot_id in journal header on open

The header of the journal file contains a boot ID field that is
currently updated whenever we open the journal file. This is not ideal:
pretty often we want to archive a journal file, and need to open it for
that. Archiving a foreign journal file should not mark it as ours, it
should just change the status flag in the file header.

The boot ID in the header is aleady rewritten whenever we write a
journal entry to the file anyway, hence all this patch effectively does
is slightly "delay" when the boot ID in the header is updated: instead
of immediately on open it is updated on the first entry that is written.

Net effect: archived journal files don't all look like they were written
to on a boot newer then they actually were

And more importantly: the "tail_entry_monotonic" field suddenly becomes
useful, since we know which boot it belongs to. Generally, monotonic
timestamps without boot ID information are useless, and this fixes it.

A new (compatible) header flag marks file where the boot_id can be
understood this way. This can be used by code that wants to make use of
the "tail_entry_monotonic" field to ensure it actually can do so safely.

This also renames the structure definition in journal-def accordingly,
to indicate we now follow the stricter semantics for it.
This commit is contained in:
Lennart Poettering 2023-01-26 16:49:36 +01:00
parent 512f2da5c7
commit 9204fc642a
6 changed files with 40 additions and 35 deletions

View File

@ -230,7 +230,7 @@ static void test_sequence_numbers_one(void) {
assert_se(one->file->header->state == STATE_ONLINE);
assert_se(!sd_id128_equal(one->file->header->file_id, one->file->header->machine_id));
assert_se(!sd_id128_equal(one->file->header->file_id, one->file->header->boot_id));
assert_se(!sd_id128_equal(one->file->header->file_id, one->file->header->tail_entry_boot_id));
assert_se(sd_id128_equal(one->file->header->file_id, one->file->header->seqnum_id));
memcpy(&seqnum_id, &one->file->header->seqnum_id, sizeof(sd_id128_t));
@ -241,7 +241,7 @@ static void test_sequence_numbers_one(void) {
assert_se(two->file->header->state == STATE_ONLINE);
assert_se(!sd_id128_equal(two->file->header->file_id, one->file->header->file_id));
assert_se(sd_id128_equal(one->file->header->machine_id, one->file->header->machine_id));
assert_se(sd_id128_equal(one->file->header->boot_id, one->file->header->boot_id));
assert_se(sd_id128_equal(one->file->header->tail_entry_boot_id, one->file->header->tail_entry_boot_id));
assert_se(sd_id128_equal(one->file->header->seqnum_id, one->file->header->seqnum_id));
append_number(two, 3, &seqnum);

View File

@ -300,7 +300,7 @@ int journal_file_hmac_put_header(JournalFile *f) {
* n_entry_arrays. */
gcry_md_write(f->hmac, f->header->signature, offsetof(Header, state) - offsetof(Header, signature));
gcry_md_write(f->hmac, &f->header->file_id, offsetof(Header, boot_id) - offsetof(Header, file_id));
gcry_md_write(f->hmac, &f->header->file_id, offsetof(Header, tail_entry_boot_id) - offsetof(Header, file_id));
gcry_md_write(f->hmac, &f->header->seqnum_id, offsetof(Header, arena_size) - offsetof(Header, seqnum_id));
gcry_md_write(f->hmac, &f->header->data_hash_table_offset, offsetof(Header, tail_object_offset) - offsetof(Header, data_hash_table_offset));

View File

@ -173,32 +173,31 @@ enum {
HEADER_INCOMPATIBLE_KEYED_HASH = 1 << 2,
HEADER_INCOMPATIBLE_COMPRESSED_ZSTD = 1 << 3,
HEADER_INCOMPATIBLE_COMPACT = 1 << 4,
HEADER_INCOMPATIBLE_ANY = HEADER_INCOMPATIBLE_COMPRESSED_XZ |
HEADER_INCOMPATIBLE_COMPRESSED_LZ4 |
HEADER_INCOMPATIBLE_KEYED_HASH |
HEADER_INCOMPATIBLE_COMPRESSED_ZSTD |
HEADER_INCOMPATIBLE_COMPACT,
HEADER_INCOMPATIBLE_SUPPORTED = (HAVE_XZ ? HEADER_INCOMPATIBLE_COMPRESSED_XZ : 0) |
(HAVE_LZ4 ? HEADER_INCOMPATIBLE_COMPRESSED_LZ4 : 0) |
(HAVE_ZSTD ? HEADER_INCOMPATIBLE_COMPRESSED_ZSTD : 0) |
HEADER_INCOMPATIBLE_KEYED_HASH |
HEADER_INCOMPATIBLE_COMPACT,
};
#define HEADER_INCOMPATIBLE_ANY \
(HEADER_INCOMPATIBLE_COMPRESSED_XZ | \
HEADER_INCOMPATIBLE_COMPRESSED_LZ4 | \
HEADER_INCOMPATIBLE_KEYED_HASH | \
HEADER_INCOMPATIBLE_COMPRESSED_ZSTD | \
HEADER_INCOMPATIBLE_COMPACT)
#define HEADER_INCOMPATIBLE_SUPPORTED \
((HAVE_XZ ? HEADER_INCOMPATIBLE_COMPRESSED_XZ : 0) | \
(HAVE_LZ4 ? HEADER_INCOMPATIBLE_COMPRESSED_LZ4 : 0) | \
(HAVE_ZSTD ? HEADER_INCOMPATIBLE_COMPRESSED_ZSTD : 0) | \
HEADER_INCOMPATIBLE_KEYED_HASH | \
HEADER_INCOMPATIBLE_COMPACT)
enum {
HEADER_COMPATIBLE_SEALED = 1 << 0,
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_SUPPORTED = (HAVE_GCRYPT ? HEADER_COMPATIBLE_SEALED : 0) |
HEADER_COMPATIBLE_TAIL_ENTRY_BOOT_ID,
};
#define HEADER_COMPATIBLE_ANY HEADER_COMPATIBLE_SEALED
#if HAVE_GCRYPT
# define HEADER_COMPATIBLE_SUPPORTED HEADER_COMPATIBLE_SEALED
#else
# define HEADER_COMPATIBLE_SUPPORTED 0
#endif
#define HEADER_SIGNATURE \
((const uint8_t[]) { 'L', 'P', 'K', 'S', 'H', 'H', 'R', 'H' })
@ -211,7 +210,7 @@ enum {
uint8_t reserved[7]; \
sd_id128_t file_id; \
sd_id128_t machine_id; \
sd_id128_t boot_id; /* last writer */ \
sd_id128_t tail_entry_boot_id; \
sd_id128_t seqnum_id; \
le64_t header_size; \
le64_t arena_size; \

View File

@ -357,7 +357,9 @@ static int journal_file_init_header(
FLAGS_SET(file_flags, JOURNAL_COMPRESS) * COMPRESSION_TO_HEADER_INCOMPATIBLE_FLAG(DEFAULT_COMPRESSION) |
keyed_hash_requested() * HEADER_INCOMPATIBLE_KEYED_HASH |
compact_mode_requested() * HEADER_INCOMPATIBLE_COMPACT),
.compatible_flags = htole32(seal * HEADER_COMPATIBLE_SEALED),
.compatible_flags = htole32(
(seal * HEADER_COMPATIBLE_SEALED) |
HEADER_COMPATIBLE_TAIL_ENTRY_BOOT_ID),
};
assert_cc(sizeof(h.signature) == sizeof(HEADER_SIGNATURE));
@ -397,9 +399,8 @@ static int journal_file_refresh_header(JournalFile *f) {
f->header->machine_id = SD_ID128_NULL;
}
r = sd_id128_get_boot(&f->header->boot_id);
if (r < 0)
return r;
/* We used to update the header's boot ID field here, but we don't do that anymore, as per
* HEADER_COMPATIBLE_TAIL_ENTRY_BOOT_ID */
r = journal_file_set_online(f);
@ -2126,9 +2127,9 @@ static int journal_file_append_entry_internal(
"timestamp %" PRIu64 ", refusing entry.",
ts->realtime, le64toh(f->header->tail_entry_realtime));
if (!sd_id128_is_null(f->header->boot_id) && boot_id) {
if (!sd_id128_is_null(f->header->tail_entry_boot_id) && boot_id) {
if (!sd_id128_equal(f->header->boot_id, *boot_id))
if (!sd_id128_equal(f->header->tail_entry_boot_id, *boot_id))
return log_debug_errno(SYNTHETIC_ERRNO(EREMOTE),
"Boot ID to write is different from previous boot id, refusing entry.");
@ -2166,8 +2167,8 @@ static int journal_file_append_entry_internal(
o->entry.monotonic = htole64(ts->monotonic);
o->entry.xor_hash = htole64(xor_hash);
if (boot_id)
f->header->boot_id = *boot_id;
o->entry.boot_id = f->header->boot_id;
f->header->tail_entry_boot_id = *boot_id;
o->entry.boot_id = f->header->tail_entry_boot_id;
for (size_t i = 0; i < n_items; i++)
write_entry_item(f, o, i, &items[i]);
@ -3567,7 +3568,7 @@ void journal_file_print_header(JournalFile *f) {
"Boot ID: %s\n"
"Sequential number ID: %s\n"
"State: %s\n"
"Compatible flags:%s%s\n"
"Compatible flags:%s%s%s\n"
"Incompatible flags:%s%s%s%s%s%s\n"
"Header size: %"PRIu64"\n"
"Arena size: %"PRIu64"\n"
@ -3584,12 +3585,13 @@ void journal_file_print_header(JournalFile *f) {
f->path,
SD_ID128_TO_STRING(f->header->file_id),
SD_ID128_TO_STRING(f->header->machine_id),
SD_ID128_TO_STRING(f->header->boot_id),
SD_ID128_TO_STRING(f->header->tail_entry_boot_id),
SD_ID128_TO_STRING(f->header->seqnum_id),
f->header->state == STATE_OFFLINE ? "OFFLINE" :
f->header->state == STATE_ONLINE ? "ONLINE" :
f->header->state == STATE_ARCHIVED ? "ARCHIVED" : "UNKNOWN",
JOURNAL_HEADER_SEALED(f->header) ? " SEALED" : "",
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" : "",
JOURNAL_HEADER_COMPRESSED_LZ4(f->header) ? " COMPRESSED-LZ4" : "",

View File

@ -180,6 +180,9 @@ static inline bool VALID_EPOCH(uint64_t u) {
#define JOURNAL_HEADER_SEALED(h) \
FLAGS_SET(le32toh((h)->compatible_flags), HEADER_COMPATIBLE_SEALED)
#define JOURNAL_HEADER_TAIL_ENTRY_BOOT_ID(h) \
FLAGS_SET(le32toh((h)->compatible_flags), HEADER_COMPATIBLE_TAIL_ENTRY_BOOT_ID)
#define JOURNAL_HEADER_COMPRESSED_XZ(h) \
FLAGS_SET(le32toh((h)->incompatible_flags), HEADER_INCOMPATIBLE_COMPRESSED_XZ)

View File

@ -1297,7 +1297,8 @@ int journal_file_verify(
}
if (entry_monotonic_set &&
(sd_id128_equal(entry_boot_id, f->header->boot_id) &&
(sd_id128_equal(entry_boot_id, f->header->tail_entry_boot_id) &&
JOURNAL_HEADER_TAIL_ENTRY_BOOT_ID(f->header) &&
entry_monotonic != le64toh(f->header->tail_entry_monotonic))) {
error(0,
"Invalid tail monotonic timestamp (%"PRIu64" != %"PRIu64")",