]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
journal-file: don't update boot_id in journal header on open
authorLennart Poettering <lennart@poettering.net>
Thu, 26 Jan 2023 15:49:36 +0000 (16:49 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 21 Feb 2023 09:47:53 +0000 (10:47 +0100)
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.

src/journal/test-journal-interleaving.c
src/libsystemd/sd-journal/journal-authenticate.c
src/libsystemd/sd-journal/journal-def.h
src/libsystemd/sd-journal/journal-file.c
src/libsystemd/sd-journal/journal-file.h
src/libsystemd/sd-journal/journal-verify.c

index 55d717da3163ec45f428bd26b9a74de965d7e434..7fec6d9eea25ae7842c53dbcfa491a894ae3d31c 100644 (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);
index 3c5d9d7e4975bb61d224f18e7f03f9d1efee8c00..159e21536791ece195ee1a3bba35e34418df0bf7 100644 (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));
 
index d35290d3c70ba30f507885a6343a742d96e6dc73..fb22fc45f304e111eeaada8c5c782dd595ee27a8 100644 (file)
@@ -173,32 +173,31 @@ enum {
         HEADER_INCOMPATIBLE_KEYED_HASH      = 1 << 2,
         HEADER_INCOMPATIBLE_COMPRESSED_ZSTD = 1 << 3,
         HEADER_INCOMPATIBLE_COMPACT         = 1 << 4,
-};
 
-#define HEADER_INCOMPATIBLE_ANY               \
-        (HEADER_INCOMPATIBLE_COMPRESSED_XZ |  \
-         HEADER_INCOMPATIBLE_COMPRESSED_LZ4 | \
-         HEADER_INCOMPATIBLE_KEYED_HASH |     \
-         HEADER_INCOMPATIBLE_COMPRESSED_ZSTD | \
-         HEADER_INCOMPATIBLE_COMPACT)
+        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_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;                              \
index aab33dbfccab138f58d923ced36bea8b16c96a0e..d361b35a6effd64aee7d60dbbec3f2e931f0ddf7 100644 (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" : "",
index 07f1f5d180651ab250132f0baf30c474da8ca62d..c1f1ab4e4fc62f4283d106b49a01a5413f1a5ee1 100644 (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)
 
index b4ce3881a44a35c94585a511856d22565e613f98..8232f53eb66995113b01a691d3faa19c9e233184 100644 (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")",