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