1/* Verify ISO-2022-CN-EXT does not write out of the bounds.
2 Copyright (C) 2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19#include <stdio.h>
20#include <string.h>
21
22#include <errno.h>
23#include <iconv.h>
24#include <sys/mman.h>
25
26#include <support/xunistd.h>
27#include <support/check.h>
28#include <support/support.h>
29
30/* The test sets up a two memory page buffer with the second page marked
31 PROT_NONE to trigger a fault if the conversion writes beyond the exact
32 expected amount. Then we carry out various conversions and precisely
33 place the start of the output buffer in order to trigger a SIGSEGV if the
34 process writes anywhere between 1 and page sized bytes more (only one
35 PROT_NONE page is setup as a canary) than expected. These tests exercise
36 all three of the cases in ISO-2022-CN-EXT where the converter must switch
37 character sets and may run out of buffer space while doing the
38 operation. */
39
40static int
41do_test (void)
42{
43 iconv_t cd = iconv_open (tocode: "ISO-2022-CN-EXT", fromcode: "UTF-8");
44 TEST_VERIFY_EXIT (cd != (iconv_t) -1);
45
46 char *ntf;
47 size_t ntfsize;
48 char *outbufbase;
49 {
50 int pgz = getpagesize ();
51 TEST_VERIFY_EXIT (pgz > 0);
52 ntfsize = 2 * pgz;
53
54 ntf = xmmap (NULL, length: ntfsize, PROT_READ | PROT_WRITE, MAP_PRIVATE
55 | MAP_ANONYMOUS, fd: -1);
56 xmprotect (addr: ntf + pgz, length: pgz, PROT_NONE);
57
58 outbufbase = ntf + pgz;
59 }
60
61 /* Check if SOdesignation escape sequence does not trigger an OOB write. */
62 {
63 char inbuf[] = "\xe4\xba\xa4\xe6\x8d\xa2";
64
65 for (int i = 0; i < 9; i++)
66 {
67 char *inp = inbuf;
68 size_t inleft = sizeof (inbuf) - 1;
69
70 char *outp = outbufbase - i;
71 size_t outleft = i;
72
73 TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft)
74 == (size_t) -1);
75 TEST_COMPARE (errno, E2BIG);
76
77 TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0);
78 }
79 }
80
81 /* Same as before for SS2designation. */
82 {
83 char inbuf[] = "㴽 \xe3\xb4\xbd";
84
85 for (int i = 0; i < 14; i++)
86 {
87 char *inp = inbuf;
88 size_t inleft = sizeof (inbuf) - 1;
89
90 char *outp = outbufbase - i;
91 size_t outleft = i;
92
93 TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft)
94 == (size_t) -1);
95 TEST_COMPARE (errno, E2BIG);
96
97 TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0);
98 }
99 }
100
101 /* Same as before for SS3designation. */
102 {
103 char inbuf[] = "劄 \xe5\x8a\x84";
104
105 for (int i = 0; i < 14; i++)
106 {
107 char *inp = inbuf;
108 size_t inleft = sizeof (inbuf) - 1;
109
110 char *outp = outbufbase - i;
111 size_t outleft = i;
112
113 TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft)
114 == (size_t) -1);
115 TEST_COMPARE (errno, E2BIG);
116
117 TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0);
118 }
119 }
120
121 TEST_VERIFY_EXIT (iconv_close (cd) != -1);
122
123 xmunmap (addr: ntf, length: ntfsize);
124
125 return 0;
126}
127
128#include <support/test-driver.c>
129

source code of glibc/iconvdata/tst-iconv-iso-2022-cn-ext.c