journal: limit decompress_blob() output to DATA_SIZE_MAX (#41604)
We already have checks in place during compression that limit the data
we compress, so they shouldn't decompress to anything larger than
DATA_SIZE_MAX unless they've been tampered with. Let's make this
explicit and limit all our decompress_blob() calls in journal-handling
code to that limit.
One possible scenario this should prevent is when one tries to open and
verify a journal file that contains a compression bomb in its payload:
```
$ ls -lh test.journal
-rw-rw-r--+ 1 fsumsal fsumsal 1.2M Apr 12 15:07 test.journal
$ systemd-run --user --wait --pipe -- build-local/journalctl --verify --file=$PWD/test.journal
Running as unit: run-p682422-i4875779.service
000110: Invalid hash (00000000 vs. 11e4948d73bdafdd)
000110: Invalid object contents: Bad message
File corruption detected at /home/fsumsal/repos/@systemd/systemd/test.journal:272 (of 1249896 bytes, 0%).
FAIL: /home/fsumsal/repos/@systemd/systemd/test.journal (Bad message)
Finished with result: exit-code
Main processes terminated with: code=exited, status=1/FAILURE
Service runtime: 48.051s
CPU time consumed: 47.941s
Memory peak: 8G (swap: 0B)
```
Same could be, in theory, possible with just `journalctl --file=`, but
the reproducer would be a bit more complicated (haven't tried it, yet).
Lastly, the change in journal-remote is mostly hardening, as the maximum
input size to decompress_blob() there is mandated by MHD's connection
memory limit (set to JOURNAL_SERVER_MEMORY_MAX which is 128 KiB at the
time of writing), so the possible output size there is already quite
limited (e.g. ~800 - 900 MiB for xz-compressed data).
This commit is contained in:
@@ -757,6 +757,8 @@ static int decompress_blob_lz4(
|
||||
size = unaligned_read_le64(src);
|
||||
if (size < 0 || (unsigned) size != unaligned_read_le64(src))
|
||||
return -EFBIG;
|
||||
if (dst_max > 0 && (size_t) size > dst_max)
|
||||
return -ENOBUFS;
|
||||
out = greedy_realloc(dst, size, 1);
|
||||
if (!out)
|
||||
return -ENOMEM;
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
#include "install.h"
|
||||
#include "iterator.h"
|
||||
#include "job.h"
|
||||
#include "journal-importer.h"
|
||||
#include "journal-def.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "log-context.h"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "conf-parser.h"
|
||||
#include "coredump-config.h"
|
||||
#include "format-util.h"
|
||||
#include "journal-importer.h"
|
||||
#include "journal-def.h"
|
||||
#include "log.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
|
||||
@@ -286,7 +286,7 @@ static int process_http_upload(
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
size_t buf_size;
|
||||
|
||||
r = decompress_blob(source->compression, upload_data, *upload_data_size, (void **) &buf, &buf_size, 0);
|
||||
r = decompress_blob(source->compression, upload_data, *upload_data_size, (void **) &buf, &buf_size, DATA_SIZE_MAX);
|
||||
if (r < 0)
|
||||
return mhd_respondf(connection, r, MHD_HTTP_BAD_REQUEST, "Decompression of received blob failed.");
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
#include "iovec-util.h"
|
||||
#include "journal-importer.h"
|
||||
#include "journal-internal.h"
|
||||
#include "journald-client.h"
|
||||
#include "journald-console.h"
|
||||
|
||||
@@ -6,6 +6,21 @@
|
||||
#include "sd-forward.h"
|
||||
#include "sparse-endian.h"
|
||||
|
||||
/* Make sure not to make this smaller than the maximum coredump size.
|
||||
* See JOURNAL_SIZE_MAX in coredump-config.h */
|
||||
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
#define ENTRY_SIZE_MAX (1024*1024*770u)
|
||||
#define ENTRY_SIZE_UNPRIV_MAX (1024*1024*32u)
|
||||
#define DATA_SIZE_MAX (1024*1024*768u)
|
||||
#else
|
||||
#define ENTRY_SIZE_MAX (1024*1024*13u)
|
||||
#define ENTRY_SIZE_UNPRIV_MAX (1024*1024*8u)
|
||||
#define DATA_SIZE_MAX (1024*1024*11u)
|
||||
#endif
|
||||
|
||||
/* The maximum number of fields in an entry */
|
||||
#define ENTRY_FIELD_COUNT_MAX 1024u
|
||||
|
||||
/*
|
||||
* If you change this file you probably should also change its documentation:
|
||||
*
|
||||
|
||||
@@ -1971,7 +1971,7 @@ static int maybe_decompress_payload(
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = decompress_blob(compression, payload, size, &f->compress_buffer, &rsize, 0);
|
||||
r = decompress_blob(compression, payload, size, &f->compress_buffer, &rsize, DATA_SIZE_MAX);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ static int hash_payload(JournalFile *f, Object *o, uint64_t offset, const uint8_
|
||||
_cleanup_free_ void *b = NULL;
|
||||
size_t b_size;
|
||||
|
||||
r = decompress_blob(c, src, size, &b, &b_size, 0);
|
||||
r = decompress_blob(c, src, size, &b, &b_size, DATA_SIZE_MAX);
|
||||
if (r < 0) {
|
||||
error_errno(offset, r, "%s decompression failed: %m",
|
||||
compression_to_string(c));
|
||||
|
||||
@@ -8,22 +8,8 @@
|
||||
#include "iovec-wrapper.h"
|
||||
#include "time-util.h"
|
||||
|
||||
/* Make sure not to make this smaller than the maximum coredump size.
|
||||
* See JOURNAL_SIZE_MAX in coredump.c */
|
||||
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
#define ENTRY_SIZE_MAX (1024*1024*770u)
|
||||
#define ENTRY_SIZE_UNPRIV_MAX (1024*1024*32u)
|
||||
#define DATA_SIZE_MAX (1024*1024*768u)
|
||||
#else
|
||||
#define ENTRY_SIZE_MAX (1024*1024*13u)
|
||||
#define ENTRY_SIZE_UNPRIV_MAX (1024*1024*8u)
|
||||
#define DATA_SIZE_MAX (1024*1024*11u)
|
||||
#endif
|
||||
#define LINE_CHUNK 8*1024u
|
||||
|
||||
/* The maximum number of fields in an entry */
|
||||
#define ENTRY_FIELD_COUNT_MAX 1024u
|
||||
|
||||
typedef struct JournalImporter {
|
||||
int fd;
|
||||
bool passive_fd;
|
||||
|
||||
Reference in New Issue
Block a user