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 40 extern int _DYNAMIC; 41 #pragma weak _DYNAMIC 42 43 void *__elf_aux_vector; 44 45 #ifndef PIC 46 static pthread_once_t aux_vector_once = PTHREAD_ONCE_INIT; 47 48 static void 49 init_aux_vector_once(void) 50 { 51 Elf_Addr *sp; 52 53 sp = (Elf_Addr *)environ; 54 while (*sp++ != 0) 55 ; 56 __elf_aux_vector = (Elf_Auxinfo *)sp; 57 } 58 59 void 60 __init_elf_aux_vector(void) 61 { 62 63 if (&_DYNAMIC != NULL) 64 return; 65 _once(&aux_vector_once, init_aux_vector_once); 66 } 67 #endif 68 69 static bool aux_once = false; 70 static int pagesize, osreldate, canary_len, ncpus, pagesizes_len, bsdflags; 71 static int hwcap_present, hwcap2_present; 72 static char *canary, *pagesizes, *execpath; 73 static void *ps_strings, *timekeep; 74 static u_long hwcap, hwcap2; 75 static void *fxrng_seed_version; 76 static u_long usrstackbase, usrstacklim; 77 78 #ifdef __powerpc__ 79 static int powerpc_new_auxv_format = 0; 80 static void _init_aux_powerpc_fixup(void); 81 int _powerpc_elf_aux_info(int, void *, int); 82 #endif 83 84 /* 85 * This function might be called and actual body executed more than 86 * once in multithreading environment. Due to this, it is and must 87 * continue to be idempotent. All stores are atomic (no store 88 * tearing), because we only assign to int/long/ptr. 89 */ 90 static void 91 init_aux(void) 92 { 93 Elf_Auxinfo *aux; 94 95 if (aux_once) 96 return; 97 for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) { 98 switch (aux->a_type) { 99 case AT_BSDFLAGS: 100 bsdflags = aux->a_un.a_val; 101 break; 102 103 case AT_CANARY: 104 canary = (char *)(aux->a_un.a_ptr); 105 break; 106 107 case AT_CANARYLEN: 108 canary_len = aux->a_un.a_val; 109 break; 110 111 case AT_EXECPATH: 112 execpath = (char *)(aux->a_un.a_ptr); 113 break; 114 115 case AT_HWCAP: 116 hwcap_present = 1; 117 hwcap = (u_long)(aux->a_un.a_val); 118 break; 119 120 case AT_HWCAP2: 121 hwcap2_present = 1; 122 hwcap2 = (u_long)(aux->a_un.a_val); 123 break; 124 125 case AT_PAGESIZES: 126 pagesizes = (char *)(aux->a_un.a_ptr); 127 break; 128 129 case AT_PAGESIZESLEN: 130 pagesizes_len = aux->a_un.a_val; 131 break; 132 133 case AT_PAGESZ: 134 pagesize = aux->a_un.a_val; 135 break; 136 137 case AT_OSRELDATE: 138 osreldate = aux->a_un.a_val; 139 break; 140 141 case AT_NCPUS: 142 ncpus = aux->a_un.a_val; 143 break; 144 145 case AT_TIMEKEEP: 146 timekeep = aux->a_un.a_ptr; 147 break; 148 149 case AT_PS_STRINGS: 150 ps_strings = aux->a_un.a_ptr; 151 break; 152 153 case AT_FXRNG: 154 fxrng_seed_version = aux->a_un.a_ptr; 155 break; 156 157 case AT_USRSTACKBASE: 158 usrstackbase = aux->a_un.a_val; 159 break; 160 161 case AT_USRSTACKLIM: 162 usrstacklim = aux->a_un.a_val; 163 break; 164 #ifdef __powerpc__ 165 /* 166 * Since AT_STACKPROT is always set, and the common 167 * value 23 is mutually exclusive with the legacy powerpc 168 * value 21, the existence of AT_STACKPROT proves we are 169 * on the common format. 170 */ 171 case AT_STACKPROT: /* 23 */ 172 powerpc_new_auxv_format = 1; 173 break; 174 #endif 175 } 176 } 177 #ifdef __powerpc__ 178 if (!powerpc_new_auxv_format) 179 _init_aux_powerpc_fixup(); 180 #endif 181 182 aux_once = true; 183 } 184 185 #ifdef __powerpc__ 186 static void 187 _init_aux_powerpc_fixup(void) 188 { 189 Elf_Auxinfo *aux; 190 191 /* 192 * Before 1300070, PowerPC platforms had nonstandard numbering for 193 * the aux vector. When running old binaries, the kernel will pass 194 * the vector using the old numbering. Reload affected variables. 195 */ 196 for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) { 197 switch (aux->a_type) { 198 case AT_OLD_CANARY: 199 canary = (char *)(aux->a_un.a_ptr); 200 break; 201 case AT_OLD_CANARYLEN: 202 canary_len = aux->a_un.a_val; 203 break; 204 case AT_OLD_EXECPATH: 205 execpath = (char *)(aux->a_un.a_ptr); 206 break; 207 case AT_OLD_PAGESIZES: 208 pagesizes = (char *)(aux->a_un.a_ptr); 209 break; 210 case AT_OLD_PAGESIZESLEN: 211 pagesizes_len = aux->a_un.a_val; 212 break; 213 case AT_OLD_OSRELDATE: 214 osreldate = aux->a_un.a_val; 215 break; 216 case AT_OLD_NCPUS: 217 ncpus = aux->a_un.a_val; 218 break; 219 } 220 } 221 } 222 223 int 224 _powerpc_elf_aux_info(int aux, void *buf, int buflen) 225 { 226 227 /* 228 * If we are in the old auxv format, we need to translate the aux 229 * parameter of elf_aux_info() calls into the common auxv format. 230 * Internal libc calls always use the common format, and they 231 * directly call _elf_aux_info instead of using the weak symbol. 232 */ 233 if (!powerpc_new_auxv_format) { 234 switch (aux) { 235 case AT_OLD_EXECPATH: 236 aux = AT_EXECPATH; 237 break; 238 case AT_OLD_CANARY: 239 aux = AT_CANARY; 240 break; 241 case AT_OLD_CANARYLEN: 242 aux = AT_CANARYLEN; 243 break; 244 case AT_OLD_OSRELDATE: 245 aux = AT_OSRELDATE; 246 break; 247 case AT_OLD_NCPUS: 248 aux = AT_NCPUS; 249 break; 250 case AT_OLD_PAGESIZES: 251 aux = AT_PAGESIZES; 252 break; 253 case AT_OLD_PAGESIZESLEN: 254 aux = AT_PAGESIZESLEN; 255 break; 256 case AT_OLD_STACKPROT: 257 aux = AT_STACKPROT; 258 break; 259 } 260 } 261 return _elf_aux_info(aux, buf, buflen); 262 } 263 __weak_reference(_powerpc_elf_aux_info, elf_aux_info); 264 #else 265 __weak_reference(_elf_aux_info, elf_aux_info); 266 #endif 267 268 int 269 _elf_aux_info(int aux, void *buf, int buflen) 270 { 271 int res; 272 273 #ifndef PIC 274 __init_elf_aux_vector(); 275 #endif 276 if (__elf_aux_vector == NULL) 277 return (ENOSYS); 278 init_aux(); /* idempotent */ 279 280 if (buflen < 0) 281 return (EINVAL); 282 283 switch (aux) { 284 case AT_CANARY: 285 if (canary != NULL && canary_len >= buflen) { 286 memcpy(buf, canary, buflen); 287 memset(canary, 0, canary_len); 288 canary = NULL; 289 res = 0; 290 } else 291 res = ENOENT; 292 break; 293 case AT_EXECPATH: 294 if (execpath == NULL) 295 res = ENOENT; 296 else if (buf == NULL) 297 res = EINVAL; 298 else { 299 if (strlcpy(buf, execpath, buflen) >= 300 (unsigned int)buflen) 301 res = EINVAL; 302 else 303 res = 0; 304 } 305 break; 306 case AT_HWCAP: 307 if (hwcap_present && buflen == sizeof(u_long)) { 308 *(u_long *)buf = hwcap; 309 res = 0; 310 } else 311 res = ENOENT; 312 break; 313 case AT_HWCAP2: 314 if (hwcap2_present && buflen == sizeof(u_long)) { 315 *(u_long *)buf = hwcap2; 316 res = 0; 317 } else 318 res = ENOENT; 319 break; 320 case AT_PAGESIZES: 321 if (pagesizes != NULL && pagesizes_len >= buflen) { 322 memcpy(buf, pagesizes, buflen); 323 res = 0; 324 } else 325 res = ENOENT; 326 break; 327 case AT_PAGESZ: 328 if (buflen == sizeof(int)) { 329 if (pagesize != 0) { 330 *(int *)buf = pagesize; 331 res = 0; 332 } else 333 res = ENOENT; 334 } else 335 res = EINVAL; 336 break; 337 case AT_OSRELDATE: 338 if (buflen == sizeof(int)) { 339 if (osreldate != 0) { 340 *(int *)buf = osreldate; 341 res = 0; 342 } else 343 res = ENOENT; 344 } else 345 res = EINVAL; 346 break; 347 case AT_NCPUS: 348 if (buflen == sizeof(int)) { 349 if (ncpus != 0) { 350 *(int *)buf = ncpus; 351 res = 0; 352 } else 353 res = ENOENT; 354 } else 355 res = EINVAL; 356 break; 357 case AT_TIMEKEEP: 358 if (buflen == sizeof(void *)) { 359 if (timekeep != NULL) { 360 *(void **)buf = timekeep; 361 res = 0; 362 } else 363 res = ENOENT; 364 } else 365 res = EINVAL; 366 break; 367 case AT_BSDFLAGS: 368 if (buflen == sizeof(int)) { 369 *(int *)buf = bsdflags; 370 res = 0; 371 } else 372 res = EINVAL; 373 break; 374 case AT_PS_STRINGS: 375 if (buflen == sizeof(void *)) { 376 if (ps_strings != NULL) { 377 *(void **)buf = ps_strings; 378 res = 0; 379 } else 380 res = ENOENT; 381 } else 382 res = EINVAL; 383 break; 384 case AT_FXRNG: 385 if (buflen == sizeof(void *)) { 386 if (fxrng_seed_version != NULL) { 387 *(void **)buf = fxrng_seed_version; 388 res = 0; 389 } else 390 res = ENOENT; 391 } else 392 res = EINVAL; 393 break; 394 case AT_USRSTACKBASE: 395 if (buflen == sizeof(u_long)) { 396 if (usrstackbase != 0) { 397 *(u_long *)buf = usrstackbase; 398 res = 0; 399 } else 400 res = ENOENT; 401 } else 402 res = EINVAL; 403 break; 404 case AT_USRSTACKLIM: 405 if (buflen == sizeof(u_long)) { 406 if (usrstacklim != 0) { 407 *(u_long *)buf = usrstacklim; 408 res = 0; 409 } else 410 res = ENOENT; 411 } else 412 res = EINVAL; 413 break; 414 default: 415 res = ENOENT; 416 break; 417 } 418 return (res); 419 } 420