void journal_file_close(JournalFile *f) {
assert(f);
+#ifdef HAVE_GCRYPT
/* Write the final tag */
- if (f->authenticate)
+ if (f->seal && f->writable)
journal_file_append_tag(f);
+#endif
/* Sync everything to disk, before we mark the file offline */
if (f->mmap && f->fd >= 0)
#endif
#ifdef HAVE_GCRYPT
- if (f->fsprg_file)
- munmap(f->fsprg_file, PAGE_ALIGN(f->fsprg_file_size));
+ if (f->fss_file)
+ munmap(f->fss_file, PAGE_ALIGN(f->fss_file_size));
else if (f->fsprg_state)
free(f->fsprg_state);
htole32(f->compress ? HEADER_INCOMPATIBLE_COMPRESSED : 0);
h.compatible_flags =
- htole32(f->authenticate ? HEADER_COMPATIBLE_AUTHENTICATED : 0);
+ htole32(f->seal ? HEADER_COMPATIBLE_SEALED : 0);
r = sd_id128_randomize(&h.file_id);
if (r < 0)
* compatible flags, too */
if (f->writable) {
#ifdef HAVE_GCRYPT
- if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_AUTHENTICATED) != 0)
+ if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) != 0)
return -EPROTONOSUPPORT;
#else
if (f->header->compatible_flags != 0)
#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;
- if ((le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_AUTHENTICATED) &&
- !JOURNAL_HEADER_CONTAINS(f->header, n_tags))
+ if (JOURNAL_HEADER_SEALED(f->header) && !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) {
}
}
- f->compress = !!(le32toh(f->header->incompatible_flags) & HEADER_INCOMPATIBLE_COMPRESSED);
- f->authenticate = !!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_AUTHENTICATED);
+ f->compress = JOURNAL_HEADER_COMPRESSED(f->header);
+
+ if (f->writable)
+ f->seal = JOURNAL_HEADER_SEALED(f->header);
return 0;
}
if (r != 0)
return -r;
- mmap_cache_close_fd_range(f->mmap, f->fd, old_size);
-
if (fstat(f->fd, &f->last_stat) < 0)
return -errno;
return 0;
}
-static int journal_file_move_to(JournalFile *f, int context, uint64_t offset, uint64_t size, void **ret) {
+static int journal_file_move_to(JournalFile *f, int context, bool keep_always, uint64_t offset, uint64_t size, void **ret) {
assert(f);
assert(ret);
return -EADDRNOTAVAIL;
}
- return mmap_cache_get(f->mmap, f->fd, f->prot, context, offset, size, ret);
+ return mmap_cache_get(f->mmap, f->fd, f->prot, context, keep_always, offset, size, &f->last_stat, ret);
}
static uint64_t minimum_header_size(Object *o) {
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;
- r = journal_file_move_to(f, context, offset, sizeof(ObjectHeader), &t);
+ r = journal_file_move_to(f, context, false, offset, sizeof(ObjectHeader), &t);
if (r < 0)
return r;
return -EBADMSG;
if (s > sizeof(ObjectHeader)) {
- r = journal_file_move_to(f, o->object.type, offset, s, &t);
+ r = journal_file_move_to(f, o->object.type, false, offset, s, &t);
if (r < 0)
return r;
if (r < 0)
return r;
- r = journal_file_move_to(f, type, p, size, &t);
+ r = journal_file_move_to(f, type, false, p, size, &t);
if (r < 0)
return r;
r = journal_file_move_to(f,
OBJECT_DATA_HASH_TABLE,
+ true,
p, s,
&t);
if (r < 0)
r = journal_file_move_to(f,
OBJECT_FIELD_HASH_TABLE,
+ true,
p, s,
&t);
if (r < 0)
if (r < 0)
return r;
+#ifdef HAVE_GCRYPT
r = journal_file_hmac_put_object(f, OBJECT_DATA, p);
if (r < 0)
return r;
+#endif
/* The linking might have altered the window, so let's
* refresh our pointer */
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,
if (r < 0)
return r;
+#ifdef HAVE_GCRYPT
r = journal_file_hmac_put_object(f, OBJECT_ENTRY_ARRAY, q);
if (r < 0)
return r;
+#endif
o->entry_array.items[i] = htole64(p);
o->entry.xor_hash = htole64(xor_hash);
o->entry.boot_id = f->header->boot_id;
+#ifdef HAVE_GCRYPT
r = journal_file_hmac_put_object(f, OBJECT_ENTRY, np);
if (r < 0)
return r;
+#endif
r = journal_file_link_entry(f, o, np);
if (r < 0)
ts->monotonic < le64toh(f->header->tail_entry_monotonic))
return -EINVAL;
+#ifdef HAVE_GCRYPT
r = journal_file_maybe_append_tag(f, ts->realtime);
if (r < 0)
return r;
+#endif
/* alloca() can't take 0, hence let's allocate at least one */
items = alloca(sizeof(EntryItem) * MAX(1, n_iovec));
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));
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;
}
"Arena size: %llu\n"
"Data Hash Table Size: %llu\n"
"Field Hash Table Size: %llu\n"
- "Objects: %llu\n"
- "Entry Objects: %llu\n"
"Rotate Suggested: %s\n"
"Head Sequential Number: %llu\n"
"Tail Sequential Number: %llu\n"
"Head Realtime Timestamp: %s\n"
- "Tail Realtime Timestamp: %s\n",
+ "Tail Realtime Timestamp: %s\n"
+ "Objects: %llu\n"
+ "Entry Objects: %llu\n",
f->path,
sd_id128_to_string(f->header->file_id, a),
sd_id128_to_string(f->header->machine_id, b),
sd_id128_to_string(f->header->boot_id, c),
sd_id128_to_string(f->header->seqnum_id, c),
- 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_AUTHENTICATED) ? " AUTHENTICATED" : "",
- (f->header->compatible_flags & ~HEADER_COMPATIBLE_AUTHENTICATED) ? " ???" : "",
- (f->header->incompatible_flags & HEADER_INCOMPATIBLE_COMPRESSED) ? " COMPRESSED" : "",
- (f->header->incompatible_flags & ~HEADER_INCOMPATIBLE_COMPRESSED) ? " ???" : "",
+ 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" : "",
+ (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),
(unsigned long long) le64toh(f->header->field_hash_table_size) / sizeof(HashItem),
- (unsigned long long) le64toh(f->header->n_objects),
- (unsigned long long) le64toh(f->header->n_entries),
yes_no(journal_file_rotate_suggested(f)),
(unsigned long long) le64toh(f->header->head_entry_seqnum),
(unsigned long long) le64toh(f->header->tail_entry_seqnum),
format_timestamp(x, sizeof(x), le64toh(f->header->head_entry_realtime)),
- format_timestamp(y, sizeof(y), le64toh(f->header->tail_entry_realtime)));
+ format_timestamp(y, sizeof(y), le64toh(f->header->tail_entry_realtime)),
+ (unsigned long long) le64toh(f->header->n_objects),
+ (unsigned long long) le64toh(f->header->n_entries));
if (JOURNAL_HEADER_CONTAINS(f->header, n_data))
printf("Data Objects: %llu\n"
"Field Hash Table Fill: %.1f%%\n",
(unsigned long long) le64toh(f->header->n_fields),
100.0 * (double) le64toh(f->header->n_fields) / ((double) (le64toh(f->header->field_hash_table_size) / sizeof(HashItem))));
+
+ if (JOURNAL_HEADER_CONTAINS(f->header, n_tags))
+ printf("Tag Objects: %llu\n",
+ (unsigned long long) le64toh(f->header->n_tags));
+ if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays))
+ printf("Entry Array Objects: %llu\n",
+ (unsigned long long) le64toh(f->header->n_entry_arrays));
}
int journal_file_open(
int flags,
mode_t mode,
bool compress,
- bool authenticate,
+ bool seal,
JournalMetrics *metrics,
MMapCache *mmap_cache,
JournalFile *template,
(flags & O_ACCMODE) != O_RDWR)
return -EINVAL;
- if (!endswith(fname, ".journal"))
+ if (!endswith(fname, ".journal") &&
+ !endswith(fname, ".journal~"))
return -EINVAL;
f = new0(JournalFile, 1);
f->prot = prot_from_flags(flags);
f->writable = (flags & O_ACCMODE) != O_RDONLY;
f->compress = compress;
- f->authenticate = authenticate;
+ f->seal = seal;
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;
if (f->last_stat.st_size == 0 && f->writable) {
newly_created = true;
+#ifdef HAVE_GCRYPT
/* Try to load the FSPRG state, and if we can't, then
- * just don't do authentication */
- r = journal_file_load_fsprg(f);
+ * just don't do sealing */
+ r = journal_file_fss_load(f);
if (r < 0)
- f->authenticate = false;
+ f->seal = false;
+#endif
r = journal_file_init_header(f, template);
if (r < 0)
goto fail;
}
+#ifdef HAVE_GCRYPT
if (!newly_created && f->writable) {
- r = journal_file_load_fsprg(f);
+ r = journal_file_fss_load(f);
if (r < 0)
goto fail;
}
+#endif
if (f->writable) {
if (metrics) {
goto fail;
}
- r = journal_file_setup_hmac(f);
+#ifdef HAVE_GCRYPT
+ r = journal_file_hmac_setup(f);
if (r < 0)
goto fail;
+#endif
if (newly_created) {
r = journal_file_setup_field_hash_table(f);
if (r < 0)
goto fail;
+#ifdef HAVE_GCRYPT
r = journal_file_append_first_tag(f);
if (r < 0)
goto fail;
+#endif
}
r = journal_file_map_field_hash_table(f);
return r;
}
-int journal_file_rotate(JournalFile **f, bool compress, bool authenticate) {
+int journal_file_rotate(JournalFile **f, bool compress, bool seal) {
char *p;
size_t l;
JournalFile *old_file, *new_file = NULL;
old_file->header->state = STATE_ARCHIVED;
- r = journal_file_open(old_file->path, old_file->flags, old_file->mode, compress, authenticate, NULL, old_file->mmap, old_file, &new_file);
+ r = journal_file_open(old_file->path, old_file->flags, old_file->mode, compress, seal, NULL, old_file->mmap, old_file, &new_file);
journal_file_close(old_file);
*f = new_file;
int flags,
mode_t mode,
bool compress,
- bool authenticate,
+ bool seal,
JournalMetrics *metrics,
MMapCache *mmap_cache,
JournalFile *template,
size_t l;
char *p;
- r = journal_file_open(fname, flags, mode, compress, authenticate,
+ r = journal_file_open(fname, flags, mode, compress, seal,
metrics, mmap_cache, template, ret);
if (r != -EBADMSG && /* corrupted */
r != -ENODATA && /* truncated */
log_warning("File %s corrupted or uncleanly shut down, renaming and replacing.", fname);
- return journal_file_open(fname, flags, mode, compress, authenticate,
+ return journal_file_open(fname, flags, mode, compress, seal,
metrics, mmap_cache, template, ret);
}