From 7e2a5fbd851bf195a45c650dacad45d6456910bd Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 1 Oct 2023 16:48:36 +0900 Subject: [PATCH 1/2] 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 ee1621822c..c41db65eb1 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) { From 4ed95fafad06473da7b3275461dd439e2af7d191 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 2 Oct 2023 10:28:55 +0900 Subject: [PATCH 2/2] network: set maximum length to be read by read_full_file_full() Fixes #29264 and oss-fuzz#62556 (https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=62556). --- src/network/netdev/macsec.c | 10 +++++++--- src/network/netdev/wireguard.c | 8 ++++++-- test/fuzz/fuzz-netdev-parser/oss-fuzz-62556 | Bin 0 -> 27849 bytes 3 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 test/fuzz/fuzz-netdev-parser/oss-fuzz-62556 diff --git a/src/network/netdev/macsec.c b/src/network/netdev/macsec.c index 6d17d45059..98927b168d 100644 --- a/src/network/netdev/macsec.c +++ b/src/network/netdev/macsec.c @@ -959,15 +959,19 @@ static int macsec_read_key_file(NetDev *netdev, SecurityAssociation *sa) { return 0; r = read_full_file_full( - AT_FDCWD, sa->key_file, UINT64_MAX, SIZE_MAX, - READ_FULL_FILE_SECURE | READ_FULL_FILE_UNHEX | READ_FULL_FILE_WARN_WORLD_READABLE | READ_FULL_FILE_CONNECT_SOCKET, + AT_FDCWD, sa->key_file, UINT64_MAX, MACSEC_KEYID_LEN, + READ_FULL_FILE_SECURE | + READ_FULL_FILE_UNHEX | + READ_FULL_FILE_WARN_WORLD_READABLE | + READ_FULL_FILE_CONNECT_SOCKET | + READ_FULL_FILE_FAIL_WHEN_LARGER, NULL, (char **) &key, &key_len); if (r < 0) return log_netdev_error_errno(netdev, r, "Failed to read key from '%s', ignoring: %m", sa->key_file); - if (key_len != 16) + if (key_len != MACSEC_KEYID_LEN) return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), "Invalid key length (%zu bytes), ignoring: %m", key_len); diff --git a/src/network/netdev/wireguard.c b/src/network/netdev/wireguard.c index c89577609d..4c7d837c41 100644 --- a/src/network/netdev/wireguard.c +++ b/src/network/netdev/wireguard.c @@ -1037,8 +1037,12 @@ static int wireguard_read_key_file(const char *filename, uint8_t dest[static WG_ assert(dest); r = read_full_file_full( - AT_FDCWD, filename, UINT64_MAX, SIZE_MAX, - READ_FULL_FILE_SECURE | READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_WARN_WORLD_READABLE | READ_FULL_FILE_CONNECT_SOCKET, + AT_FDCWD, filename, UINT64_MAX, WG_KEY_LEN, + READ_FULL_FILE_SECURE | + READ_FULL_FILE_UNBASE64 | + READ_FULL_FILE_WARN_WORLD_READABLE | + READ_FULL_FILE_CONNECT_SOCKET | + READ_FULL_FILE_FAIL_WHEN_LARGER, NULL, &key, &key_len); if (r < 0) return r; diff --git a/test/fuzz/fuzz-netdev-parser/oss-fuzz-62556 b/test/fuzz/fuzz-netdev-parser/oss-fuzz-62556 new file mode 100644 index 0000000000000000000000000000000000000000..e2418f9e5f83a01911d57895363d0840fcd2b4a2 GIT binary patch literal 27849 zcmeI5J!->H5QJ0fGCqL{laR*5MOx!R$S)x9Pa#JkWo}}~F> zQQdS0hUts==n#@&%B;sH`+q^Bn7Ihi@< z%)IW>Ka+d%#+^_>JOCA-!auxL6i30lIWrI5rNReum+Cq~PyXB;cPAcT6Jrx&6EoYR z%!^TmqBx0|>L7x603tvHh+uMF=EW$JgnZ~2R0k2n0}ufsKm?QXGA~9MisB?67r#AP#r`N4?qNn01-^i%e)w6D2kJasSYBD2Ot7OfCwh%WnPRj zNyvweL3I#8JOB|O0z@!5FY{uQp(suwraFiq9)JiCVVXpk^mmYC0$~iln<9lt;c2Gu zh+m~6Gud3l17s$dNoJbuQRc-clf0e?9fRs1f_MNTKm>?ja$e@eC__=4L`-!MK|BBv zAOb`%IWO~Klu1H9bPTG42;u>V01+U9$$6O