[systemd-commits] 12 commits - TODO src/journal

Lennart Poettering lennart at kemper.freedesktop.org
Mon Aug 20 07:12:56 PDT 2012


 TODO                               |    2 
 src/journal/fsprg.c                |    2 
 src/journal/journal-authenticate.c |    2 
 src/journal/journal-def.h          |    9 +
 src/journal/journal-file.c         |   60 +++++++---
 src/journal/journal-file.h         |   23 +++
 src/journal/journal-verify.c       |  218 ++++++++++++++++++++++++++-----------
 src/journal/journal-verify.h       |    2 
 src/journal/journalctl.c           |   20 ++-
 src/journal/journald.c             |    2 
 src/journal/mmap-cache.c           |   55 +++++++--
 src/journal/mmap-cache.h           |    2 
 src/journal/sd-journal.c           |    5 
 src/journal/test-journal-verify.c  |   72 ++++++++++--
 14 files changed, 356 insertions(+), 118 deletions(-)

New commits:
commit 8088cbd3cfcf539c984d8042cd2b92ebbfda6d82
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Aug 20 16:11:42 2012 +0200

    journal: use a macro to check for file header flags

diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c
index 9853edb..ddcf856 100644
--- a/src/journal/journal-authenticate.c
+++ b/src/journal/journal-authenticate.c
@@ -464,5 +464,5 @@ int journal_file_append_first_tag(JournalFile *f) {
 bool journal_file_fss_enabled(JournalFile *f) {
         assert(f);
 
-        return !!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED);
+        return JOURNAL_HEADER_SEALED(f->header);
 }
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index f419cf6..760efae 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -210,8 +210,7 @@ static int journal_file_verify_header(JournalFile *f) {
         if (le64toh(f->header->header_size) < HEADER_SIZE_MIN)
                 return -EBADMSG;
 
-        if ((le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED) &&
-                !JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays))
+        if (JOURNAL_HEADER_SEALED(f->header) && !JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays))
                 return -EBADMSG;
 
         if ((le64toh(f->header->header_size) + le64toh(f->header->arena_size)) > (uint64_t) f->last_stat.st_size)
@@ -251,10 +250,10 @@ static int journal_file_verify_header(JournalFile *f) {
                 }
         }
 
-        f->compress = !!(le32toh(f->header->incompatible_flags) & HEADER_INCOMPATIBLE_COMPRESSED);
+        f->compress = JOURNAL_HEADER_COMPRESSED(f->header);
 
         if (f->writable)
-                f->seal = !!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED);
+                f->seal = JOURNAL_HEADER_SEALED(f->header);
 
         return 0;
 }
@@ -1927,10 +1926,10 @@ void journal_file_print_header(JournalFile *f) {
                f->header->state == STATE_OFFLINE ? "OFFLINE" :
                f->header->state == STATE_ONLINE ? "ONLINE" :
                f->header->state == STATE_ARCHIVED ? "ARCHIVED" : "UNKNOWN",
-               (f->header->compatible_flags & HEADER_COMPATIBLE_SEALED) ? " SEALED" : "",
-               (f->header->compatible_flags & ~HEADER_COMPATIBLE_SEALED) ? " ???" : "",
-               (f->header->incompatible_flags & HEADER_INCOMPATIBLE_COMPRESSED) ? " COMPRESSED" : "",
-               (f->header->incompatible_flags & ~HEADER_INCOMPATIBLE_COMPRESSED) ? " ???" : "",
+               JOURNAL_HEADER_SEALED(f->header) ? " SEALED" : "",
+               (le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) ? " ???" : "",
+               JOURNAL_HEADER_COMPRESSED(f->header) ? " COMPRESSED" : "",
+               (le32toh(f->header->incompatible_flags) & ~HEADER_INCOMPATIBLE_COMPRESSED) ? " ???" : "",
                (unsigned long long) le64toh(f->header->header_size),
                (unsigned long long) le64toh(f->header->arena_size),
                (unsigned long long) le64toh(f->header->data_hash_table_size) / sizeof(HashItem),
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
index 7358173..5b1530e 100644
--- a/src/journal/journal-file.h
+++ b/src/journal/journal-file.h
@@ -137,6 +137,12 @@ static inline bool VALID_EPOCH(uint64_t u) {
 #define JOURNAL_HEADER_CONTAINS(h, field) \
         (le64toh((h)->header_size) >= offsetof(Header, field) + sizeof((h)->field))
 
+#define JOURNAL_HEADER_SEALED(h) \
+        (!!(le32toh((h)->compatible_flags) & HEADER_COMPATIBLE_SEALED))
+
+#define JOURNAL_HEADER_COMPRESSED(h) \
+        (!!(le32toh((h)->incompatible_flags) & HEADER_INCOMPATIBLE_COMPRESSED))
+
 int journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Object **ret);
 
 uint64_t journal_file_entry_n_items(Object *o);
diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
index 08f3e16..6afeab9 100644
--- a/src/journal/journal-verify.c
+++ b/src/journal/journal-verify.c
@@ -36,7 +36,6 @@
 /* FIXME:
  *
  * - evolve key even if nothing happened in regular intervals
- * - add macro for accessing flags
  *
  * - Allow building without libgcrypt
  * - check with sparse
@@ -806,8 +805,7 @@ int journal_file_verify(
                         goto fail;
                 }
 
-                if (o->object.flags & OBJECT_COMPRESSED &&
-                    !(le32toh(f->header->incompatible_flags) & HEADER_INCOMPATIBLE_COMPRESSED)) {
+                if ((o->object.flags & OBJECT_COMPRESSED) && !JOURNAL_HEADER_COMPRESSED(f->header)) {
                         log_error("Compressed object in file without compression at %llu", (unsigned long long) p);
                         r = -EBADMSG;
                         goto fail;
@@ -828,7 +826,7 @@ int journal_file_verify(
                         break;
 
                 case OBJECT_ENTRY:
-                        if ((le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED) && n_tags <= 0) {
+                        if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) {
                                 log_error("First entry before first tag at %llu", (unsigned long long) p);
                                 r = -EBADMSG;
                                 goto fail;
@@ -941,7 +939,7 @@ int journal_file_verify(
                 case OBJECT_TAG: {
                         uint64_t q, rt;
 
-                        if (!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED)) {
+                        if (!JOURNAL_HEADER_SEALED(f->header)) {
                                 log_error("Tag object in file without sealing at %llu", (unsigned long long) p);
                                 r = -EBADMSG;
                                 goto fail;

commit f7fab8a5ae7a3b378040203821383f5a8fc91126
Author: Lennart Poettering <lennart at poettering.net>
Date:   Mon Aug 20 15:59:33 2012 +0200

    journal: fix tag ordering check

diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index c6b25ce..f419cf6 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -1855,7 +1855,7 @@ void journal_file_dump(JournalFile *f) {
                         break;
 
                 case OBJECT_ENTRY:
-                        printf("Type: OBJECT_ENTRY %llu %llu %llu\n",
+                        printf("Type: OBJECT_ENTRY seqnum=%llu monotonic=%llu realtime=%llu\n",
                                (unsigned long long) le64toh(o->entry.seqnum),
                                (unsigned long long) le64toh(o->entry.monotonic),
                                (unsigned long long) le64toh(o->entry.realtime));
@@ -1874,8 +1874,9 @@ void journal_file_dump(JournalFile *f) {
                         break;
 
                 case OBJECT_TAG:
-                        printf("Type: OBJECT_TAG %llu\n",
-                               (unsigned long long) le64toh(o->tag.seqnum));
+                        printf("Type: OBJECT_TAG seqnum=%llu epoch=%llu\n",
+                               (unsigned long long) le64toh(o->tag.seqnum),
+                               (unsigned long long) le64toh(o->tag.epoch));
                         break;
                 }
 
diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
index e3c3ccd..08f3e16 100644
--- a/src/journal/journal-verify.c
+++ b/src/journal/journal-verify.c
@@ -709,7 +709,7 @@ int journal_file_verify(
                 bool show_progress) {
         int r;
         Object *o;
-        uint64_t p = 0, last_tag = 0, last_epoch = 0, last_tag_realtime = 0;
+        uint64_t p = 0, last_tag = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0;
         uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
         sd_id128_t entry_boot_id;
         bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
@@ -838,7 +838,7 @@ int journal_file_verify(
                         if (r < 0)
                                 goto fail;
 
-                        if (last_tag_realtime > le64toh(o->entry.realtime)) {
+                        if (le64toh(o->entry.realtime) < last_tag_realtime) {
                                 log_error("Older entry after newer tag at %llu", (unsigned long long) p);
                                 r = -EBADMSG;
                                 goto fail;
@@ -962,8 +962,8 @@ int journal_file_verify(
                         if (f->seal) {
                                 log_debug("Checking tag %llu..", (unsigned long long) le64toh(o->tag.seqnum));
 
-                                rt = (o->tag.epoch + 1) * f->fss_interval_usec + f->fss_start_usec;
-                                if (entry_realtime_set && entry_realtime >= rt) {
+                                rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec;
+                                if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
                                         log_error("Tag/entry realtime timestamp out of synchronization at %llu", (unsigned long long) p);
                                         r = -EBADMSG;
                                         goto fail;
@@ -1014,6 +1014,7 @@ int journal_file_verify(
 
                                 f->hmac_running = false;
                                 last_tag_realtime = rt;
+                                last_sealed_realtime = entry_realtime;
                         }
 
                         last_tag = p + ALIGN64(le64toh(o->object.size));
@@ -1158,7 +1159,7 @@ int journal_file_verify(
         if (first_validated)
                 *first_validated = last_tag_realtime ? le64toh(f->header->head_entry_realtime) : 0;
         if (last_validated)
-                *last_validated = last_tag_realtime;
+                *last_validated = last_sealed_realtime;
         if (last_contained)
                 *last_contained = le64toh(f->header->tail_entry_realtime);
 
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index ba678a2..e61ddf6 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -478,7 +478,7 @@ static int setup_keys(void) {
                 return log_oom();
 
         if (access(p, F_OK) >= 0) {
-                log_error("Evolving key file %s exists already.", p);
+                log_error("Sealing key file %s exists already.", p);
                 r = -EEXIST;
                 goto finish;
         }
diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c
index 4e6c119..ed6e21d 100644
--- a/src/journal/test-journal-verify.c
+++ b/src/journal/test-journal-verify.c
@@ -108,7 +108,8 @@ int main(int argc, char *argv[]) {
         log_info("Verifying...");
 
         assert_se(journal_file_open("test.journal", O_RDONLY, 0666, true, true, NULL, NULL, NULL, &f) == 0);
-        journal_file_print_header(f);
+        /* journal_file_print_header(f); */
+        journal_file_dump(f);
 
         assert_se(journal_file_verify(f, verification_key, &from, &to, &total, true) >= 0);
 
@@ -120,21 +121,21 @@ int main(int argc, char *argv[]) {
         }
         journal_file_close(f);
 
-        log_info("Toggling bits...");
+        if (verification_key) {
+                log_info("Toggling bits...");
 
-        assert_se(stat("test.journal", &st) >= 0);
+                assert_se(stat("test.journal", &st) >= 0);
 
-        for (p = 240*8; p < ((uint64_t) st.st_size * 8); p ++) {
-                bit_toggle("test.journal", p);
+                for (p = 38448*8+0; p < ((uint64_t) st.st_size * 8); p ++) {
+                        bit_toggle("test.journal", p);
 
-                log_info("[ %llu+%llu]", (unsigned long long) p / 8, (unsigned long long) p % 8);
+                        log_info("[ %llu+%llu]", (unsigned long long) p / 8, (unsigned long long) p % 8);
 
-                if (raw_verify("test.journal", verification_key) >= 0) {
-                        log_notice(ANSI_HIGHLIGHT_RED_ON ">>>> %llu (bit %llu) can be toggled without detection." ANSI_HIGHLIGHT_OFF, (unsigned long long) p / 8, (unsigned long long) p % 8);
-                        sleep(1);
-                }
+                        if (raw_verify("test.journal", verification_key) >= 0)
+                                log_notice(ANSI_HIGHLIGHT_RED_ON ">>>> %llu (bit %llu) can be toggled without detection." ANSI_HIGHLIGHT_OFF, (unsigned long long) p / 8, (unsigned long long) p % 8);
 
-                bit_toggle("test.journal", p);
+                        bit_toggle("test.journal", p);
+                }
         }
 
         log_info("Exiting...");

commit a2e99cdf94a8a0350ff13b241de07f34c015b1fc
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Aug 19 15:16:32 2012 +0200

    journal: fix bisection algorithm

diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
index 535b272..e3c3ccd 100644
--- a/src/journal/journal-verify.c
+++ b/src/journal/journal-verify.c
@@ -266,10 +266,14 @@ static int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) {
                 if (*z == p)
                         return 1;
 
+                if (a + 1 >= b)
+                        return 0;
+
                 if (p < *z)
                         b = c;
-                else
+                else {
                         a = c;
+                }
         }
 
         return 0;

commit fc89a13992384ab8d8fb0c937b021434123bbc49
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Aug 19 15:15:59 2012 +0200

    journal: validate timestamps as well

diff --git a/src/journal/fsprg.c b/src/journal/fsprg.c
index 34ce3be..2190b7c 100644
--- a/src/journal/fsprg.c
+++ b/src/journal/fsprg.c
@@ -160,7 +160,7 @@ static gcry_mpi_t twopowmodphi(uint64_t m, const gcry_mpi_t p) {
         gcry_mpi_sub_ui(phi, p, 1);
 
         /* count number of used bits in m */
-        for (n = 0; ((uint64_t)1 << n) <= m; n++)
+        for (n = 0; (1ULL << n) <= m; n++)
                 ;
 
         r = gcry_mpi_new(0);
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
index e2ef033..7358173 100644
--- a/src/journal/journal-file.h
+++ b/src/journal/journal-file.h
@@ -119,6 +119,21 @@ int journal_file_open_reliably(
 #define ALIGN64(x) (((x) + 7ULL) & ~7ULL)
 #define VALID64(x) (((x) & 7ULL) == 0ULL)
 
+static inline bool VALID_REALTIME(uint64_t u) {
+        /* This considers timestamps until the year 3112 valid. That should be plenty room... */
+        return u > 0 && u < (1ULL << 55);
+}
+
+static inline bool VALID_MONOTONIC(uint64_t u) {
+        /* This considers timestamps until 1142 years of runtime valid. */
+        return u < (1ULL << 55);
+}
+
+static inline bool VALID_EPOCH(uint64_t u) {
+        /* This allows changing the key for 1142 years, every usec. */
+        return u < (1ULL << 55);
+}
+
 #define JOURNAL_HEADER_CONTAINS(h, field) \
         (le64toh((h)->header_size) >= offsetof(Header, field) + sizeof((h)->field))
 
diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
index a318176..535b272 100644
--- a/src/journal/journal-verify.c
+++ b/src/journal/journal-verify.c
@@ -35,8 +35,8 @@
 
 /* FIXME:
  *
- * - write bit mucking test
  * - evolve key even if nothing happened in regular intervals
+ * - add macro for accessing flags
  *
  * - Allow building without libgcrypt
  * - check with sparse
@@ -115,7 +115,8 @@ static int journal_file_object_verify(JournalFile *f, Object *o) {
                         return -EBADMSG;
 
                 if (le64toh(o->entry.seqnum) <= 0 ||
-                    le64toh(o->entry.realtime) <= 0)
+                    !VALID_REALTIME(le64toh(o->entry.realtime)) ||
+                    !VALID_MONOTONIC(le64toh(o->entry.monotonic)))
                         return -EBADMSG;
 
                 for (i = 0; i < journal_file_entry_n_items(o); i++) {
@@ -169,6 +170,10 @@ static int journal_file_object_verify(JournalFile *f, Object *o) {
         case OBJECT_TAG:
                 if (le64toh(o->object.size) != sizeof(TagObject))
                         return -EBADMSG;
+
+                if (!VALID_EPOCH(o->tag.epoch))
+                        return -EBADMSG;
+
                 break;
         }
 

commit 84168d8068bb67dcd5468ab3b376535d81643aef
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Aug 18 01:46:20 2012 +0200

    mmap: resize arrays dynamically

diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index df991a4..c6b25ce 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -2003,10 +2003,7 @@ int journal_file_open(
         if (mmap_cache)
                 f->mmap = mmap_cache_ref(mmap_cache);
         else {
-                /* One context for each type, plus the zeroth catchall
-                 * context. One fd for the file plus one for each type
-                 * (which we need during verification */
-                f->mmap = mmap_cache_new(_OBJECT_TYPE_MAX, 1 + _OBJECT_TYPE_MAX);
+                f->mmap = mmap_cache_new();
                 if (!f->mmap) {
                         r = -ENOMEM;
                         goto fail;
diff --git a/src/journal/journald.c b/src/journal/journald.c
index d431953..f74c461 100644
--- a/src/journal/journald.c
+++ b/src/journal/journald.c
@@ -2794,7 +2794,7 @@ static int server_init(Server *s) {
         if (!s->user_journals)
                 return log_oom();
 
-        s->mmap = mmap_cache_new(_OBJECT_TYPE_MAX, USER_JOURNALS_MAX + 2);
+        s->mmap = mmap_cache_new();
         if (!s->mmap)
                 return log_oom();
 
diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c
index 9782139..69efb20 100644
--- a/src/journal/mmap-cache.c
+++ b/src/journal/mmap-cache.c
@@ -30,7 +30,10 @@
 #include "mmap-cache.h"
 
 #define WINDOW_SIZE (8ULL*1024ULL*1024ULL)
-#define WINDOWS_MAX 32
+
+#define DEFAULT_WINDOWS_MAX 64
+#define DEFAULT_FDS_MAX 32
+#define DEFAULT_CONTEXTS_MAX 32
 
 typedef struct Window {
         int fd;
@@ -236,19 +239,16 @@ static void mmap_cache_free(MMapCache *m) {
         free(m);
 }
 
-MMapCache* mmap_cache_new(unsigned contexts_max, unsigned fds_max) {
+MMapCache* mmap_cache_new(void) {
         MMapCache *m;
 
-        assert(contexts_max > 0);
-        assert(fds_max > 0);
-
         m = new0(MMapCache, 1);
         if (!m)
                 return NULL;
 
-        m->contexts_max = contexts_max;
-        m->fds_max = fds_max;
-        m->windows_max = MAX(m->contexts_max, WINDOWS_MAX);
+        m->contexts_max = DEFAULT_CONTEXTS_MAX;
+        m->fds_max = DEFAULT_FDS_MAX;
+        m->windows_max = DEFAULT_WINDOWS_MAX;
         m->n_ref = 1;
         m->lru_first = (unsigned) -1;
         m->lru_last = (unsigned) -1;
@@ -465,8 +465,18 @@ static int mmap_cache_get_fd_index(MMapCache *m, int fd, unsigned *fd_index) {
         if (r != 0)
                 return r;
 
-        if (m->n_fds >= m->fds_max)
-                return -E2BIG;
+        if (m->n_fds >= m->fds_max) {
+                unsigned k;
+                FileDescriptor *n;
+
+                k = m->n_fds * 2;
+                n = realloc(m->by_fd, sizeof(FileDescriptor) * k);
+                if (!n)
+                        return -ENOMEM;
+
+                m->fds_max = k;
+                m->by_fd = n;
+        }
 
         j = m->by_fd + m->n_fds ++;
         j->fd = fd;
@@ -580,10 +590,33 @@ int mmap_cache_get(
 
         assert(m);
         assert(fd >= 0);
-        assert(context < m->contexts_max);
         assert(size > 0);
         assert(ret);
 
+        if (context >= m->contexts_max) {
+                unsigned k, *n;
+                Window *w;
+
+                /* Increase the number of contexts if necessary, and
+                 * make sure we have twice the number of windows */
+
+                k = context * 2;
+                n = realloc(m->by_context, sizeof(unsigned) * k);
+                if (!n)
+                        return -ENOMEM;
+                memset(n + m->contexts_max, -1, (k - m->contexts_max) * sizeof(unsigned));
+                m->contexts_max = k;
+                m->by_context = n;
+
+                k = MAX(m->windows_max, m->contexts_max*2);
+                w = realloc(m->windows, sizeof(Window) * k);
+                if (!w)
+                        return -ENOMEM;
+
+                m->windows_max = k;
+                m->windows = w;
+        }
+
         /* Maybe the current pointer for this context is already the
          * right one? */
         r = mmap_cache_current(m, fd, context, offset, size, ret);
diff --git a/src/journal/mmap-cache.h b/src/journal/mmap-cache.h
index 984b759..aae4544 100644
--- a/src/journal/mmap-cache.h
+++ b/src/journal/mmap-cache.h
@@ -25,7 +25,7 @@
 
 typedef struct MMapCache MMapCache;
 
-MMapCache* mmap_cache_new(unsigned contexts_max, unsigned fds_max);
+MMapCache* mmap_cache_new(void);
 MMapCache* mmap_cache_ref(MMapCache *m);
 MMapCache* mmap_cache_unref(MMapCache *m);
 
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 41526b3..725c979 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -1439,10 +1439,7 @@ static sd_journal *journal_new(int flags, const char *path) {
                 return NULL;
         }
 
-        /* One context for each type, plus the zeroth catchall
-         * context. One fd for each file plus one for each type, which
-         * is need when verifying things */
-        j->mmap = mmap_cache_new(_OBJECT_TYPE_MAX, JOURNAL_FILES_MAX + _OBJECT_TYPE_MAX);
+        j->mmap = mmap_cache_new();
         if (!j->mmap) {
                 hashmap_free(j->files);
                 hashmap_free(j->directories_by_path);

commit fb9a24b6b1ed5b1f42e6e350ccdb7e11800a83bd
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Aug 18 01:45:39 2012 +0200

    journal: even more simple static object tests

diff --git a/src/journal/journal-def.h b/src/journal/journal-def.h
index 45c3cde..8f00176 100644
--- a/src/journal/journal-def.h
+++ b/src/journal/journal-def.h
@@ -188,6 +188,8 @@ _packed_ struct Header {
         /* Added in 189 */
         le64_t n_tags;
         le64_t n_entry_arrays;
+
+        /* Size: 224 */
 };
 
 #define FSS_HEADER_SIGNATURE ((char[]) { 'K', 'S', 'H', 'H', 'R', 'H', 'L', 'P' })
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index e04ffd0..df991a4 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -798,6 +798,14 @@ uint64_t journal_file_entry_array_n_items(Object *o) {
         return (le64toh(o->object.size) - offsetof(Object, entry_array.items)) / sizeof(uint64_t);
 }
 
+uint64_t journal_file_hash_table_n_items(Object *o) {
+        assert(o);
+        assert(o->object.type == OBJECT_DATA_HASH_TABLE ||
+               o->object.type == OBJECT_FIELD_HASH_TABLE);
+
+        return (le64toh(o->object.size) - offsetof(Object, hash_table.items)) / sizeof(HashItem);
+}
+
 static int link_entry_into_array(JournalFile *f,
                                  le64_t *first,
                                  le64_t *idx,
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
index 2d2bf31..e2ef033 100644
--- a/src/journal/journal-file.h
+++ b/src/journal/journal-file.h
@@ -126,6 +126,7 @@ int journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Objec
 
 uint64_t journal_file_entry_n_items(Object *o);
 uint64_t journal_file_entry_array_n_items(Object *o);
+uint64_t journal_file_hash_table_n_items(Object *o);
 
 int journal_file_append_object(JournalFile *f, int type, uint64_t size, Object **ret, uint64_t *offset);
 int journal_file_append_entry(JournalFile *f, const dual_timestamp *ts, const struct iovec iovec[], unsigned n_iovec, uint64_t *seqno, Object **ret, uint64_t *offset);
diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
index e3bd8ff..a318176 100644
--- a/src/journal/journal-verify.c
+++ b/src/journal/journal-verify.c
@@ -134,6 +134,19 @@ static int journal_file_object_verify(JournalFile *f, Object *o) {
                 if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0)
                         return -EBADMSG;
 
+                for (i = 0; i < journal_file_hash_table_n_items(o); i++) {
+                        if (o->hash_table.items[i].head_hash_offset != 0 &&
+                            !VALID64(le64toh(o->hash_table.items[i].head_hash_offset)))
+                                return -EBADMSG;
+                        if (o->hash_table.items[i].tail_hash_offset != 0 &&
+                            !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset)))
+                                return -EBADMSG;
+
+                        if ((o->hash_table.items[i].head_hash_offset != 0) !=
+                            (o->hash_table.items[i].tail_hash_offset != 0))
+                                return -EBADMSG;
+                }
+
                 break;
 
         case OBJECT_ENTRY_ARRAY:
@@ -146,6 +159,11 @@ static int journal_file_object_verify(JournalFile *f, Object *o) {
                 if (!VALID64(o->entry_array.next_entry_array_offset))
                         return -EBADMSG;
 
+                for (i = 0; i < journal_file_entry_array_n_items(o); i++)
+                        if (o->entry_array.items[i] != 0 &&
+                            !VALID64(o->entry_array.items[i]))
+                                return -EBADMSG;
+
                 break;
 
         case OBJECT_TAG:

commit 97147f8c1f63234470a7062d2ed0f999c0996d42
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Aug 18 00:40:48 2012 +0200

    journal: refuse verification of files with unknown flags

diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
index f66b235..e3bd8ff 100644
--- a/src/journal/journal-verify.c
+++ b/src/journal/journal-verify.c
@@ -692,6 +692,8 @@ int journal_file_verify(
         char data_path[] = "/var/tmp/journal-data-XXXXXX",
                 entry_path[] = "/var/tmp/journal-entry-XXXXXX",
                 entry_array_path[] = "/var/tmp/journal-entry-array-XXXXXX";
+        unsigned i;
+        bool found_last;
 
         assert(f);
 
@@ -728,6 +730,24 @@ int journal_file_verify(
         }
         unlink(entry_array_path);
 
+#ifdef HAVE_GCRYPT
+        if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) != 0)
+#else
+        if (f->header->compatible_flags != 0)
+#endif
+        {
+                log_error("Cannot verify file with unknown extensions.");
+                r = -ENOTSUP;
+                goto fail;
+        }
+
+        for (i = 0; i < sizeof(f->header->reserved); i++)
+                if (f->header->reserved[i] != 0) {
+                        log_error("Reserved field in non-zero.");
+                        r = -EBADMSG;
+                        goto fail;
+                }
+
         /* First iteration: we go through all objects, verify the
          * superficial structure, headers, hashes. */
 
@@ -742,12 +762,15 @@ int journal_file_verify(
                         goto fail;
                 }
 
-                if (le64toh(f->header->tail_object_offset) < p) {
+                if (p > le64toh(f->header->tail_object_offset)) {
                         log_error("Invalid tail object pointer");
                         r = -EBADMSG;
                         goto fail;
                 }
 
+                if (p == le64toh(f->header->tail_object_offset))
+                        found_last = true;
+
                 n_objects ++;
 
                 r = journal_file_object_verify(f, o);
@@ -983,6 +1006,12 @@ int journal_file_verify(
                         p = p + ALIGN64(le64toh(o->object.size));
         }
 
+        if (!found_last) {
+                log_error("Tail object pointer dead");
+                r = -EBADMSG;
+                goto fail;
+        }
+
         if (n_objects != le64toh(f->header->n_objects)) {
                 log_error("Object number mismatch");
                 r = -EBADMSG;

commit b72631e59c1b9f62bcfaf1ce3f7e72e4a3beee89
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Aug 18 00:40:03 2012 +0200

    jounral: write bit fiddling test
    
    This test goes through every single bit in a journal file, toggles it,
    and checks if this change is detected by the verification.

diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
index 39cf3a3..f66b235 100644
--- a/src/journal/journal-verify.c
+++ b/src/journal/journal-verify.c
@@ -394,7 +394,8 @@ static int verify_hash_table(
                 int data_fd, uint64_t n_data,
                 int entry_fd, uint64_t n_entries,
                 int entry_array_fd, uint64_t n_entry_arrays,
-                usec_t *last_usec) {
+                usec_t *last_usec,
+                bool show_progress) {
 
         uint64_t i, n;
         int r;
@@ -409,7 +410,8 @@ static int verify_hash_table(
         for (i = 0; i < n; i++) {
                 uint64_t last = 0, p;
 
-                draw_progress(0xC000 + (0x3FFF * i / n), last_usec);
+                if (show_progress)
+                        draw_progress(0xC000 + (0x3FFF * i / n), last_usec);
 
                 p = le64toh(f->data_hash_table[i].head_hash_offset);
                 while (p != 0) {
@@ -535,7 +537,8 @@ static int verify_entry_array(
                 int data_fd, uint64_t n_data,
                 int entry_fd, uint64_t n_entries,
                 int entry_array_fd, uint64_t n_entry_arrays,
-                usec_t *last_usec) {
+                usec_t *last_usec,
+                bool show_progress) {
 
         uint64_t i = 0, a, n, last = 0;
         int r;
@@ -552,7 +555,8 @@ static int verify_entry_array(
                 uint64_t next, m, j;
                 Object *o;
 
-                draw_progress(0x8000 + (0x3FFF * i / n), last_usec);
+                if (show_progress)
+                        draw_progress(0x8000 + (0x3FFF * i / n), last_usec);
 
                 if (a == 0) {
                         log_error("Array chain too short at %llu of %llu",
@@ -674,7 +678,8 @@ static int journal_file_parse_verification_key(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) {
+                usec_t *first_validated, usec_t *last_validated, usec_t *last_contained,
+                bool show_progress) {
         int r;
         Object *o;
         uint64_t p = 0, last_tag = 0, last_epoch = 0, last_tag_realtime = 0;
@@ -728,7 +733,8 @@ int journal_file_verify(
 
         p = le64toh(f->header->header_size);
         while (p != 0) {
-                draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
+                if (show_progress)
+                        draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec);
 
                 r = journal_file_move_to_object(f, -1, p, &o);
                 if (r < 0) {
@@ -891,8 +897,6 @@ int journal_file_verify(
                                 goto fail;
                         }
 
-                        log_debug("Checking tag %llu..", (unsigned long long) le64toh(o->tag.seqnum));
-
                         if (le64toh(o->tag.seqnum) != n_tags + 1) {
                                 log_error("Tag sequence number out of synchronization at %llu", (unsigned long long) p);
                                 r = -EBADMSG;
@@ -1070,7 +1074,8 @@ int journal_file_verify(
                                data_fd, n_data,
                                entry_fd, n_entries,
                                entry_array_fd, n_entry_arrays,
-                               &last_usec);
+                               &last_usec,
+                               show_progress);
         if (r < 0)
                 goto fail;
 
@@ -1078,11 +1083,13 @@ int journal_file_verify(
                               data_fd, n_data,
                               entry_fd, n_entries,
                               entry_array_fd, n_entry_arrays,
-                              &last_usec);
+                              &last_usec,
+                              show_progress);
         if (r < 0)
                 goto fail;
 
-        flush_progress();
+        if (show_progress)
+                flush_progress();
 
         mmap_cache_close_fd(f->mmap, data_fd);
         mmap_cache_close_fd(f->mmap, entry_fd);
@@ -1102,7 +1109,8 @@ int journal_file_verify(
         return 0;
 
 fail:
-        flush_progress();
+        if (show_progress)
+                flush_progress();
 
         log_error("File corruption detected at %s:%llu (of %llu, %llu%%).",
                   f->path,
diff --git a/src/journal/journal-verify.h b/src/journal/journal-verify.h
index e4449c6..a4633ad 100644
--- a/src/journal/journal-verify.h
+++ b/src/journal/journal-verify.h
@@ -23,4 +23,4 @@
 
 #include "journal-file.h"
 
-int journal_file_verify(JournalFile *f, const char *key, usec_t *first_validated, usec_t *last_validated, usec_t *last_contained);
+int journal_file_verify(JournalFile *f, const char *key, usec_t *first_validated, usec_t *last_validated, usec_t *last_contained, bool show_progress);
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index 25f41f6..ba678a2 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -637,7 +637,7 @@ static int verify(sd_journal *j) {
                         log_warning("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
 #endif
 
-                k = journal_file_verify(f, arg_verify_key, &from, &to, &total);
+                k = journal_file_verify(f, arg_verify_key, &from, &to, &total, true);
                 if (k == -EINVAL) {
                         /* If the key was invalid give up right-away. */
                         return k;
@@ -648,7 +648,7 @@ static int verify(sd_journal *j) {
                         char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
                         log_info("PASS: %s", f->path);
 
-                        if (journal_file_fss_enabled(f))
+                        if (arg_verify_key && journal_file_fss_enabled(f))
                                 log_info("=> Validated from %s to %s, %s missing",
                                          format_timestamp(a, sizeof(a), from),
                                          format_timestamp(b, sizeof(b), to),
diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c
index df0a5dd..4e6c119 100644
--- a/src/journal/test-journal-verify.c
+++ b/src/journal/test-journal-verify.c
@@ -27,19 +27,55 @@
 #include "log.h"
 #include "journal-file.h"
 #include "journal-verify.h"
+#include "journal-authenticate.h"
 
 #define N_ENTRIES 6000
 #define RANDOM_RANGE 77
 
+static void bit_toggle(const char *fn, uint64_t p) {
+        uint8_t b;
+        ssize_t r;
+        int fd;
+
+        fd = open(fn, O_RDWR|O_CLOEXEC);
+        assert(fd >= 0);
+
+        r = pread(fd, &b, 1, p/8);
+        assert(r == 1);
+
+        b ^= 1 << (p % 8);
+
+        r = pwrite(fd, &b, 1, p/8);
+        assert(r == 1);
+
+        close_nointr_nofail(fd);
+}
+
+static int raw_verify(const char *fn, const char *verification_key) {
+        JournalFile *f;
+        int r;
+
+        r = journal_file_open(fn, O_RDONLY, 0666, true, true, NULL, NULL, NULL, &f);
+        if (r < 0)
+                return r;
+
+        r = journal_file_verify(f, verification_key, NULL, NULL, NULL, false);
+        journal_file_close(f);
+
+        return r;
+}
+
 int main(int argc, char *argv[]) {
         char t[] = "/tmp/journal-XXXXXX";
         unsigned n;
         JournalFile *f;
         const char *verification_key = argv[1];
-        usec_t from, to, total;
+        usec_t from = 0, to = 0, total = 0;
         char a[FORMAT_TIMESTAMP_MAX];
         char b[FORMAT_TIMESTAMP_MAX];
         char c[FORMAT_TIMESPAN_MAX];
+        struct stat st;
+        uint64_t p;
 
         log_set_max_level(LOG_DEBUG);
 
@@ -71,19 +107,36 @@ int main(int argc, char *argv[]) {
 
         log_info("Verifying...");
 
-        assert_se(journal_file_open("test.journal", O_RDONLY, 0666, false, false, NULL, NULL, NULL, &f) == 0);
-
+        assert_se(journal_file_open("test.journal", O_RDONLY, 0666, true, true, NULL, NULL, NULL, &f) == 0);
         journal_file_print_header(f);
 
-        assert_se(journal_file_verify(f, verification_key, &from, &to, &total) >= 0);
-
-        log_info("=> Validated from %s to %s, %s missing",
-                 format_timestamp(a, sizeof(a), from),
-                 format_timestamp(b, sizeof(b), to),
-                 format_timespan(c, sizeof(c), total > to ? total - to : 0));
+        assert_se(journal_file_verify(f, verification_key, &from, &to, &total, true) >= 0);
 
+        if (verification_key && journal_file_fss_enabled(f)) {
+                log_info("=> Validated from %s to %s, %s missing",
+                         format_timestamp(a, sizeof(a), from),
+                         format_timestamp(b, sizeof(b), to),
+                         format_timespan(c, sizeof(c), total > to ? total - to : 0));
+        }
         journal_file_close(f);
 
+        log_info("Toggling bits...");
+
+        assert_se(stat("test.journal", &st) >= 0);
+
+        for (p = 240*8; p < ((uint64_t) st.st_size * 8); p ++) {
+                bit_toggle("test.journal", p);
+
+                log_info("[ %llu+%llu]", (unsigned long long) p / 8, (unsigned long long) p % 8);
+
+                if (raw_verify("test.journal", verification_key) >= 0) {
+                        log_notice(ANSI_HIGHLIGHT_RED_ON ">>>> %llu (bit %llu) can be toggled without detection." ANSI_HIGHLIGHT_OFF, (unsigned long long) p / 8, (unsigned long long) p % 8);
+                        sleep(1);
+                }
+
+                bit_toggle("test.journal", p);
+        }
+
         log_info("Exiting...");
 
         assert_se(rm_rf_dangerous(t, false, true, false) >= 0);

commit c586dbf110abdbf0317bdd0f0a5900d709194409
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Aug 18 00:38:57 2012 +0200

    journal: fix verification without key

diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 3cf28a7..e04ffd0 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -65,7 +65,7 @@ void journal_file_close(JournalFile *f) {
         assert(f);
 
         /* Write the final tag */
-        if (f->seal)
+        if (f->seal && f->writable)
                 journal_file_append_tag(f);
 
         /* Sync everything to disk, before we mark the file offline */
@@ -252,7 +252,9 @@ static int journal_file_verify_header(JournalFile *f) {
         }
 
         f->compress = !!(le32toh(f->header->incompatible_flags) & HEADER_INCOMPATIBLE_COMPRESSED);
-        f->seal = !!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED);
+
+        if (f->writable)
+                f->seal = !!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED);
 
         return 0;
 }
diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
index 7be0d2e..39cf3a3 100644
--- a/src/journal/journal-verify.c
+++ b/src/journal/journal-verify.c
@@ -696,7 +696,8 @@ int journal_file_verify(
                         log_error("Failed to parse seed.");
                         return r;
                 }
-        }
+        } else if (f->seal)
+                return -ENOKEY;
 
         data_fd = mkostemp(data_path, O_CLOEXEC);
         if (data_fd < 0) {
@@ -904,60 +905,65 @@ int journal_file_verify(
                                 goto fail;
                         }
 
-                        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;
-                        }
-
-                        /* OK, now we know the epoch. So let's now set
-                         * it, and calculate the HMAC for everything
-                         * since the last tag. */
-                        r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
-                        if (r < 0)
-                                goto fail;
+                        if (f->seal) {
+                                log_debug("Checking tag %llu..", (unsigned long long) le64toh(o->tag.seqnum));
 
-                        r = journal_file_hmac_start(f);
-                        if (r < 0)
-                                goto fail;
+                                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;
+                                }
 
-                        if (last_tag == 0) {
-                                r = journal_file_hmac_put_header(f);
+                                /* OK, now we know the epoch. So let's now set
+                                 * it, and calculate the HMAC for everything
+                                 * since the last tag. */
+                                r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
                                 if (r < 0)
                                         goto fail;
 
-                                q = le64toh(f->header->header_size);
-                        } else
-                                q = last_tag;
-
-                        while (q <= p) {
-                                r = journal_file_move_to_object(f, -1, q, &o);
+                                r = journal_file_hmac_start(f);
                                 if (r < 0)
                                         goto fail;
 
-                                r = journal_file_hmac_put_object(f, -1, q);
+                                if (last_tag == 0) {
+                                        r = journal_file_hmac_put_header(f);
+                                        if (r < 0)
+                                                goto fail;
+
+                                        q = le64toh(f->header->header_size);
+                                } else
+                                        q = last_tag;
+
+                                while (q <= p) {
+                                        r = journal_file_move_to_object(f, -1, q, &o);
+                                        if (r < 0)
+                                                goto fail;
+
+                                        r = journal_file_hmac_put_object(f, -1, q);
+                                        if (r < 0)
+                                                goto fail;
+
+                                        q = q + ALIGN64(le64toh(o->object.size));
+                                }
+
+                                /* Position might have changed, let's reposition things */
+                                r = journal_file_move_to_object(f, -1, p, &o);
                                 if (r < 0)
                                         goto fail;
 
-                                q = q + ALIGN64(le64toh(o->object.size));
-                        }
-
-                        /* Position might have changed, let's reposition things */
-                        r = journal_file_move_to_object(f, -1, p, &o);
-                        if (r < 0)
-                                goto fail;
+                                if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
+                                        log_error("Tag failed verification at %llu", (unsigned long long) p);
+                                        r = -EBADMSG;
+                                        goto fail;
+                                }
 
-                        if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
-                                log_error("Tag failed verification at %llu", (unsigned long long) p);
-                                r = -EBADMSG;
-                                goto fail;
+                                f->hmac_running = false;
+                                last_tag_realtime = rt;
                         }
 
-                        f->hmac_running = false;
-
                         last_tag = p + ALIGN64(le64toh(o->object.size));
-                        last_tag_realtime = rt;
+                        last_epoch = le64toh(o->tag.epoch);
 
                         n_tags ++;
                         break;
@@ -1087,7 +1093,7 @@ int journal_file_verify(
         close_nointr_nofail(entry_array_fd);
 
         if (first_validated)
-                *first_validated = le64toh(f->header->head_entry_realtime);
+                *first_validated = last_tag_realtime ? le64toh(f->header->head_entry_realtime) : 0;
         if (last_validated)
                 *last_validated = last_tag_realtime;
         if (last_contained)

commit db11ac1ab56bc13514a029e7d126c5efe2c68bc2
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sat Aug 18 00:37:21 2012 +0200

    journald: add additional simple static tests to verifier

diff --git a/src/journal/journal-def.h b/src/journal/journal-def.h
index 52c55ab..45c3cde 100644
--- a/src/journal/journal-def.h
+++ b/src/journal/journal-def.h
@@ -140,9 +140,10 @@ union Object {
 };
 
 enum {
-        STATE_OFFLINE,
-        STATE_ONLINE,
-        STATE_ARCHIVED
+        STATE_OFFLINE = 0,
+        STATE_ONLINE = 1,
+        STATE_ARCHIVED = 2,
+        _STATE_MAX
 };
 
 /* Header flags */
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 08d4285..3cf28a7 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -203,6 +203,9 @@ static int journal_file_verify_header(JournalFile *f) {
 #endif
         }
 
+        if (f->header->state >= _STATE_MAX)
+                return -EBADMSG;
+
         /* The first addition was n_data, so check that we are at least this large */
         if (le64toh(f->header->header_size) < HEADER_SIZE_MIN)
                 return -EBADMSG;
@@ -211,7 +214,16 @@ static int journal_file_verify_header(JournalFile *f) {
                 !JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays))
                 return -EBADMSG;
 
-        if ((uint64_t) f->last_stat.st_size < (le64toh(f->header->header_size) + le64toh(f->header->arena_size)))
+        if ((le64toh(f->header->header_size) + le64toh(f->header->arena_size)) > (uint64_t) f->last_stat.st_size)
+                return -ENODATA;
+
+        if (le64toh(f->header->tail_object_offset) > (le64toh(f->header->header_size) + le64toh(f->header->arena_size)))
+                return -ENODATA;
+
+        if (!VALID64(f->header->data_hash_table_offset) ||
+            !VALID64(f->header->field_hash_table_offset) ||
+            !VALID64(f->header->tail_object_offset) ||
+            !VALID64(f->header->entry_array_offset))
                 return -ENODATA;
 
         if (f->writable) {
@@ -351,6 +363,10 @@ int journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Objec
         assert(f);
         assert(ret);
 
+        /* Objects may only be located at multiple of 64 bit */
+        if (!VALID64(offset))
+                return -EFAULT;
+
         /* One context for each type, plus one catch-all for the rest */
         context = type > 0 && type < _OBJECT_TYPE_MAX ? type : 0;
 
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
index 58de214..2d2bf31 100644
--- a/src/journal/journal-file.h
+++ b/src/journal/journal-file.h
@@ -117,6 +117,7 @@ int journal_file_open_reliably(
                 JournalFile **ret);
 
 #define ALIGN64(x) (((x) + 7ULL) & ~7ULL)
+#define VALID64(x) (((x) & 7ULL) == 0ULL)
 
 #define JOURNAL_HEADER_CONTAINS(h, field) \
         (le64toh((h)->header_size) >= offsetof(Header, field) + sizeof((h)->field))
diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
index f9a930e..7be0d2e 100644
--- a/src/journal/journal-verify.c
+++ b/src/journal/journal-verify.c
@@ -45,6 +45,8 @@
  * */
 
 static int journal_file_object_verify(JournalFile *f, Object *o) {
+        uint64_t i;
+
         assert(f);
         assert(o);
 
@@ -87,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:
@@ -106,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:
@@ -125,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:

commit a0108012974558c5a7dcf8c76456be6a07b0e95d
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Aug 17 22:10:36 2012 +0200

    journal: be fine with opening rotated/corrupted journal files

diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 4d7a6ff..08d4285 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -1957,7 +1957,8 @@ int journal_file_open(
             (flags & O_ACCMODE) != O_RDWR)
                 return -EINVAL;
 
-        if (!endswith(fname, ".journal"))
+        if (!endswith(fname, ".journal") &&
+            !endswith(fname, ".journal~"))
                 return -EINVAL;
 
         f = new0(JournalFile, 1);

commit f982e6f7612401a9a789bb8f40d2adca34c85c10
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Aug 17 22:10:11 2012 +0200

    journal: set secure deletion flags for FSS file

diff --git a/TODO b/TODO
index 102a813..875a3db 100644
--- a/TODO
+++ b/TODO
@@ -49,6 +49,8 @@ Bugfixes:
 
 Features:
 
+* man: document in ExecStart= explicitly that we don't take shell command lines, only executable names with arguments
+
 * shutdown: don't read-only mount anything when running in container
 
 * nspawn: --read-only is not applied recursively to submounts
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index 5c21ab0..25f41f6 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -30,6 +30,8 @@
 #include <time.h>
 #include <getopt.h>
 #include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
 
 #include <systemd/sd-journal.h>
 
@@ -453,7 +455,7 @@ static int setup_keys(void) {
         size_t mpk_size, seed_size, state_size, i;
         uint8_t *mpk, *seed, *state;
         ssize_t l;
-        int fd = -1, r;
+        int fd = -1, r, attr = 0;
         sd_id128_t machine, boot;
         char *p = NULL, *k = NULL;
         struct FSSHeader h;
@@ -530,6 +532,16 @@ static int setup_keys(void) {
                 goto finish;
         }
 
+        /* Enable secure remove, exclusion from dump, synchronous
+         * writing and in-place updating */
+        if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
+                log_warning("FS_IOC_GETFLAGS failed: %m");
+
+        attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
+
+        if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
+                log_warning("FS_IOC_SETFLAGS failed: %m");
+
         zero(h);
         memcpy(h.signature, "KSHHRHLP", 8);
         h.machine_id = machine;



More information about the systemd-commits mailing list