Home | History | Annotate | Line # | Download | only in gen
      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