From 309576f61c2811049e3a4b65dcfb565ab2a019b6 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 28 Apr 2021 05:16:34 +0200 Subject: [PATCH] [klibc] cpio: Fix possible integer overflow on 32-bit systems Origin: https://git.kernel.org/pub/scm/libs/klibc/klibc.git/commit/?id=9b1c91577aef7f2e72c3aa11a27749160bd278ff Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2021-31872 The maximum name and file sizes in the "new" header format are 32-bit unsigned values. However, the I/O functions mostly use long for sizes and offsets, so that sizes >= 2^31 are handled wrongly on 32-bit systems. The current GNU cpio code doesn't seem to have this problem, but the divergence between this version and that is large enough that I can't simply cherry-pick a fix for it. As a short-term fix, in read_in_new_ascii(), fail if c_namesize or c_filesize is > LONG_MAX. CVE-2021-31872 Signed-off-by: Ben Hutchings Gbp-Pq: Name 0039-klibc-cpio-Fix-possible-integer-overflow-on-32-bit-s.patch --- usr/utils/cpio.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/usr/utils/cpio.c b/usr/utils/cpio.c index cb61679..ac48131 100644 --- a/usr/utils/cpio.c +++ b/usr/utils/cpio.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -904,6 +905,15 @@ static void read_in_new_ascii(struct new_cpio_header *file_hdr, int in_des) file_hdr->c_hdr[i] = strtoul(hexbuf, NULL, 16); ah += 8; } + + /* Sizes > LONG_MAX can currently result in integer overflow + in various places. Fail if name is too large. */ + if (file_hdr->c_namesize > LONG_MAX) { + fprintf(stderr, "%s: name size out of range\n", + progname); + exit(1); + } + /* Read file name from input. */ free(file_hdr->c_name); file_hdr->c_name = (char *)xmalloc(file_hdr->c_namesize); @@ -914,6 +924,14 @@ static void read_in_new_ascii(struct new_cpio_header *file_hdr, int in_des) is rounded up to the next long-word, so we might need to drop 1-3 bytes. */ tape_skip_padding(in_des, file_hdr->c_namesize + 110); + + /* Fail if file is too large. We could check this earlier + but it's helpful to report the name. */ + if (file_hdr->c_filesize > LONG_MAX) { + fprintf(stderr, "%s: %s: file size out of range\n", + progname, file_hdr->c_name); + exit(1); + } } /* Return 16-bit integer I with the bytes swapped. */ -- 2.30.2