From 7e2a5fbd851bf195a45c650dacad45d6456910bd Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 1 Oct 2023 16:48:36 +0900 Subject: [PATCH] fileio: make read_full_file_full() usable with size and READ_FULL_FILE_UNBASE64 When READ_FULL_FILE_UNBASE64 (or READ_FULL_FILE_UNHEX) is specified, setting size argument by caller is difficult, as it is hard to estimate the encoded length. This makes when size is specified with decoding option, let's read file more, and check decoded size later with the specified size. --- src/basic/fileio.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/basic/fileio.c b/src/basic/fileio.c index ee1621822c3..c41db65eb19 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -32,6 +32,8 @@ /* The maximum size of the file we'll read in one go in read_full_file() (64M). */ #define READ_FULL_BYTES_MAX (64U*1024U*1024U - 1U) +/* Used when a size is specified for read_full_file() with READ_FULL_FILE_UNBASE64 or _UNHEX */ +#define READ_FULL_FILE_ENCODED_STRING_AMPLIFICATION_BOUNDARY 3 /* The maximum size of virtual files (i.e. procfs, sysfs, and other virtual "API" files) we'll read in one go * in read_virtual_file(). Note that this limit is different (and much lower) than the READ_FULL_BYTES_MAX @@ -572,7 +574,7 @@ int read_full_stream_full( size_t *ret_size) { _cleanup_free_ char *buf = NULL; - size_t n, n_next = 0, l; + size_t n, n_next = 0, l, expected_decoded_size = size; int fd, r; assert(f); @@ -583,6 +585,13 @@ int read_full_stream_full( if (offset != UINT64_MAX && offset > LONG_MAX) /* fseek() can only deal with "long" offsets */ return -ERANGE; + if ((flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) != 0) { + if (size <= SIZE_MAX / READ_FULL_FILE_ENCODED_STRING_AMPLIFICATION_BOUNDARY) + size *= READ_FULL_FILE_ENCODED_STRING_AMPLIFICATION_BOUNDARY; + else + size = SIZE_MAX; + } + fd = fileno(f); if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see * fmemopen()), let's optimize our buffering */ @@ -707,6 +716,11 @@ int read_full_stream_full( explicit_bzero_safe(buf, n); free_and_replace(buf, decoded); n = l = decoded_size; + + if (FLAGS_SET(flags, READ_FULL_FILE_FAIL_WHEN_LARGER) && l > expected_decoded_size) { + r = -E2BIG; + goto finalize; + } } if (!ret_size) {