/* 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