1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright 2010, 2012 Konstantin Belousov <kib@FreeBSD.ORG>. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 */ 28 29 #include "namespace.h" 30 #include <elf.h> 31 #include <errno.h> 32 #include <link.h> 33 #include <pthread.h> 34 #include <stdbool.h> 35 #include <string.h> 36 #include <sys/auxv.h> 37 #include "un-namespace.h" 38 #include "libc_private.h" 39 #include <machine/atomic.h> 40 41 extern int _DYNAMIC; 42 #pragma weak _DYNAMIC 43 44 void *__elf_aux_vector; 45 46 #ifndef PIC 47 static pthread_once_t aux_vector_once = PTHREAD_ONCE_INIT; 48 49 static void 50 init_aux_vector_once(void) 51 { 52 Elf_Addr *sp; 53 54 sp = (Elf_Addr *)environ; 55 while (*sp++ != 0) 56 ; 57 __elf_aux_vector = (Elf_Auxinfo *)sp; 58 } 59 60 void 61 __init_elf_aux_vector(void) 62 { 63 64 if (&_DYNAMIC != NULL) 65 return; 66 _once(&aux_vector_once, init_aux_vector_once); 67 } 68 #endif 69 70 static int aux_once; 71 static int pagesize, osreldate, canary_len, ncpus, pagesizes_len, bsdflags; 72 static int hwcap_present, hwcap2_present; 73 static char *canary, *pagesizes, *execpath; 74 static void *ps_strings, *timekeep; 75 static u_long hwcap, hwcap2; 76 static void *fxrng_seed_version; 77 static u_long usrstackbase, usrstacklim; 78 79 #ifdef __powerpc__ 80 static int powerpc_new_auxv_format = 0; 81 static void _init_aux_powerpc_fixup(void); 82 int _powerpc_elf_aux_info(int, void *, int); 83 #endif 84 85 /* 86 * This function might be called and actual body executed more than 87 * once in multithreading environment. Due to this, it is and must 88 * continue to be idempotent. All stores are atomic (no store 89 * tearing), because we only assign to int/long/ptr. 90 */ 91 static void 92 init_aux(void) 93 { 94 Elf_Auxinfo *aux; 95 96 if (atomic_load_acq_int(&aux_once)) 97 return; 98 for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) { 99 switch (aux->a_type) { 100 case AT_BSDFLAGS: 101 bsdflags = aux->a_un.a_val; 102 break; 103 104 case AT_CANARY: 105 canary = (char *)(aux->a_un.a_ptr); 106 break; 107 108 case AT_CANARYLEN: 109 canary_len = aux->a_un.a_val; 110 break; 111 112 case AT_EXECPATH: 113 execpath = (char *)(aux->a_un.a_ptr); 114 break; 115 116 case AT_HWCAP: 117 hwcap_present = 1; 118 hwcap = (u_long)(aux->a_un.a_val); 119 break; 120 121 case AT_HWCAP2: 122 hwcap2_present = 1; 123 hwcap2 = (u_long)(aux->a_un.a_val); 124 break; 125 126 case AT_PAGESIZES: 127 pagesizes = (char *)(aux->a_un.a_ptr); 128 break; 129 130 case AT_PAGESIZESLEN: 131 pagesizes_len = aux->a_un.a_val; 132 break; 133 134 case AT_PAGESZ: 135 pagesize = aux->a_un.a_val; 136 break; 137 138 case AT_OSRELDATE: 139 osreldate = aux->a_un.a_val; 140 break; 141 142 case AT_NCPUS: 143 ncpus = aux->a_un.a_val; 144 break; 145 146 case AT_TIMEKEEP: 147 timekeep = aux->a_un.a_ptr; 148 break; 149 150 case AT_PS_STRINGS: 151 ps_strings = aux->a_un.a_ptr; 152 break; 153 154 case AT_FXRNG: 155 fxrng_seed_version = aux->a_un.a_ptr; 156 break; 157 158 case AT_USRSTACKBASE: 159 usrstackbase = aux->a_un.a_val; 160 break; 161 162 case AT_USRSTACKLIM: 163 usrstacklim = aux->a_un.a_val; 164 break; 165 #ifdef __powerpc__ 166 /* 167 * Since AT_STACKPROT is always set, and the common 168 * value 23 is mutually exclusive with the legacy powerpc 169 * value 21, the existence of AT_STACKPROT proves we are 170 * on the common format. 171 */ 172 case AT_STACKPROT: /* 23 */ 173 powerpc_new_auxv_format = 1; 174 break; 175 #endif 176 } 177 } 178 #ifdef __powerpc__ 179 if (!powerpc_new_auxv_format) 180 _init_aux_powerpc_fixup(); 181 #endif 182 183 atomic_store_rel_int(&aux_once, 1); 184 } 185 186 #ifdef __powerpc__ 187 static void 188 _init_aux_powerpc_fixup(void) 189 { 190 Elf_Auxinfo *aux; 191 192 /* 193 * Before 1300070, PowerPC platforms had nonstandard numbering for 194 * the aux vector. When running old binaries, the kernel will pass 195 * the vector using the old numbering. Reload affected variables. 196 */ 197 for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) { 198 switch (aux->a_type) { 199 case AT_OLD_CANARY: 200 canary = (char *)(aux->a_un.a_ptr); 201 break; 202 case AT_OLD_CANARYLEN: 203 canary_len = aux->a_un.a_val; 204 break; 205 case AT_OLD_EXECPATH: 206 execpath = (char *)(aux->a_un.a_ptr); 207 break; 208 case AT_OLD_PAGESIZES: 209 pagesizes = (char *)(aux->a_un.a_ptr); 210 break; 211 case AT_OLD_PAGESIZESLEN: 212 pagesizes_len = aux->a_un.a_val; 213 break; 214 case AT_OLD_OSRELDATE: 215 osreldate = aux->a_un.a_val; 216 break; 217 case AT_OLD_NCPUS: 218 ncpus = aux->a_un.a_val; 219 break; 220 } 221 } 222 } 223 224 int 225 _powerpc_elf_aux_info(int aux, void *buf, int buflen) 226 { 227 228 /* 229 * If we are in the old auxv format, we need to translate the aux 230 * parameter of elf_aux_info() calls into the common auxv format. 231 * Internal libc calls always use the common format, and they 232 * directly call _elf_aux_info instead of using the weak symbol. 233 */ 234 if (!powerpc_new_auxv_format) { 235 switch (aux) { 236 case AT_OLD_EXECPATH: 237 aux = AT_EXECPATH; 238 break; 239 case AT_OLD_CANARY: 240 aux = AT_CANARY; 241 break; 242 case AT_OLD_CANARYLEN: 243 aux = AT_CANARYLEN; 244 break; 245 case AT_OLD_OSRELDATE: 246 aux = AT_OSRELDATE; 247 break; 248 case AT_OLD_NCPUS: 249 aux = AT_NCPUS; 250 break; 251 case AT_OLD_PAGESIZES: 252 aux = AT_PAGESIZES; 253 break; 254 case AT_OLD_PAGESIZESLEN: 255 aux = AT_PAGESIZESLEN; 256 break; 257 case AT_OLD_STACKPROT: 258 aux = AT_STACKPROT; 259 break; 260 } 261 } 262 return _elf_aux_info(aux, buf, buflen); 263 } 264 __weak_reference(_powerpc_elf_aux_info, elf_aux_info); 265 #else 266 __weak_reference(_elf_aux_info, elf_aux_info); 267 #endif 268 269 int 270 _elf_aux_info(int aux, void *buf, int buflen) 271 { 272 int res; 273 274 #ifndef PIC 275 __init_elf_aux_vector(); 276 #endif 277 if (__elf_aux_vector == NULL) 278 return (ENOSYS); 279 init_aux(); /* idempotent */ 280 281 if (buflen < 0) 282 return (EINVAL); 283 284 switch (aux) { 285 case AT_CANARY: 286 if (canary != NULL && canary_len >= buflen) { 287 memcpy(buf, canary, buflen); 288 memset(canary, 0, canary_len); 289 canary = NULL; 290 res = 0; 291 } else 292 res = ENOENT; 293 break; 294 case AT_EXECPATH: 295 if (execpath == NULL) 296 res = ENOENT; 297 else if (buf == NULL) 298 res = EINVAL; 299 else { 300 if (strlcpy(buf, execpath, buflen) >= 301 (unsigned int)buflen) 302 res = EINVAL; 303 else 304 res = 0; 305 } 306 break; 307 case AT_HWCAP: 308 if (hwcap_present && buflen == sizeof(u_long)) { 309 *(u_long *)buf = hwcap; 310 res = 0; 311 } else 312 res = ENOENT; 313 break; 314 case AT_HWCAP2: 315 if (hwcap2_present && buflen == sizeof(u_long)) { 316 *(u_long *)buf = hwcap2; 317 res = 0; 318 } else 319 res = ENOENT; 320 break; 321 case AT_PAGESIZES: 322 if (pagesizes != NULL && pagesizes_len >= buflen) { 323 memcpy(buf, pagesizes, buflen); 324 res = 0; 325 } else 326 res = ENOENT; 327 break; 328 case AT_PAGESZ: 329 if (buflen == sizeof(int)) { 330 if (pagesize != 0) { 331 *(int *)buf = pagesize; 332 res = 0; 333 } else 334 res = ENOENT; 335 } else 336 res = EINVAL; 337 break; 338 case AT_OSRELDATE: 339 if (buflen == sizeof(int)) { 340 if (osreldate != 0) { 341 *(int *)buf = osreldate; 342 res = 0; 343 } else 344 res = ENOENT; 345 } else 346 res = EINVAL; 347 break; 348 case AT_NCPUS: 349 if (buflen == sizeof(int)) { 350 if (ncpus != 0) { 351 *(int *)buf = ncpus; 352 res = 0; 353 } else 354 res = ENOENT; 355 } else 356 res = EINVAL; 357 break; 358 case AT_TIMEKEEP: 359 if (buflen == sizeof(void *)) { 360 if (timekeep != NULL) { 361 *(void **)buf = timekeep; 362 res = 0; 363 } else 364 res = ENOENT; 365 } else 366 res = EINVAL; 367 break; 368 case AT_BSDFLAGS: 369 if (buflen == sizeof(int)) { 370 *(int *)buf = bsdflags; 371 res = 0; 372 } else 373 res = EINVAL; 374 break; 375 case AT_PS_STRINGS: 376 if (buflen == sizeof(void *)) { 377 if (ps_strings != NULL) { 378 *(void **)buf = ps_strings; 379 res = 0; 380 } else 381 res = ENOENT; 382 } else 383 res = EINVAL; 384 break; 385 case AT_FXRNG: 386 if (buflen == sizeof(void *)) { 387 if (fxrng_seed_version != NULL) { 388 *(void **)buf = fxrng_seed_version; 389 res = 0; 390 } else 391 res = ENOENT; 392 } else 393 res = EINVAL; 394 break; 395 case AT_USRSTACKBASE: 396 if (buflen == sizeof(u_long)) { 397 if (usrstackbase != 0) { 398 *(u_long *)buf = usrstackbase; 399 res = 0; 400 } else 401 res = ENOENT; 402 } else 403 res = EINVAL; 404 break; 405 case AT_USRSTACKLIM: 406 if (buflen == sizeof(u_long)) { 407 if (usrstacklim != 0) { 408 *(u_long *)buf = usrstacklim; 409 res = 0; 410 } else 411 res = ENOENT; 412 } else 413 res = EINVAL; 414 break; 415 default: 416 res = ENOENT; 417 break; 418 } 419 return (res); 420 } 421