File: | src/lib/libc/nls/catopen.c |
Warning: | line 159, column 20 Potential leak of memory pointed to by 'catd' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: catopen.c,v 1.21 2017/04/27 23:54:08 millert Exp $ */ | |||
2 | /*- | |||
3 | * Copyright (c) 1996 The NetBSD Foundation, Inc. | |||
4 | * All rights reserved. | |||
5 | * | |||
6 | * This code is derived from software contributed to The NetBSD Foundation | |||
7 | * by J.T. Conklin. | |||
8 | * | |||
9 | * Redistribution and use in source and binary forms, with or without | |||
10 | * modification, are permitted provided that the following conditions | |||
11 | * are met: | |||
12 | * 1. Redistributions of source code must retain the above copyright | |||
13 | * notice, this list of conditions and the following disclaimer. | |||
14 | * 2. Redistributions in binary form must reproduce the above copyright | |||
15 | * notice, this list of conditions and the following disclaimer in the | |||
16 | * documentation and/or other materials provided with the distribution. | |||
17 | * | |||
18 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |||
19 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |||
20 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||
21 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE | |||
22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
28 | * POSSIBILITY OF SUCH DAMAGE. | |||
29 | */ | |||
30 | ||||
31 | #define _NLS_PRIVATE | |||
32 | ||||
33 | #include <sys/types.h> | |||
34 | #include <sys/stat.h> | |||
35 | #include <sys/mman.h> | |||
36 | #include <errno(*__errno()).h> | |||
37 | #include <fcntl.h> | |||
38 | #include <limits.h> | |||
39 | #include <nl_types.h> | |||
40 | #include <stdlib.h> | |||
41 | #include <string.h> | |||
42 | #include <unistd.h> | |||
43 | ||||
44 | #define MAXIMUM(a, b)(((a) > (b)) ? (a) : (b)) (((a) > (b)) ? (a) : (b)) | |||
45 | ||||
46 | #define NLS_DEFAULT_LANG"C" "C" | |||
47 | ||||
48 | static nl_catd load_msgcat(const char *); | |||
49 | static int verify_msgcat(nl_catd); | |||
50 | ||||
51 | nl_catd | |||
52 | catopen(const char *name, int oflag) | |||
53 | { | |||
54 | char tmppath[PATH_MAX1024]; | |||
55 | char *nlspath; | |||
56 | char *lang; | |||
57 | char *s, *t, *sep, *dot; | |||
58 | const char *u; | |||
59 | nl_catd catd; | |||
60 | ||||
61 | if (name == NULL((void *)0) || *name == '\0') | |||
| ||||
62 | return (nl_catd) -1; | |||
63 | ||||
64 | /* absolute or relative path? */ | |||
65 | if (strchr(name, '/')) | |||
66 | return load_msgcat(name); | |||
67 | ||||
68 | if (issetugid() != 0 || (nlspath = getenv("NLSPATH")) == NULL((void *)0)) | |||
69 | return (nl_catd) -1; | |||
70 | ||||
71 | lang = NULL((void *)0); | |||
72 | if (oflag & NL_CAT_LOCALE1) { | |||
73 | lang = getenv("LC_ALL"); | |||
74 | if (lang == NULL((void *)0)) | |||
75 | lang = getenv("LC_MESSAGES"); | |||
76 | } | |||
77 | if (lang
| |||
78 | lang = getenv("LANG"); | |||
79 | if (lang == NULL((void *)0)) | |||
80 | lang = NLS_DEFAULT_LANG"C"; | |||
81 | if (strcmp(lang, "POSIX") == 0) | |||
82 | lang = NLS_DEFAULT_LANG"C"; | |||
83 | ||||
84 | s = nlspath; | |||
85 | t = tmppath; | |||
86 | ||||
87 | /* | |||
88 | * Locale names are of the form language[_territory][.codeset]. | |||
89 | * See POSIX-1-2008 "8.2 Internationalization Variables" | |||
90 | */ | |||
91 | sep = strchr(lang, '_'); | |||
92 | dot = strrchr(lang, '.'); | |||
93 | if (dot && sep && dot < sep) | |||
94 | dot = NULL((void *)0); /* ignore dots preceeding _ */ | |||
95 | if (dot
| |||
96 | lang = NLS_DEFAULT_LANG"C"; /* no codeset specified */ | |||
97 | do { | |||
98 | while (*s && *s != ':') { | |||
99 | if (*s == '%') { | |||
100 | switch (*(++s)) { | |||
101 | case 'L': /* LANG or LC_MESSAGES */ | |||
102 | u = lang; | |||
103 | while (*u && t < tmppath + PATH_MAX1024-1) | |||
104 | *t++ = *u++; | |||
105 | break; | |||
106 | case 'N': /* value of name parameter */ | |||
107 | u = name; | |||
108 | while (*u && t < tmppath + PATH_MAX1024-1) | |||
109 | *t++ = *u++; | |||
110 | break; | |||
111 | case 'l': /* language part */ | |||
112 | u = lang; | |||
113 | while (*u && t < tmppath + PATH_MAX1024-1) { | |||
114 | *t++ = *u++; | |||
115 | if (sep && u >= sep) | |||
116 | break; | |||
117 | if (dot && u >= dot) | |||
118 | break; | |||
119 | } | |||
120 | break; | |||
121 | case 't': /* territory part */ | |||
122 | if (sep == NULL((void *)0)) | |||
123 | break; | |||
124 | u = sep + 1; | |||
125 | while (*u && t < tmppath + PATH_MAX1024-1) { | |||
126 | *t++ = *u++; | |||
127 | if (dot && u >= dot) | |||
128 | break; | |||
129 | } | |||
130 | break; | |||
131 | case 'c': /* codeset part */ | |||
132 | if (dot == NULL((void *)0)) | |||
133 | break; | |||
134 | u = dot + 1; | |||
135 | while (*u && t < tmppath + PATH_MAX1024-1) | |||
136 | *t++ = *u++; | |||
137 | break; | |||
138 | default: | |||
139 | if (t < tmppath + PATH_MAX1024-1) | |||
140 | *t++ = *s; | |||
141 | } | |||
142 | } else { | |||
143 | if (t < tmppath + PATH_MAX1024-1) | |||
144 | *t++ = *s; | |||
145 | } | |||
146 | s++; | |||
147 | } | |||
148 | ||||
149 | *t = '\0'; | |||
150 | catd = load_msgcat(tmppath); | |||
151 | if (catd != (nl_catd) -1) | |||
152 | return catd; | |||
153 | ||||
154 | if (*s) | |||
155 | s++; | |||
156 | t = tmppath; | |||
157 | } while (*s); | |||
158 | ||||
159 | return (nl_catd) -1; | |||
| ||||
160 | } | |||
161 | DEF_WEAK(catopen)__asm__(".weak " "catopen" " ; " "catopen" " = " "_libc_catopen" ); | |||
162 | ||||
163 | static nl_catd | |||
164 | load_msgcat(const char *path) | |||
165 | { | |||
166 | struct stat st; | |||
167 | nl_catd catd; | |||
168 | void *data; | |||
169 | int fd; | |||
170 | ||||
171 | catd = NULL((void *)0); | |||
172 | ||||
173 | if ((fd = open(path, O_RDONLY0x0000|O_CLOEXEC0x10000)) == -1) | |||
174 | return (nl_catd) -1; | |||
175 | ||||
176 | if (fstat(fd, &st) != 0) { | |||
177 | close (fd); | |||
178 | return (nl_catd) -1; | |||
179 | } | |||
180 | ||||
181 | if (st.st_size > INT_MAX2147483647 || st.st_size < sizeof (struct _nls_cat_hdr)) { | |||
182 | errno(*__errno()) = EINVAL22; | |||
183 | close (fd); | |||
184 | return (nl_catd) -1; | |||
185 | } | |||
186 | ||||
187 | data = mmap(0, st.st_size, PROT_READ0x01, MAP_SHARED0x0001, fd, 0); | |||
188 | close (fd); | |||
189 | ||||
190 | if (data == MAP_FAILED((void *)-1)) | |||
191 | return (nl_catd) -1; | |||
192 | ||||
193 | if (ntohl(((struct _nls_cat_hdr *) data)->__magic)(__uint32_t)(__builtin_constant_p(((struct _nls_cat_hdr *) data )->__magic) ? (__uint32_t)(((__uint32_t)(((struct _nls_cat_hdr *) data)->__magic) & 0xff) << 24 | ((__uint32_t )(((struct _nls_cat_hdr *) data)->__magic) & 0xff00) << 8 | ((__uint32_t)(((struct _nls_cat_hdr *) data)->__magic ) & 0xff0000) >> 8 | ((__uint32_t)(((struct _nls_cat_hdr *) data)->__magic) & 0xff000000) >> 24) : __swap32md (((struct _nls_cat_hdr *) data)->__magic)) != _NLS_MAGIC0xff88ff89) | |||
194 | goto invalid; | |||
195 | ||||
196 | if ((catd = malloc(sizeof (*catd))) == 0) | |||
197 | goto invalid; | |||
198 | ||||
199 | catd->__data = data; | |||
200 | catd->__size = st.st_size; | |||
201 | ||||
202 | if (verify_msgcat(catd)) | |||
203 | goto invalid; | |||
204 | ||||
205 | return catd; | |||
206 | ||||
207 | invalid: | |||
208 | free(catd); | |||
209 | munmap(data, st.st_size); | |||
210 | errno(*__errno()) = EINVAL22; | |||
211 | return (nl_catd) -1; | |||
212 | } | |||
213 | ||||
214 | static int | |||
215 | verify_msgcat(nl_catd catd) | |||
216 | { | |||
217 | struct _nls_cat_hdr *cat; | |||
218 | struct _nls_set_hdr *set; | |||
219 | struct _nls_msg_hdr *msg; | |||
220 | size_t remain; | |||
221 | int hdr_offset, i, index, j, msgs, nmsgs, nsets, off, txt_offset; | |||
222 | ||||
223 | remain = catd->__size; | |||
224 | cat = (struct _nls_cat_hdr *) catd->__data; | |||
225 | ||||
226 | hdr_offset = ntohl(cat->__msg_hdr_offset)(__uint32_t)(__builtin_constant_p(cat->__msg_hdr_offset) ? (__uint32_t)(((__uint32_t)(cat->__msg_hdr_offset) & 0xff ) << 24 | ((__uint32_t)(cat->__msg_hdr_offset) & 0xff00) << 8 | ((__uint32_t)(cat->__msg_hdr_offset) & 0xff0000) >> 8 | ((__uint32_t)(cat->__msg_hdr_offset ) & 0xff000000) >> 24) : __swap32md(cat->__msg_hdr_offset )); | |||
227 | nsets = ntohl(cat->__nsets)(__uint32_t)(__builtin_constant_p(cat->__nsets) ? (__uint32_t )(((__uint32_t)(cat->__nsets) & 0xff) << 24 | (( __uint32_t)(cat->__nsets) & 0xff00) << 8 | ((__uint32_t )(cat->__nsets) & 0xff0000) >> 8 | ((__uint32_t) (cat->__nsets) & 0xff000000) >> 24) : __swap32md (cat->__nsets)); | |||
228 | txt_offset = ntohl(cat->__msg_txt_offset)(__uint32_t)(__builtin_constant_p(cat->__msg_txt_offset) ? (__uint32_t)(((__uint32_t)(cat->__msg_txt_offset) & 0xff ) << 24 | ((__uint32_t)(cat->__msg_txt_offset) & 0xff00) << 8 | ((__uint32_t)(cat->__msg_txt_offset) & 0xff0000) >> 8 | ((__uint32_t)(cat->__msg_txt_offset ) & 0xff000000) >> 24) : __swap32md(cat->__msg_txt_offset )); | |||
229 | ||||
230 | /* catalog must contain at least one set and no negative offsets */ | |||
231 | if (nsets < 1 || hdr_offset < 0 || txt_offset < 0) | |||
232 | return (1); | |||
233 | ||||
234 | remain -= sizeof (*cat); | |||
235 | ||||
236 | /* check if offsets or set size overflow */ | |||
237 | if (remain <= hdr_offset || remain <= ntohl(cat->__msg_txt_offset)(__uint32_t)(__builtin_constant_p(cat->__msg_txt_offset) ? (__uint32_t)(((__uint32_t)(cat->__msg_txt_offset) & 0xff ) << 24 | ((__uint32_t)(cat->__msg_txt_offset) & 0xff00) << 8 | ((__uint32_t)(cat->__msg_txt_offset) & 0xff0000) >> 8 | ((__uint32_t)(cat->__msg_txt_offset ) & 0xff000000) >> 24) : __swap32md(cat->__msg_txt_offset )) || | |||
238 | remain / sizeof (*set) < nsets) | |||
239 | return (1); | |||
240 | ||||
241 | set = (struct _nls_set_hdr *) ((char *) catd->__data + sizeof (*cat)); | |||
242 | ||||
243 | /* make sure that msg has space for at least one index */ | |||
244 | if (remain - hdr_offset < sizeof(*msg)) | |||
245 | return (1); | |||
246 | ||||
247 | msg = (struct _nls_msg_hdr *) ((char *) catd->__data + sizeof (*cat) | |||
248 | + hdr_offset); | |||
249 | ||||
250 | /* validate and retrieve largest string offset from sets */ | |||
251 | off = 0; | |||
252 | for (i = 0; i < nsets; i++) { | |||
253 | index = ntohl(set[i].__index)(__uint32_t)(__builtin_constant_p(set[i].__index) ? (__uint32_t )(((__uint32_t)(set[i].__index) & 0xff) << 24 | ((__uint32_t )(set[i].__index) & 0xff00) << 8 | ((__uint32_t)(set [i].__index) & 0xff0000) >> 8 | ((__uint32_t)(set[i ].__index) & 0xff000000) >> 24) : __swap32md(set[i] .__index)); | |||
254 | nmsgs = ntohl(set[i].__nmsgs)(__uint32_t)(__builtin_constant_p(set[i].__nmsgs) ? (__uint32_t )(((__uint32_t)(set[i].__nmsgs) & 0xff) << 24 | ((__uint32_t )(set[i].__nmsgs) & 0xff00) << 8 | ((__uint32_t)(set [i].__nmsgs) & 0xff0000) >> 8 | ((__uint32_t)(set[i ].__nmsgs) & 0xff000000) >> 24) : __swap32md(set[i] .__nmsgs)); | |||
255 | /* set must contain at least one message */ | |||
256 | if (index < 0 || nmsgs < 1) | |||
257 | return (1); | |||
258 | ||||
259 | if (INT_MAX2147483647 - nmsgs < index) | |||
260 | return (1); | |||
261 | msgs = index + nmsgs; | |||
262 | ||||
263 | /* avoid msg index overflow */ | |||
264 | if ((remain - hdr_offset) / sizeof(*msg) < msgs) | |||
265 | return (1); | |||
266 | ||||
267 | /* retrieve largest string offset */ | |||
268 | for (j = index; j < nmsgs; j++) { | |||
269 | if (ntohl(msg[j].__offset)(__uint32_t)(__builtin_constant_p(msg[j].__offset) ? (__uint32_t )(((__uint32_t)(msg[j].__offset) & 0xff) << 24 | (( __uint32_t)(msg[j].__offset) & 0xff00) << 8 | ((__uint32_t )(msg[j].__offset) & 0xff0000) >> 8 | ((__uint32_t) (msg[j].__offset) & 0xff000000) >> 24) : __swap32md (msg[j].__offset)) > INT_MAX2147483647) | |||
270 | return (1); | |||
271 | off = MAXIMUM(off, ntohl(msg[j].__offset))(((off) > ((__uint32_t)(__builtin_constant_p(msg[j].__offset ) ? (__uint32_t)(((__uint32_t)(msg[j].__offset) & 0xff) << 24 | ((__uint32_t)(msg[j].__offset) & 0xff00) << 8 | ((__uint32_t)(msg[j].__offset) & 0xff0000) >> 8 | ((__uint32_t)(msg[j].__offset) & 0xff000000) >> 24 ) : __swap32md(msg[j].__offset)))) ? (off) : ((__uint32_t)(__builtin_constant_p (msg[j].__offset) ? (__uint32_t)(((__uint32_t)(msg[j].__offset ) & 0xff) << 24 | ((__uint32_t)(msg[j].__offset) & 0xff00) << 8 | ((__uint32_t)(msg[j].__offset) & 0xff0000 ) >> 8 | ((__uint32_t)(msg[j].__offset) & 0xff000000 ) >> 24) : __swap32md(msg[j].__offset)))); | |||
272 | } | |||
273 | } | |||
274 | ||||
275 | /* check if largest string offset is nul-terminated */ | |||
276 | if (remain - txt_offset < off || | |||
277 | memchr((char *) catd->__data + sizeof(*cat) + txt_offset + off, | |||
278 | '\0', remain - txt_offset - off) == NULL((void *)0)) | |||
279 | return (1); | |||
280 | ||||
281 | return (0); | |||
282 | } | |||
283 |