aboutsummaryrefslogtreecommitdiff
path: root/iconvdata/tst-iconv-iso-2022-cn-ext.c
blob: 96a8765fd5369681a84bf70713d801d9a3fdd445 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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>