* [COMMITTED 2.31] iconv: ISO-2022-CN-EXT: fix out-of-bound writes when writing escape sequence (CVE-2024-2961)
@ 2024-04-19 19:52 Aurelien Jarno
2024-04-22 13:13 ` Adhemerval Zanella Netto
0 siblings, 1 reply; 2+ messages in thread
From: Aurelien Jarno @ 2024-04-19 19:52 UTC (permalink / raw)
To: libc-stable; +Cc: Charles Fol, Adhemerval Zanella, Carlos O'Donell
From: Charles Fol <folcharles@gmail.com>
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 <adhemerval.zanella@linaro.org>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
(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
+ <https://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <errno.h>
+#include <iconv.h>
+#include <sys/mman.h>
+
+#include <support/xunistd.h>
+#include <support/check.h>
+#include <support/support.h>
+
+/* 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 <support/test-driver.c>
--
2.43.0
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [COMMITTED 2.31] iconv: ISO-2022-CN-EXT: fix out-of-bound writes when writing escape sequence (CVE-2024-2961)
2024-04-19 19:52 [COMMITTED 2.31] iconv: ISO-2022-CN-EXT: fix out-of-bound writes when writing escape sequence (CVE-2024-2961) Aurelien Jarno
@ 2024-04-22 13:13 ` Adhemerval Zanella Netto
0 siblings, 0 replies; 2+ messages in thread
From: Adhemerval Zanella Netto @ 2024-04-22 13:13 UTC (permalink / raw)
To: Aurelien Jarno, libc-stable; +Cc: Carlos O'Donell
I think we also need to update the advisories/GLIBC-SA-2024-0004 with this
backport.
On 19/04/24 16:52, Aurelien Jarno wrote:
> From: Charles Fol <folcharles@gmail.com>
>
> 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 <adhemerval.zanella@linaro.org>
> Reviewed-by: Carlos O'Donell <carlos@redhat.com>
> Tested-by: Carlos O'Donell <carlos@redhat.com>
>
> (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
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <stdio.h>
> +#include <string.h>
> +
> +#include <errno.h>
> +#include <iconv.h>
> +#include <sys/mman.h>
> +
> +#include <support/xunistd.h>
> +#include <support/check.h>
> +#include <support/support.h>
> +
> +/* 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 <support/test-driver.c>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2024-04-22 13:14 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-04-19 19:52 [COMMITTED 2.31] iconv: ISO-2022-CN-EXT: fix out-of-bound writes when writing escape sequence (CVE-2024-2961) Aurelien Jarno
2024-04-22 13:13 ` Adhemerval Zanella Netto
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).