1 /* $NetBSD: ctype_.c,v 1.24 2025/09/15 00:11:54 riastradh Exp $ */ 2 3 /* 4 * Copyright (c) 1989 The Regents of the University of California. 5 * All rights reserved. 6 * (c) UNIX System Laboratories, Inc. 7 * All or some portions of this file are derived from material licensed 8 * to the University of California by American Telephone and Telegraph 9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 10 * the permission of UNIX System Laboratories, Inc. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #include <sys/cdefs.h> 38 #if defined(LIBC_SCCS) && !defined(lint) 39 #if 0 40 /*static char *sccsid = "from: @(#)ctype_.c 5.6 (Berkeley) 6/1/90";*/ 41 #else 42 __RCSID("$NetBSD: ctype_.c,v 1.24 2025/09/15 00:11:54 riastradh Exp $"); 43 #endif 44 #endif /* LIBC_SCCS and not lint */ 45 46 #include <sys/ctype_bits.h> 47 #include <sys/mman.h> 48 49 #include <stdio.h> 50 #include <string.h> 51 52 #include "ctype_guard.h" 53 #include "ctype_local.h" 54 55 #if EOF != -1 56 #error "EOF != -1" 57 #endif 58 59 #ifdef __BUILD_LEGACY 60 #define _C _COMPAT_C 61 #define _S _COMPAT_S 62 #define _U _COMPAT_U 63 #define _X _COMPAT_X 64 #define _L _COMPAT_L 65 #define _P _COMPAT_P 66 #define _B _COMPAT_B 67 #define _N _COMPAT_N 68 69 __ctype_table 70 static 71 const unsigned char _C_compat_bsdctype_guarded[_C_COMPAT_BSDCTYPE_GUARD + 72 1 + _CTYPE_NUM_CHARS] = { 73 _CTYPE_GUARD_INIT(_C_COMPAT_BSDCTYPE_GUARD, -1) 74 [_C_COMPAT_BSDCTYPE_GUARD] = 0, 75 _C, _C, _C, _C, _C, _C, _C, _C, 76 _C, _C|_S, _C|_S, _C|_S, _C|_S, _C|_S, _C, _C, 77 _C, _C, _C, _C, _C, _C, _C, _C, 78 _C, _C, _C, _C, _C, _C, _C, _C, 79 _S|_B, _P, _P, _P, _P, _P, _P, _P, 80 _P, _P, _P, _P, _P, _P, _P, _P, 81 _N, _N, _N, _N, _N, _N, _N, _N, 82 _N, _N, _P, _P, _P, _P, _P, _P, 83 _P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U, 84 _U, _U, _U, _U, _U, _U, _U, _U, 85 _U, _U, _U, _U, _U, _U, _U, _U, 86 _U, _U, _U, _P, _P, _P, _P, _P, 87 _P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L, 88 _L, _L, _L, _L, _L, _L, _L, _L, 89 _L, _L, _L, _L, _L, _L, _L, _L, 90 _L, _L, _L, _P, _P, _P, _P, _C 91 }; 92 __ctype_table_guarded(_C_compat_bsdctype, _C_compat_bsdctype_guarded, 93 1 + _CTYPE_NUM_CHARS, /*sizeof(unsigned char)*/1); 94 95 #undef _C 96 #undef _S 97 #undef _U 98 #undef _X 99 #undef _L 100 #undef _P 101 #undef _B 102 #undef _N 103 104 #ifdef __weak_alias 105 __weak_alias(_C_ctype_, _C_compat_bsdctype) 106 #endif 107 108 const unsigned char *_ctype_ = &_C_compat_bsdctype[0]; 109 #endif /* __BUILD_LEGACY */ 110 111 #define _A _CTYPE_A 112 #define _BL _CTYPE_BL 113 #define _C _CTYPE_C 114 #define _D _CTYPE_D 115 #define _G _CTYPE_G 116 #define _L _CTYPE_L 117 #define _P _CTYPE_P 118 #define _R _CTYPE_R 119 #define _S _CTYPE_S 120 #define _U _CTYPE_U 121 #define _X _CTYPE_X 122 123 __ctype_table 124 static const unsigned short _C_ctype_tab_guarded_[_C_CTYPE_TAB_GUARD + 125 1 + _CTYPE_NUM_CHARS] = { 126 _CTYPE_GUARD_INIT(_C_CTYPE_TAB_GUARD, -1) 127 [_C_CTYPE_TAB_GUARD] = 0, 128 _C, _C, _C, _C, 129 _C, _C, _C, _C, 130 _C, _BL|_C|_S, _C|_S, _C|_S, 131 _C|_S, _C|_S, _C, _C, 132 _C, _C, _C, _C, 133 _C, _C, _C, _C, 134 _C, _C, _C, _C, 135 _C, _C, _C, _C, 136 _BL|_R|_S, _G|_R|_P, _G|_R|_P, _G|_R|_P, 137 _G|_R|_P, _G|_R|_P, _G|_R|_P, _G|_R|_P, 138 _G|_R|_P, _G|_R|_P, _G|_R|_P, _G|_R|_P, 139 _G|_R|_P, _G|_R|_P, _G|_R|_P, _G|_R|_P, 140 _D|_G|_R|_X, _D|_G|_R|_X, _D|_G|_R|_X, _D|_G|_R|_X, 141 _D|_G|_R|_X, _D|_G|_R|_X, _D|_G|_R|_X, _D|_G|_R|_X, 142 _D|_G|_R|_X, _D|_G|_R|_X, _G|_R|_P, _G|_R|_P, 143 _G|_R|_P, _G|_R|_P, _G|_R|_P, _G|_R|_P, 144 _G|_R|_P, _A|_G|_R|_U|_X, _A|_G|_R|_U|_X, _A|_G|_R|_U|_X, 145 _A|_G|_R|_U|_X, _A|_G|_R|_U|_X, _A|_G|_R|_U|_X, _A|_G|_R|_U, 146 _A|_G|_R|_U, _A|_G|_R|_U, _A|_G|_R|_U, _A|_G|_R|_U, 147 _A|_G|_R|_U, _A|_G|_R|_U, _A|_G|_R|_U, _A|_G|_R|_U, 148 _A|_G|_R|_U, _A|_G|_R|_U, _A|_G|_R|_U, _A|_G|_R|_U, 149 _A|_G|_R|_U, _A|_G|_R|_U, _A|_G|_R|_U, _A|_G|_R|_U, 150 _A|_G|_R|_U, _A|_G|_R|_U, _A|_G|_R|_U, _G|_R|_P, 151 _G|_R|_P, _G|_R|_P, _G|_R|_P, _G|_R|_P, 152 _G|_R|_P, _A|_G|_L|_R|_X, _A|_G|_L|_R|_X, _A|_G|_L|_R|_X, 153 _A|_G|_L|_R|_X, _A|_G|_L|_R|_X, _A|_G|_L|_R|_X, _A|_G|_L|_R, 154 _A|_G|_L|_R, _A|_G|_L|_R, _A|_G|_L|_R, _A|_G|_L|_R, 155 _A|_G|_L|_R, _A|_G|_L|_R, _A|_G|_L|_R, _A|_G|_L|_R, 156 _A|_G|_L|_R, _A|_G|_L|_R, _A|_G|_L|_R, _A|_G|_L|_R, 157 _A|_G|_L|_R, _A|_G|_L|_R, _A|_G|_L|_R, _A|_G|_L|_R, 158 _A|_G|_L|_R, _A|_G|_L|_R, _A|_G|_L|_R, _G|_R|_P, 159 _G|_R|_P, _G|_R|_P, _G|_R|_P, _C, 160 }; 161 __ctype_table_guarded(_C_ctype_tab_, _C_ctype_tab_guarded_, 162 1 + _CTYPE_NUM_CHARS, __SIZEOF_SHORT__); 163 164 #undef _A 165 #undef _BL 166 #undef _C 167 #undef _D 168 #undef _G 169 #undef _L 170 #undef _P 171 #undef _R 172 #undef _S 173 #undef _U 174 #undef _X 175 176 const unsigned short *_ctype_tab_ = &_C_ctype_tab_[0]; 177 178 /* 179 * _allow_ctype_abuse() 180 * 181 * Internal subroutine to interpret environ and return true if 182 * LIBC_ALLOWCTYPEABUSE is defined, false if not. 183 * 184 * We use environ and strcmp directly to make sure this works 185 * inside constructors and to avoid pulling in all the 186 * stdlib/_env.c machinery if unnecessary. We cache it so we only 187 * add one traversal of environ to each process startup for the 188 * ctype, toupper, and tolower tables (not ideal -- rtld already 189 * does another traversal -- but better than adding multiple 190 * traversals). 191 * 192 * This query is also used by the out-of-line ctype logic in 193 * isctype.c outside a constructor, where it could use getenv, and 194 * perhaps support finer-grained distinctions -- like 195 * LIBC_ALLOWCTYPEABUSE=silent vs LIBC_ALLOWCTYPEABUSE=noisy. But 196 * until we feel the need to implement such finer distinctions, 197 * let's keep the logic of interpreting LIBC_ALLOWCTYPEABUSE 198 * together in one place. 199 */ 200 #ifndef RTLD_LOADER 201 #include "extern.h" /* environ */ 202 static bool 203 _allow_ctype_abuse(void) 204 { 205 const char vareq[] = "LIBC_ALLOWCTYPEABUSE="; 206 char *const *envp; 207 208 for (envp = environ; *envp != NULL; envp++) { 209 if (strncmp(*envp, vareq, strlen(vareq)) == 0) { 210 return true; 211 } 212 } 213 return false; 214 } 215 #endif 216 217 #if _CTYPE_GUARD_PAGE 218 219 static enum { 220 ABUSE_UNDETERMINED = 0, 221 ABUSE_ALLOWED, 222 ABUSE_TRAPPED, 223 } allow_ctype_abuse_cache; 224 225 /* 226 * allow_ctype_abuse() 227 * 228 * True if LIBC_ALLOWCTYPEABUSE is defined in the environment, 229 * false if not. May reflect the environment any time between 230 * process startup and now. 231 */ 232 __dso_hidden 233 bool 234 allow_ctype_abuse(void) 235 { 236 237 if (allow_ctype_abuse_cache != ABUSE_UNDETERMINED) 238 return allow_ctype_abuse_cache == ABUSE_ALLOWED; 239 return _allow_ctype_abuse(); 240 } 241 242 /* 243 * constructor_allow_ctype_abuse() 244 * 245 * True if LIBC_ALLOWCTYPEABUSE is defined in the environment, 246 * false if not. May be used only in an ELF constructor. 247 */ 248 __dso_hidden 249 bool 250 constructor_allow_ctype_abuse(void) 251 { 252 253 if (allow_ctype_abuse_cache != ABUSE_UNDETERMINED) 254 return allow_ctype_abuse_cache == ABUSE_ALLOWED; 255 if (_allow_ctype_abuse()) { 256 allow_ctype_abuse_cache = ABUSE_ALLOWED; 257 return true; 258 } else { 259 allow_ctype_abuse_cache = ABUSE_TRAPPED; 260 return false; 261 } 262 } 263 264 __attribute__((constructor)) 265 static void 266 _C_ctype_tab_guard_init(void) 267 { 268 269 if (constructor_allow_ctype_abuse()) 270 return; 271 #ifdef __BUILD_LEGACY 272 (void)mprotect(__UNCONST(_C_compat_bsdctype_guarded), 273 _CTYPE_GUARD_SIZE, PROT_NONE); 274 #endif /* __BUILD_LEGACY */ 275 (void)mprotect(__UNCONST(_C_ctype_tab_guarded_), 276 _CTYPE_GUARD_SIZE, PROT_NONE); 277 } 278 279 #else 280 281 #ifndef RTLD_LOADER 282 __dso_hidden 283 bool 284 allow_ctype_abuse(void) 285 { 286 287 return _allow_ctype_abuse(); 288 } 289 #endif 290 291 #endif /* _CTYPE_GUARD_PAGE */ 292