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