1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include "journal-def.h"
26 #include "journal-file.h"
27 #include "journal-authenticate.h"
30 static uint64_t journal_file_tag_seqnum(JournalFile *f) {
35 r = le64toh(f->header->n_tags) + 1;
36 f->header->n_tags = htole64(r);
41 int journal_file_append_tag(JournalFile *f) {
54 log_debug("Writing tag for epoch %llu\n", (unsigned long long) FSPRG_GetEpoch(f->fsprg_state));
58 r = journal_file_append_object(f, OBJECT_TAG, sizeof(struct TagObject), &o, &p);
62 o->tag.seqnum = htole64(journal_file_tag_seqnum(f));
63 o->tag.epoch = htole64(FSPRG_GetEpoch(f->fsprg_state));
65 /* Add the tag object itself, so that we can protect its
66 * header. This will exclude the actual hash value in it */
67 r = journal_file_hmac_put_object(f, OBJECT_TAG, p);
71 /* Get the HMAC tag and store it in the object */
72 memcpy(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH);
73 f->hmac_running = false;
78 int journal_file_hmac_start(JournalFile *f) {
79 uint8_t key[256 / 8]; /* Let's pass 256 bit from FSPRG to HMAC */
88 /* Prepare HMAC for next cycle */
89 gcry_md_reset(f->hmac);
90 FSPRG_GetKey(f->fsprg_state, key, sizeof(key), 0);
91 gcry_md_setkey(f->hmac, key, sizeof(key));
93 f->hmac_running = true;
98 static int journal_file_get_epoch(JournalFile *f, uint64_t realtime, uint64_t *epoch) {
105 if (f->fss_start_usec == 0 ||
106 f->fss_interval_usec == 0)
109 if (realtime < f->fss_start_usec)
112 t = realtime - f->fss_start_usec;
113 t = t / f->fss_interval_usec;
119 static int journal_file_fsprg_need_evolve(JournalFile *f, uint64_t realtime) {
120 uint64_t goal, epoch;
127 r = journal_file_get_epoch(f, realtime, &goal);
131 epoch = FSPRG_GetEpoch(f->fsprg_state);
135 return epoch != goal;
138 int journal_file_fsprg_evolve(JournalFile *f, uint64_t realtime) {
139 uint64_t goal, epoch;
147 r = journal_file_get_epoch(f, realtime, &goal);
151 epoch = FSPRG_GetEpoch(f->fsprg_state);
153 log_debug("Evolving FSPRG key from epoch %llu to %llu.", (unsigned long long) epoch, (unsigned long long) goal);
161 FSPRG_Evolve(f->fsprg_state);
162 epoch = FSPRG_GetEpoch(f->fsprg_state);
166 int journal_file_fsprg_seek(JournalFile *f, uint64_t goal) {
175 assert(f->fsprg_seed);
177 if (f->fsprg_state) {
180 epoch = FSPRG_GetEpoch(f->fsprg_state);
184 if (goal == epoch+1) {
185 FSPRG_Evolve(f->fsprg_state);
189 f->fsprg_state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
190 f->fsprg_state = malloc(f->fsprg_state_size);
196 log_debug("Seeking FSPRG key to %llu.", (unsigned long long) goal);
198 msk = alloca(FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR));
199 FSPRG_GenMK(msk, NULL, f->fsprg_seed, f->fsprg_seed_size, FSPRG_RECOMMENDED_SECPAR);
200 FSPRG_Seek(f->fsprg_state, goal, msk, f->fsprg_seed, f->fsprg_seed_size);
204 int journal_file_maybe_append_tag(JournalFile *f, uint64_t realtime) {
212 r = journal_file_fsprg_need_evolve(f, realtime);
216 r = journal_file_append_tag(f);
220 r = journal_file_fsprg_evolve(f, realtime);
224 r = journal_file_hmac_start(f);
231 int journal_file_hmac_put_object(JournalFile *f, int type, uint64_t p) {
240 r = journal_file_hmac_start(f);
244 r = journal_file_move_to_object(f, type, p, &o);
248 gcry_md_write(f->hmac, o, offsetof(ObjectHeader, payload));
250 switch (o->object.type) {
253 /* All but hash and payload are mutable */
254 gcry_md_write(f->hmac, &o->data.hash, sizeof(o->data.hash));
255 gcry_md_write(f->hmac, o->data.payload, le64toh(o->object.size) - offsetof(DataObject, payload));
260 gcry_md_write(f->hmac, &o->entry.seqnum, le64toh(o->object.size) - offsetof(EntryObject, seqnum));
263 case OBJECT_FIELD_HASH_TABLE:
264 case OBJECT_DATA_HASH_TABLE:
265 case OBJECT_ENTRY_ARRAY:
266 /* Nothing: everything is mutable */
270 /* All but the tag itself */
271 gcry_md_write(f->hmac, &o->tag.seqnum, sizeof(o->tag.seqnum));
272 gcry_md_write(f->hmac, &o->tag.epoch, sizeof(o->tag.epoch));
281 int journal_file_hmac_put_header(JournalFile *f) {
289 r = journal_file_hmac_start(f);
293 /* All but state+reserved, boot_id, arena_size,
294 * tail_object_offset, n_objects, n_entries,
295 * tail_entry_seqnum, head_entry_seqnum, entry_array_offset,
296 * head_entry_realtime, tail_entry_realtime,
297 * tail_entry_monotonic, n_data, n_fields, n_tags,
300 gcry_md_write(f->hmac, f->header->signature, offsetof(Header, state) - offsetof(Header, signature));
301 gcry_md_write(f->hmac, &f->header->file_id, offsetof(Header, boot_id) - offsetof(Header, file_id));
302 gcry_md_write(f->hmac, &f->header->seqnum_id, offsetof(Header, arena_size) - offsetof(Header, seqnum_id));
303 gcry_md_write(f->hmac, &f->header->data_hash_table_offset, offsetof(Header, tail_object_offset) - offsetof(Header, data_hash_table_offset));
308 int journal_file_fss_load(JournalFile *f) {
320 r = sd_id128_get_machine(&machine);
324 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
325 SD_ID128_FORMAT_VAL(machine)) < 0)
328 fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
330 log_error("Failed to open %s: %m", p);
335 if (fstat(fd, &st) < 0) {
340 if (st.st_size < (off_t) sizeof(FSSHeader)) {
345 m = mmap(NULL, PAGE_ALIGN(sizeof(FSSHeader)), PROT_READ, MAP_SHARED, fd, 0);
346 if (m == MAP_FAILED) {
352 if (memcmp(m->signature, FSS_HEADER_SIGNATURE, 8) != 0) {
357 if (m->incompatible_flags != 0) {
358 r = -EPROTONOSUPPORT;
362 if (le64toh(m->header_size) < sizeof(FSSHeader)) {
367 if (le64toh(m->fsprg_state_size) != FSPRG_stateinbytes(m->fsprg_secpar)) {
372 f->fss_file_size = le64toh(m->header_size) + le64toh(m->fsprg_state_size);
373 if ((uint64_t) st.st_size < f->fss_file_size) {
378 if (!sd_id128_equal(machine, m->machine_id)) {
383 if (le64toh(m->start_usec) <= 0 ||
384 le64toh(m->interval_usec) <= 0) {
389 f->fss_file = mmap(NULL, PAGE_ALIGN(f->fss_file_size), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
390 if (f->fss_file == MAP_FAILED) {
396 f->fss_start_usec = le64toh(f->fss_file->start_usec);
397 f->fss_interval_usec = le64toh(f->fss_file->interval_usec);
399 f->fsprg_state = (uint8_t*) f->fss_file + le64toh(f->fss_file->header_size);
400 f->fsprg_state_size = le64toh(f->fss_file->fsprg_state_size);
406 munmap(m, PAGE_ALIGN(sizeof(FSSHeader)));
409 close_nointr_nofail(fd);
415 int journal_file_hmac_setup(JournalFile *f) {
421 e = gcry_md_open(&f->hmac, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
428 int journal_file_append_first_tag(JournalFile *f) {
435 log_debug("Calculating first tag...");
437 r = journal_file_hmac_put_header(f);
441 p = le64toh(f->header->field_hash_table_offset);
442 if (p < offsetof(Object, hash_table.items))
444 p -= offsetof(Object, hash_table.items);
446 r = journal_file_hmac_put_object(f, OBJECT_FIELD_HASH_TABLE, p);
450 p = le64toh(f->header->data_hash_table_offset);
451 if (p < offsetof(Object, hash_table.items))
453 p -= offsetof(Object, hash_table.items);
455 r = journal_file_hmac_put_object(f, OBJECT_DATA_HASH_TABLE, p);
459 r = journal_file_append_tag(f);
466 bool journal_file_fss_enabled(JournalFile *f) {
469 return !!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED);