]> git.ipfire.org Git - thirdparty/glibc.git/blame - wcsmbs/wcsmbsload.c
iconv: ISO-2022-CN-EXT: fix out-of-bound writes when writing escape sequence (CVE...
[thirdparty/glibc.git] / wcsmbs / wcsmbsload.c
CommitLineData
dff8da6b 1/* Copyright (C) 1998-2024 Free Software Foundation, Inc.
4bca4c17 2 This file is part of the GNU C Library.
4bca4c17
UD
3
4 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
4bca4c17
UD
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 12 Lesser General Public License for more details.
4bca4c17 13
41bdb6e2 14 You should have received a copy of the GNU Lesser General Public
59ba27a6 15 License along with the GNU C Library; if not, see
5a82c748 16 <https://www.gnu.org/licenses/>. */
4bca4c17 17
e4d0709f 18#include <ctype.h>
4bca4c17
UD
19#include <langinfo.h>
20#include <limits.h>
4553f228 21#include <stdlib.h>
c9c15ac3 22#include <stdio.h>
4553f228 23#include <string.h>
4bca4c17 24
4553f228 25#include <locale/localeinfo.h>
4bca4c17 26#include <wcsmbsload.h>
ec999b8e 27#include <libc-lock.h>
4bca4c17
UD
28
29
4bca4c17 30/* These are the descriptions for the default conversion functions. */
bd62cef6 31static const struct __gconv_step to_wc =
4bca4c17 32{
d64b6ad0
UD
33 .__shlib_handle = NULL,
34 .__modname = NULL,
35 .__counter = INT_MAX,
129d706d
UD
36 .__from_name = (char *) "ANSI_X3.4-1968//TRANSLIT",
37 .__to_name = (char *) "INTERNAL",
d64b6ad0 38 .__fct = __gconv_transform_ascii_internal,
f9ad060c 39 .__btowc_fct = __gconv_btwoc_ascii,
d64b6ad0
UD
40 .__init_fct = NULL,
41 .__end_fct = NULL,
42 .__min_needed_from = 1,
43 .__max_needed_from = 1,
44 .__min_needed_to = 4,
45 .__max_needed_to = 4,
46 .__stateful = 0,
47 .__data = NULL
4bca4c17
UD
48};
49
bd62cef6 50static const struct __gconv_step to_mb =
4bca4c17 51{
d64b6ad0
UD
52 .__shlib_handle = NULL,
53 .__modname = NULL,
54 .__counter = INT_MAX,
129d706d
UD
55 .__from_name = (char *) "INTERNAL",
56 .__to_name = (char *) "ANSI_X3.4-1968//TRANSLIT",
d64b6ad0 57 .__fct = __gconv_transform_internal_ascii,
f9ad060c 58 .__btowc_fct = NULL,
d64b6ad0
UD
59 .__init_fct = NULL,
60 .__end_fct = NULL,
61 .__min_needed_from = 4,
62 .__max_needed_from = 4,
63 .__min_needed_to = 1,
64 .__max_needed_to = 1,
65 .__stateful = 0,
66 .__data = NULL
4bca4c17
UD
67};
68
69
70/* For the default locale we only have to handle ANSI_X3.4-1968. */
96310297 71const struct gconv_fcts __wcsmbs_gconv_fcts_c =
4bca4c17 72{
bd62cef6 73 .towc = (struct __gconv_step *) &to_wc,
129d706d 74 .towc_nsteps = 1,
bd62cef6 75 .tomb = (struct __gconv_step *) &to_mb,
db6af3eb 76 .tomb_nsteps = 1,
4bca4c17
UD
77};
78
79
01beb5b9 80attribute_hidden
c4bb5cd8 81struct __gconv_step *
01beb5b9 82__wcsmbs_getfct (const char *to, const char *from, size_t *nstepsp)
4bca4c17
UD
83{
84 size_t nsteps;
d64b6ad0 85 struct __gconv_step *result;
129d706d 86#if 0
d64b6ad0
UD
87 size_t nstateful;
88 size_t cnt;
129d706d 89#endif
4bca4c17 90
c90a2db6 91 if (__gconv_find_transform (to, from, &result, &nsteps, 0) != __GCONV_OK)
4bca4c17
UD
92 /* Loading the conversion step is not possible. */
93 return NULL;
94
129d706d
UD
95 /* Maybe it is someday necessary to allow more than one step.
96 Currently this is not the case since the conversions handled here
97 are from and to INTERNAL and there always is a converted for
98 that. It the directly following code is enabled the libio
99 functions will have to allocate appropriate __gconv_step_data
100 elements instead of only one. */
101#if 0
d64b6ad0
UD
102 /* Count the number of stateful conversions. Since we will only
103 have one 'mbstate_t' object available we can only deal with one
104 stateful conversion. */
105 nstateful = 0;
106 for (cnt = 0; cnt < nsteps; ++cnt)
107 if (result[cnt].__stateful)
108 ++nstateful;
109 if (nstateful > 1)
129d706d
UD
110#else
111 if (nsteps > 1)
112#endif
d64b6ad0
UD
113 {
114 /* We cannot handle this case. */
115 __gconv_close_transform (result, nsteps);
116 result = NULL;
117 }
129d706d
UD
118 else
119 *nstepsp = nsteps;
4bca4c17
UD
120
121 return result;
122}
123
124
4553f228
UD
125/* Extract from the given locale name the character set portion. Since
126 only the XPG form of the name includes this information we don't have
127 to take care for the CEN form. */
128#define extract_charset_name(str) \
129 ({ \
130 const char *cp = str; \
131 char *result = NULL; \
132 \
b17277cf 133 cp += strcspn (cp, "@.+,"); \
4553f228
UD
134 if (*cp == '.') \
135 { \
a7c378d8 136 const char *endp = ++cp; \
4553f228
UD
137 while (*endp != '\0' && *endp != '@') \
138 ++endp; \
139 if (endp != cp) \
a7c378d8 140 result = strndupa (cp, endp - cp); \
4553f228
UD
141 } \
142 result; \
4553f228
UD
143 })
144
145
96310297 146/* Some of the functions here must not be used while setlocale is called. */
91e32540 147__libc_rwlock_define (extern, __libc_setlocale_lock attribute_hidden)
d64b6ad0 148
4bca4c17
UD
149/* Load conversion functions for the currently selected locale. */
150void
f095bb72 151__wcsmbs_load_conv (struct __locale_data *new_category)
4bca4c17 152{
93ec1cf0
FW
153 struct lc_ctype_data *data = new_category->private;
154
4bca4c17 155 /* Acquire the lock. */
91e32540 156 __libc_rwlock_wrlock (__libc_setlocale_lock);
4bca4c17 157
61d655c1 158 /* We should repeat the test since while we waited some other thread
4bca4c17 159 might have run this function. */
93ec1cf0 160 if (__glibc_likely (data->fcts == NULL))
4bca4c17 161 {
96310297
RM
162 /* We must find the real functions. */
163 const char *charset_name;
164 const char *complete_name;
165 struct gconv_fcts *new_fcts;
166 int use_translit;
167
168 /* Allocate the gconv_fcts structure. */
9954432e 169 new_fcts = calloc (1, sizeof *new_fcts);
96310297 170 if (new_fcts == NULL)
6e606fad 171 goto failed;
96310297
RM
172
173 /* Get name of charset of the locale. */
174 charset_name = new_category->values[_NL_ITEM_INDEX(CODESET)].string;
175
176 /* Does the user want transliteration? */
177 use_translit = new_category->use_translit;
178
179 /* Normalize the name and add the slashes necessary for a
180 complete lookup. */
181 complete_name = norm_add_slashes (charset_name,
db2f05ba 182 use_translit ? "TRANSLIT" : "");
96310297
RM
183
184 /* It is not necessary to use transliteration in this direction
185 since the internal character set is supposed to be able to
186 represent all others. */
187 new_fcts->towc = __wcsmbs_getfct ("INTERNAL", complete_name,
188 &new_fcts->towc_nsteps);
9954432e
UD
189 if (new_fcts->towc != NULL)
190 new_fcts->tomb = __wcsmbs_getfct (complete_name, "INTERNAL",
191 &new_fcts->tomb_nsteps);
96310297
RM
192
193 /* If any of the conversion functions is not available we don't
194 use any since this would mean we cannot convert back and
d3ed7225 195 forth. NB: NEW_FCTS was allocated with calloc. */
96310297 196 if (new_fcts->tomb == NULL)
4bca4c17 197 {
96310297
RM
198 if (new_fcts->towc != NULL)
199 __gconv_close_transform (new_fcts->towc, new_fcts->towc_nsteps);
200
201 free (new_fcts);
4bca4c17 202
6e606fad 203 failed:
93ec1cf0 204 data->fcts = (void *) &__wcsmbs_gconv_fcts_c;
6e606fad
RM
205 }
206 else
93ec1cf0 207 data->fcts = new_fcts;
4bca4c17
UD
208 }
209
91e32540 210 __libc_rwlock_unlock (__libc_setlocale_lock);
4bca4c17 211}
d64b6ad0
UD
212
213
214/* Clone the current conversion function set. */
215void
d64b6ad0
UD
216__wcsmbs_clone_conv (struct gconv_fcts *copy)
217{
96310297 218 const struct gconv_fcts *orig;
34e3c127 219
96310297 220 orig = get_gconv_fcts (_NL_CURRENT_DATA (LC_CTYPE));
d64b6ad0
UD
221
222 /* Copy the data. */
96310297 223 *copy = *orig;
d64b6ad0 224
c9c15ac3
FW
225 /* Now increment the usage counters. Note: This assumes
226 copy->*_nsteps == 1. The current locale holds a reference, so it
227 is still there after acquiring the lock. */
228
229 __libc_lock_lock (__gconv_lock);
230
231 bool overflow = false;
d64b6ad0 232 if (copy->towc->__shlib_handle != NULL)
c9c15ac3
FW
233 overflow |= __builtin_add_overflow (copy->towc->__counter, 1,
234 &copy->towc->__counter);
d64b6ad0 235 if (copy->tomb->__shlib_handle != NULL)
c9c15ac3
FW
236 overflow |= __builtin_add_overflow (copy->tomb->__counter, 1,
237 &copy->tomb->__counter);
238
239 __libc_lock_unlock (__gconv_lock);
240
241 if (overflow)
242 __libc_fatal ("\
243Fatal glibc error: gconv module reference counter overflow\n");
d64b6ad0 244}
4e2e9999
UD
245
246
129d706d 247/* Get converters for named charset. */
4e2e9999 248int
4e2e9999
UD
249__wcsmbs_named_conv (struct gconv_fcts *copy, const char *name)
250{
01beb5b9 251 copy->towc = __wcsmbs_getfct ("INTERNAL", name, &copy->towc_nsteps);
db6af3eb
UD
252 if (copy->towc == NULL)
253 return 1;
254
255 copy->tomb = __wcsmbs_getfct (name, "INTERNAL", &copy->tomb_nsteps);
256 if (copy->tomb == NULL)
4e2e9999 257 {
db6af3eb 258 __gconv_close_transform (copy->towc, copy->towc_nsteps);
db6af3eb 259 return 1;
4e2e9999
UD
260 }
261
db6af3eb 262 return 0;
129d706d 263}
4e2e9999 264
d7ccc6c9 265void
f095bb72 266_nl_cleanup_ctype (struct __locale_data *locale)
129d706d 267{
93ec1cf0
FW
268 struct lc_ctype_data *data = locale->private;
269 if (data->fcts != NULL && data->fcts != &__wcsmbs_gconv_fcts_c)
129d706d 270 {
96310297 271 /* Free the old conversions. */
93ec1cf0
FW
272 __gconv_close_transform (data->fcts->tomb, data->fcts->tomb_nsteps);
273 __gconv_close_transform (data->fcts->towc, data->fcts->towc_nsteps);
274
275 free ((void *) data->fcts);
276 data->fcts = NULL;
277 /* data itself is allocated within locale. */
129d706d 278 }
4e2e9999 279}