From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from hall.aurel32.net (hall.aurel32.net [IPv6:2001:bc8:30d7:100::1]) by sourceware.org (Postfix) with ESMTPS id 508B13846401 for ; Fri, 19 Apr 2024 19:52:57 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 508B13846401 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=aurel32.net Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=aurel32.net ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 508B13846401 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2001:bc8:30d7:100::1 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1713556379; cv=none; b=d269hO0bf5WuTzZGpzYQMkuM8j9IDAOE13aDtCWZCUL1z4PTQ93hEJryLVRHjLmm8ZqrkEQFY0M1WsMWgLYDb3CyQ14/BzB2qpsZdViO8D44auSwlOuQuM2grge697SIW502zDmQakVslkAPutFeLgUPmhnpbSs7Wuv6zLFzl2o= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1713556379; c=relaxed/simple; bh=YqGTmyWMP+jlbUEHsGPvcvDsfzEyhoqXH1x/gIygWXc=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=boddBWCKt0StYhqjEc7ptyS7P1eV4qTrLeHyqwvk7Bu849s3oD47gq67faT28F1jyvE12ze5LqIAH2ZxO/I6ZA3/fOUxDFNJ9ivIRifrcoGDAMwlcLNpW7aEn+EcfNt2Fszsf9hhPEC8/U25lwpfLxzXYeI5wh8gJNXk42hIR9o= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=aurel32.net ; s=202004.hall; h=Content-Transfer-Encoding:Content-Type:MIME-Version: Message-ID:Date:Subject:Cc:To:From:From:Reply-To:Subject:Content-ID: Content-Description:In-Reply-To:References:X-Debbugs-Cc; bh=pX2NEzNAO2qfer313hf1SHGDiqWucpRY5mH/65uVOMw=; b=Xo2tIy3nz1LTp5eWzaaMFfAkgp egxr+Tjx3HfPM60BVsiwQUWdohRoU3Ohqc7N76dpKkMKjIByLPhE4vNUgvWLkpC61UktjAinro6VS LgAB52TRjVUqUIjDfbLiwtywrxQHhxcK80C0qK+AMbbyuLg2ogf8DGg0B4/p/+Xtn1tmf1GzIZp1J EIS+BgbRgnqpAfu63z4Uhj94nfeEz793Up/SSAwBqnrkXDvL2q/WwlpNLeIvU6KnkzE+TqLTkmy/x qXu4frLic4dY6cV6esDXMxazv3dXlLXbDCJtWxdmSwepYm7Zl2f6SzYeqLTXFxwKPZlGc3ixv9WZ5 bQNbvnMw==; Received: from ohm.aurel32.net ([2001:bc8:30d7:111::2] helo=ohm.rr44.fr) by hall.aurel32.net with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1rxuI3-007L4B-0Z; Fri, 19 Apr 2024 21:52:55 +0200 From: Aurelien Jarno To: libc-stable@sourceware.org Cc: Charles Fol , Adhemerval Zanella , Carlos O'Donell Subject: [COMMITTED 2.31] iconv: ISO-2022-CN-EXT: fix out-of-bound writes when writing escape sequence (CVE-2024-2961) Date: Fri, 19 Apr 2024 21:52:21 +0200 Message-ID: <20240419195247.1794363-1-aurelien@aurel32.net> X-Mailer: git-send-email 2.43.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-13.4 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,KAM_SHORT,SPF_HELO_PASS,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: From: Charles Fol ISO-2022-CN-EXT uses escape sequences to indicate character set changes (as specified by RFC 1922). While the SOdesignation has the expected bounds checks, neither SS2designation nor SS3designation have its; allowing a write overflow of 1, 2, or 3 bytes with fixed values: '$+I', '$+J', '$+K', '$+L', '$+M', or '$*H'. Checked on aarch64-linux-gnu. Co-authored-by: Adhemerval Zanella Reviewed-by: Carlos O'Donell Tested-by: Carlos O'Donell (cherry picked from commit f9dc609e06b1136bb0408be9605ce7973a767ada) --- iconvdata/Makefile | 5 +- iconvdata/iso-2022-cn-ext.c | 12 +++ iconvdata/tst-iconv-iso-2022-cn-ext.c | 128 ++++++++++++++++++++++++++ 3 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 iconvdata/tst-iconv-iso-2022-cn-ext.c diff --git a/iconvdata/Makefile b/iconvdata/Makefile index 8fbb67a52b..31b1cf8a9f 100644 --- a/iconvdata/Makefile +++ b/iconvdata/Makefile @@ -75,7 +75,8 @@ ifeq (yes,$(build-shared)) tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \ tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \ bug-iconv10 bug-iconv11 bug-iconv12 bug-iconv13 bug-iconv14 \ - bug-iconv15 + bug-iconv15 \ + tst-iconv-iso-2022-cn-ext ifeq ($(have-thread-library),yes) tests += bug-iconv3 endif @@ -322,6 +323,8 @@ $(objpfx)bug-iconv14.out: $(objpfx)gconv-modules \ $(addprefix $(objpfx),$(modules.so)) $(objpfx)bug-iconv15.out: $(addprefix $(objpfx), $(gconv-modules)) \ $(addprefix $(objpfx),$(modules.so)) +$(objpfx)tst-iconv-iso-2022-cn-ext.out: $(addprefix $(objpfx), $(gconv-modules)) \ + $(addprefix $(objpfx),$(modules.so)) $(objpfx)iconv-test.out: run-iconv-test.sh $(objpfx)gconv-modules \ $(addprefix $(objpfx),$(modules.so)) \ diff --git a/iconvdata/iso-2022-cn-ext.c b/iconvdata/iso-2022-cn-ext.c index 947b807421..34e1010bed 100644 --- a/iconvdata/iso-2022-cn-ext.c +++ b/iconvdata/iso-2022-cn-ext.c @@ -575,6 +575,12 @@ DIAG_IGNORE_Os_NEEDS_COMMENT (5, "-Wmaybe-uninitialized"); { \ const char *escseq; \ \ + if (outptr + 4 > outend) \ + { \ + result = __GCONV_FULL_OUTPUT; \ + break; \ + } \ + \ assert (used == CNS11643_2_set); /* XXX */ \ escseq = "*H"; \ *outptr++ = ESC; \ @@ -588,6 +594,12 @@ DIAG_IGNORE_Os_NEEDS_COMMENT (5, "-Wmaybe-uninitialized"); { \ const char *escseq; \ \ + if (outptr + 4 > outend) \ + { \ + result = __GCONV_FULL_OUTPUT; \ + break; \ + } \ + \ assert ((used >> 5) >= 3 && (used >> 5) <= 7); \ escseq = "+I+J+K+L+M" + ((used >> 5) - 3) * 2; \ *outptr++ = ESC; \ diff --git a/iconvdata/tst-iconv-iso-2022-cn-ext.c b/iconvdata/tst-iconv-iso-2022-cn-ext.c new file mode 100644 index 0000000000..96a8765fd5 --- /dev/null +++ b/iconvdata/tst-iconv-iso-2022-cn-ext.c @@ -0,0 +1,128 @@ +/* Verify ISO-2022-CN-EXT does not write out of the bounds. + Copyright (C) 2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include + +#include +#include +#include + +#include +#include +#include + +/* The test sets up a two memory page buffer with the second page marked + PROT_NONE to trigger a fault if the conversion writes beyond the exact + expected amount. Then we carry out various conversions and precisely + place the start of the output buffer in order to trigger a SIGSEGV if the + process writes anywhere between 1 and page sized bytes more (only one + PROT_NONE page is setup as a canary) than expected. These tests exercise + all three of the cases in ISO-2022-CN-EXT where the converter must switch + character sets and may run out of buffer space while doing the + operation. */ + +static int +do_test (void) +{ + iconv_t cd = iconv_open ("ISO-2022-CN-EXT", "UTF-8"); + TEST_VERIFY_EXIT (cd != (iconv_t) -1); + + char *ntf; + size_t ntfsize; + char *outbufbase; + { + int pgz = getpagesize (); + TEST_VERIFY_EXIT (pgz > 0); + ntfsize = 2 * pgz; + + ntf = xmmap (NULL, ntfsize, PROT_READ | PROT_WRITE, MAP_PRIVATE + | MAP_ANONYMOUS, -1); + xmprotect (ntf + pgz, pgz, PROT_NONE); + + outbufbase = ntf + pgz; + } + + /* Check if SOdesignation escape sequence does not trigger an OOB write. */ + { + char inbuf[] = "\xe4\xba\xa4\xe6\x8d\xa2"; + + for (int i = 0; i < 9; i++) + { + char *inp = inbuf; + size_t inleft = sizeof (inbuf) - 1; + + char *outp = outbufbase - i; + size_t outleft = i; + + TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft) + == (size_t) -1); + TEST_COMPARE (errno, E2BIG); + + TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0); + } + } + + /* Same as before for SS2designation. */ + { + char inbuf[] = "㴽 \xe3\xb4\xbd"; + + for (int i = 0; i < 14; i++) + { + char *inp = inbuf; + size_t inleft = sizeof (inbuf) - 1; + + char *outp = outbufbase - i; + size_t outleft = i; + + TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft) + == (size_t) -1); + TEST_COMPARE (errno, E2BIG); + + TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0); + } + } + + /* Same as before for SS3designation. */ + { + char inbuf[] = "劄 \xe5\x8a\x84"; + + for (int i = 0; i < 14; i++) + { + char *inp = inbuf; + size_t inleft = sizeof (inbuf) - 1; + + char *outp = outbufbase - i; + size_t outleft = i; + + TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft) + == (size_t) -1); + TEST_COMPARE (errno, E2BIG); + + TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0); + } + } + + TEST_VERIFY_EXIT (iconv_close (cd) != -1); + + xmunmap (ntf, ntfsize); + + return 0; +} + +#include -- 2.43.0