xref: /freebsd/lib/libsys/auxv.c (revision 2f4cbf459d4af41977be30eab2f6f7d7e9f9b5b5)
14c33415eSBrooks Davis /*-
24c33415eSBrooks Davis  * SPDX-License-Identifier: BSD-2-Clause
34c33415eSBrooks Davis  *
44c33415eSBrooks Davis  * Copyright 2010, 2012 Konstantin Belousov <kib@FreeBSD.ORG>.
54c33415eSBrooks Davis  * All rights reserved.
64c33415eSBrooks Davis  *
74c33415eSBrooks Davis  * Redistribution and use in source and binary forms, with or without
84c33415eSBrooks Davis  * modification, are permitted provided that the following conditions
94c33415eSBrooks Davis  * are met:
104c33415eSBrooks Davis  * 1. Redistributions of source code must retain the above copyright
114c33415eSBrooks Davis  *    notice, this list of conditions and the following disclaimer.
124c33415eSBrooks Davis  * 2. Redistributions in binary form must reproduce the above copyright
134c33415eSBrooks Davis  *    notice, this list of conditions and the following disclaimer in the
144c33415eSBrooks Davis  *    documentation and/or other materials provided with the distribution.
154c33415eSBrooks Davis  *
164c33415eSBrooks Davis  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
174c33415eSBrooks Davis  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
184c33415eSBrooks Davis  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
194c33415eSBrooks Davis  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
204c33415eSBrooks Davis  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
214c33415eSBrooks Davis  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
224c33415eSBrooks Davis  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
234c33415eSBrooks Davis  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
244c33415eSBrooks Davis  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
254c33415eSBrooks Davis  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
264c33415eSBrooks Davis  *
274c33415eSBrooks Davis  */
284c33415eSBrooks Davis 
294c33415eSBrooks Davis #include "namespace.h"
304c33415eSBrooks Davis #include <elf.h>
314c33415eSBrooks Davis #include <errno.h>
324c33415eSBrooks Davis #include <link.h>
334c33415eSBrooks Davis #include <pthread.h>
348271d9b9SKonstantin Belousov #include <stdbool.h>
354c33415eSBrooks Davis #include <string.h>
364c33415eSBrooks Davis #include <sys/auxv.h>
374c33415eSBrooks Davis #include "un-namespace.h"
384c33415eSBrooks Davis #include "libc_private.h"
39*2f4cbf45SKonstantin Belousov #include <machine/atomic.h>
404c33415eSBrooks Davis 
414c33415eSBrooks Davis extern int _DYNAMIC;
424c33415eSBrooks Davis #pragma weak _DYNAMIC
434c33415eSBrooks Davis 
444c33415eSBrooks Davis void *__elf_aux_vector;
458271d9b9SKonstantin Belousov 
468271d9b9SKonstantin Belousov #ifndef PIC
474c33415eSBrooks Davis static pthread_once_t aux_vector_once = PTHREAD_ONCE_INIT;
484c33415eSBrooks Davis 
494c33415eSBrooks Davis static void
504c33415eSBrooks Davis init_aux_vector_once(void)
514c33415eSBrooks Davis {
524c33415eSBrooks Davis 	Elf_Addr *sp;
534c33415eSBrooks Davis 
544c33415eSBrooks Davis 	sp = (Elf_Addr *)environ;
554c33415eSBrooks Davis 	while (*sp++ != 0)
564c33415eSBrooks Davis 		;
574c33415eSBrooks Davis 	__elf_aux_vector = (Elf_Auxinfo *)sp;
584c33415eSBrooks Davis }
594c33415eSBrooks Davis 
604c33415eSBrooks Davis void
614c33415eSBrooks Davis __init_elf_aux_vector(void)
624c33415eSBrooks Davis {
634c33415eSBrooks Davis 
644c33415eSBrooks Davis 	if (&_DYNAMIC != NULL)
654c33415eSBrooks Davis 		return;
664c33415eSBrooks Davis 	_once(&aux_vector_once, init_aux_vector_once);
674c33415eSBrooks Davis }
688271d9b9SKonstantin Belousov #endif
694c33415eSBrooks Davis 
70*2f4cbf45SKonstantin Belousov static int aux_once;
714c33415eSBrooks Davis static int pagesize, osreldate, canary_len, ncpus, pagesizes_len, bsdflags;
724c33415eSBrooks Davis static int hwcap_present, hwcap2_present;
734c33415eSBrooks Davis static char *canary, *pagesizes, *execpath;
744c33415eSBrooks Davis static void *ps_strings, *timekeep;
754c33415eSBrooks Davis static u_long hwcap, hwcap2;
764c33415eSBrooks Davis static void *fxrng_seed_version;
774c33415eSBrooks Davis static u_long usrstackbase, usrstacklim;
784c33415eSBrooks Davis 
794c33415eSBrooks Davis #ifdef __powerpc__
804c33415eSBrooks Davis static int powerpc_new_auxv_format = 0;
814c33415eSBrooks Davis static void _init_aux_powerpc_fixup(void);
824c33415eSBrooks Davis int _powerpc_elf_aux_info(int, void *, int);
834c33415eSBrooks Davis #endif
844c33415eSBrooks Davis 
858271d9b9SKonstantin Belousov /*
868271d9b9SKonstantin Belousov  * This function might be called and actual body executed more than
878271d9b9SKonstantin Belousov  * once in multithreading environment.  Due to this, it is and must
888271d9b9SKonstantin Belousov  * continue to be idempotent.  All stores are atomic (no store
898271d9b9SKonstantin Belousov  * tearing), because we only assign to int/long/ptr.
908271d9b9SKonstantin Belousov  */
914c33415eSBrooks Davis static void
924c33415eSBrooks Davis init_aux(void)
934c33415eSBrooks Davis {
944c33415eSBrooks Davis 	Elf_Auxinfo *aux;
954c33415eSBrooks Davis 
96*2f4cbf45SKonstantin Belousov 	if (atomic_load_acq_int(&aux_once))
978271d9b9SKonstantin Belousov 		return;
984c33415eSBrooks Davis 	for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) {
994c33415eSBrooks Davis 		switch (aux->a_type) {
1004c33415eSBrooks Davis 		case AT_BSDFLAGS:
1014c33415eSBrooks Davis 			bsdflags = aux->a_un.a_val;
1024c33415eSBrooks Davis 			break;
1034c33415eSBrooks Davis 
1044c33415eSBrooks Davis 		case AT_CANARY:
1054c33415eSBrooks Davis 			canary = (char *)(aux->a_un.a_ptr);
1064c33415eSBrooks Davis 			break;
1074c33415eSBrooks Davis 
1084c33415eSBrooks Davis 		case AT_CANARYLEN:
1094c33415eSBrooks Davis 			canary_len = aux->a_un.a_val;
1104c33415eSBrooks Davis 			break;
1114c33415eSBrooks Davis 
1124c33415eSBrooks Davis 		case AT_EXECPATH:
1134c33415eSBrooks Davis 			execpath = (char *)(aux->a_un.a_ptr);
1144c33415eSBrooks Davis 			break;
1154c33415eSBrooks Davis 
1164c33415eSBrooks Davis 		case AT_HWCAP:
1174c33415eSBrooks Davis 			hwcap_present = 1;
1184c33415eSBrooks Davis 			hwcap = (u_long)(aux->a_un.a_val);
1194c33415eSBrooks Davis 			break;
1204c33415eSBrooks Davis 
1214c33415eSBrooks Davis 		case AT_HWCAP2:
1224c33415eSBrooks Davis 			hwcap2_present = 1;
1234c33415eSBrooks Davis 			hwcap2 = (u_long)(aux->a_un.a_val);
1244c33415eSBrooks Davis 			break;
1254c33415eSBrooks Davis 
1264c33415eSBrooks Davis 		case AT_PAGESIZES:
1274c33415eSBrooks Davis 			pagesizes = (char *)(aux->a_un.a_ptr);
1284c33415eSBrooks Davis 			break;
1294c33415eSBrooks Davis 
1304c33415eSBrooks Davis 		case AT_PAGESIZESLEN:
1314c33415eSBrooks Davis 			pagesizes_len = aux->a_un.a_val;
1324c33415eSBrooks Davis 			break;
1334c33415eSBrooks Davis 
1344c33415eSBrooks Davis 		case AT_PAGESZ:
1354c33415eSBrooks Davis 			pagesize = aux->a_un.a_val;
1364c33415eSBrooks Davis 			break;
1374c33415eSBrooks Davis 
1384c33415eSBrooks Davis 		case AT_OSRELDATE:
1394c33415eSBrooks Davis 			osreldate = aux->a_un.a_val;
1404c33415eSBrooks Davis 			break;
1414c33415eSBrooks Davis 
1424c33415eSBrooks Davis 		case AT_NCPUS:
1434c33415eSBrooks Davis 			ncpus = aux->a_un.a_val;
1444c33415eSBrooks Davis 			break;
1454c33415eSBrooks Davis 
1464c33415eSBrooks Davis 		case AT_TIMEKEEP:
1474c33415eSBrooks Davis 			timekeep = aux->a_un.a_ptr;
1484c33415eSBrooks Davis 			break;
1494c33415eSBrooks Davis 
1504c33415eSBrooks Davis 		case AT_PS_STRINGS:
1514c33415eSBrooks Davis 			ps_strings = aux->a_un.a_ptr;
1524c33415eSBrooks Davis 			break;
1534c33415eSBrooks Davis 
1544c33415eSBrooks Davis 		case AT_FXRNG:
1554c33415eSBrooks Davis 			fxrng_seed_version = aux->a_un.a_ptr;
1564c33415eSBrooks Davis 			break;
1574c33415eSBrooks Davis 
1584c33415eSBrooks Davis 		case AT_USRSTACKBASE:
1594c33415eSBrooks Davis 			usrstackbase = aux->a_un.a_val;
1604c33415eSBrooks Davis 			break;
1614c33415eSBrooks Davis 
1624c33415eSBrooks Davis 		case AT_USRSTACKLIM:
1634c33415eSBrooks Davis 			usrstacklim = aux->a_un.a_val;
1644c33415eSBrooks Davis 			break;
1654c33415eSBrooks Davis #ifdef __powerpc__
1664c33415eSBrooks Davis 		/*
1674c33415eSBrooks Davis 		 * Since AT_STACKPROT is always set, and the common
1684c33415eSBrooks Davis 		 * value 23 is mutually exclusive with the legacy powerpc
1694c33415eSBrooks Davis 		 * value 21, the existence of AT_STACKPROT proves we are
1704c33415eSBrooks Davis 		 * on the common format.
1714c33415eSBrooks Davis 		 */
1724c33415eSBrooks Davis 		case AT_STACKPROT:	/* 23 */
1734c33415eSBrooks Davis 			powerpc_new_auxv_format = 1;
1744c33415eSBrooks Davis 			break;
1754c33415eSBrooks Davis #endif
1764c33415eSBrooks Davis 		}
1774c33415eSBrooks Davis 	}
1784c33415eSBrooks Davis #ifdef __powerpc__
1794c33415eSBrooks Davis 	if (!powerpc_new_auxv_format)
1804c33415eSBrooks Davis 		_init_aux_powerpc_fixup();
1814c33415eSBrooks Davis #endif
1828271d9b9SKonstantin Belousov 
183*2f4cbf45SKonstantin Belousov 	atomic_store_rel_int(&aux_once, 1);
1844c33415eSBrooks Davis }
1854c33415eSBrooks Davis 
1864c33415eSBrooks Davis #ifdef __powerpc__
1874c33415eSBrooks Davis static void
1884c33415eSBrooks Davis _init_aux_powerpc_fixup(void)
1894c33415eSBrooks Davis {
1904c33415eSBrooks Davis 	Elf_Auxinfo *aux;
1914c33415eSBrooks Davis 
1924c33415eSBrooks Davis 	/*
1934c33415eSBrooks Davis 	 * Before 1300070, PowerPC platforms had nonstandard numbering for
1944c33415eSBrooks Davis 	 * the aux vector. When running old binaries, the kernel will pass
1954c33415eSBrooks Davis 	 * the vector using the old numbering. Reload affected variables.
1964c33415eSBrooks Davis 	 */
1974c33415eSBrooks Davis 	for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) {
1984c33415eSBrooks Davis 		switch (aux->a_type) {
1994c33415eSBrooks Davis 		case AT_OLD_CANARY:
2004c33415eSBrooks Davis 			canary = (char *)(aux->a_un.a_ptr);
2014c33415eSBrooks Davis 			break;
2024c33415eSBrooks Davis 		case AT_OLD_CANARYLEN:
2034c33415eSBrooks Davis 			canary_len = aux->a_un.a_val;
2044c33415eSBrooks Davis 			break;
2054c33415eSBrooks Davis 		case AT_OLD_EXECPATH:
2064c33415eSBrooks Davis 			execpath = (char *)(aux->a_un.a_ptr);
2074c33415eSBrooks Davis 			break;
2084c33415eSBrooks Davis 		case AT_OLD_PAGESIZES:
2094c33415eSBrooks Davis 			pagesizes = (char *)(aux->a_un.a_ptr);
2104c33415eSBrooks Davis 			break;
2114c33415eSBrooks Davis 		case AT_OLD_PAGESIZESLEN:
2124c33415eSBrooks Davis 			pagesizes_len = aux->a_un.a_val;
2134c33415eSBrooks Davis 			break;
2144c33415eSBrooks Davis 		case AT_OLD_OSRELDATE:
2154c33415eSBrooks Davis 			osreldate = aux->a_un.a_val;
2164c33415eSBrooks Davis 			break;
2174c33415eSBrooks Davis 		case AT_OLD_NCPUS:
2184c33415eSBrooks Davis 			ncpus = aux->a_un.a_val;
2194c33415eSBrooks Davis 			break;
2204c33415eSBrooks Davis 		}
2214c33415eSBrooks Davis 	}
2224c33415eSBrooks Davis }
2234c33415eSBrooks Davis 
2244c33415eSBrooks Davis int
2254c33415eSBrooks Davis _powerpc_elf_aux_info(int aux, void *buf, int buflen)
2264c33415eSBrooks Davis {
2274c33415eSBrooks Davis 
2284c33415eSBrooks Davis 	/*
2294c33415eSBrooks Davis 	 * If we are in the old auxv format, we need to translate the aux
2304c33415eSBrooks Davis 	 * parameter of elf_aux_info() calls into the common auxv format.
2314c33415eSBrooks Davis 	 * Internal libc calls always use the common format, and they
2324c33415eSBrooks Davis 	 * directly call _elf_aux_info instead of using the weak symbol.
2334c33415eSBrooks Davis 	 */
2344c33415eSBrooks Davis 	if (!powerpc_new_auxv_format) {
2354c33415eSBrooks Davis 		switch (aux) {
2364c33415eSBrooks Davis 		case AT_OLD_EXECPATH:
2374c33415eSBrooks Davis 			aux = AT_EXECPATH;
2384c33415eSBrooks Davis 			break;
2394c33415eSBrooks Davis 		case AT_OLD_CANARY:
2404c33415eSBrooks Davis 			aux = AT_CANARY;
2414c33415eSBrooks Davis 			break;
2424c33415eSBrooks Davis 		case AT_OLD_CANARYLEN:
2434c33415eSBrooks Davis 			aux = AT_CANARYLEN;
2444c33415eSBrooks Davis 			break;
2454c33415eSBrooks Davis 		case AT_OLD_OSRELDATE:
2464c33415eSBrooks Davis 			aux = AT_OSRELDATE;
2474c33415eSBrooks Davis 			break;
2484c33415eSBrooks Davis 		case AT_OLD_NCPUS:
2494c33415eSBrooks Davis 			aux = AT_NCPUS;
2504c33415eSBrooks Davis 			break;
2514c33415eSBrooks Davis 		case AT_OLD_PAGESIZES:
2524c33415eSBrooks Davis 			aux = AT_PAGESIZES;
2534c33415eSBrooks Davis 			break;
2544c33415eSBrooks Davis 		case AT_OLD_PAGESIZESLEN:
2554c33415eSBrooks Davis 			aux = AT_PAGESIZESLEN;
2564c33415eSBrooks Davis 			break;
2574c33415eSBrooks Davis 		case AT_OLD_STACKPROT:
2584c33415eSBrooks Davis 			aux = AT_STACKPROT;
2594c33415eSBrooks Davis 			break;
2604c33415eSBrooks Davis 		}
2614c33415eSBrooks Davis 	}
2624c33415eSBrooks Davis 	return _elf_aux_info(aux, buf, buflen);
2634c33415eSBrooks Davis }
2644c33415eSBrooks Davis __weak_reference(_powerpc_elf_aux_info, elf_aux_info);
2654c33415eSBrooks Davis #else
2664c33415eSBrooks Davis __weak_reference(_elf_aux_info, elf_aux_info);
2674c33415eSBrooks Davis #endif
2684c33415eSBrooks Davis 
2694c33415eSBrooks Davis int
2704c33415eSBrooks Davis _elf_aux_info(int aux, void *buf, int buflen)
2714c33415eSBrooks Davis {
2724c33415eSBrooks Davis 	int res;
2734c33415eSBrooks Davis 
2748271d9b9SKonstantin Belousov #ifndef PIC
2754c33415eSBrooks Davis 	__init_elf_aux_vector();
2768271d9b9SKonstantin Belousov #endif
2774c33415eSBrooks Davis 	if (__elf_aux_vector == NULL)
2784c33415eSBrooks Davis 		return (ENOSYS);
2798271d9b9SKonstantin Belousov 	init_aux();	/* idempotent */
2804c33415eSBrooks Davis 
2814c33415eSBrooks Davis 	if (buflen < 0)
2824c33415eSBrooks Davis 		return (EINVAL);
2834c33415eSBrooks Davis 
2844c33415eSBrooks Davis 	switch (aux) {
2854c33415eSBrooks Davis 	case AT_CANARY:
2864c33415eSBrooks Davis 		if (canary != NULL && canary_len >= buflen) {
2874c33415eSBrooks Davis 			memcpy(buf, canary, buflen);
2884c33415eSBrooks Davis 			memset(canary, 0, canary_len);
2894c33415eSBrooks Davis 			canary = NULL;
2904c33415eSBrooks Davis 			res = 0;
2914c33415eSBrooks Davis 		} else
2924c33415eSBrooks Davis 			res = ENOENT;
2934c33415eSBrooks Davis 		break;
2944c33415eSBrooks Davis 	case AT_EXECPATH:
2954c33415eSBrooks Davis 		if (execpath == NULL)
2964c33415eSBrooks Davis 			res = ENOENT;
2974c33415eSBrooks Davis 		else if (buf == NULL)
2984c33415eSBrooks Davis 			res = EINVAL;
2994c33415eSBrooks Davis 		else {
3004c33415eSBrooks Davis 			if (strlcpy(buf, execpath, buflen) >=
3014c33415eSBrooks Davis 			    (unsigned int)buflen)
3024c33415eSBrooks Davis 				res = EINVAL;
3034c33415eSBrooks Davis 			else
3044c33415eSBrooks Davis 				res = 0;
3054c33415eSBrooks Davis 		}
3064c33415eSBrooks Davis 		break;
3074c33415eSBrooks Davis 	case AT_HWCAP:
3084c33415eSBrooks Davis 		if (hwcap_present && buflen == sizeof(u_long)) {
3094c33415eSBrooks Davis 			*(u_long *)buf = hwcap;
3104c33415eSBrooks Davis 			res = 0;
3114c33415eSBrooks Davis 		} else
3124c33415eSBrooks Davis 			res = ENOENT;
3134c33415eSBrooks Davis 		break;
3144c33415eSBrooks Davis 	case AT_HWCAP2:
3154c33415eSBrooks Davis 		if (hwcap2_present && buflen == sizeof(u_long)) {
3164c33415eSBrooks Davis 			*(u_long *)buf = hwcap2;
3174c33415eSBrooks Davis 			res = 0;
3184c33415eSBrooks Davis 		} else
3194c33415eSBrooks Davis 			res = ENOENT;
3204c33415eSBrooks Davis 		break;
3214c33415eSBrooks Davis 	case AT_PAGESIZES:
3224c33415eSBrooks Davis 		if (pagesizes != NULL && pagesizes_len >= buflen) {
3234c33415eSBrooks Davis 			memcpy(buf, pagesizes, buflen);
3244c33415eSBrooks Davis 			res = 0;
3254c33415eSBrooks Davis 		} else
3264c33415eSBrooks Davis 			res = ENOENT;
3274c33415eSBrooks Davis 		break;
3284c33415eSBrooks Davis 	case AT_PAGESZ:
3294c33415eSBrooks Davis 		if (buflen == sizeof(int)) {
3304c33415eSBrooks Davis 			if (pagesize != 0) {
3314c33415eSBrooks Davis 				*(int *)buf = pagesize;
3324c33415eSBrooks Davis 				res = 0;
3334c33415eSBrooks Davis 			} else
3344c33415eSBrooks Davis 				res = ENOENT;
3354c33415eSBrooks Davis 		} else
3364c33415eSBrooks Davis 			res = EINVAL;
3374c33415eSBrooks Davis 		break;
3384c33415eSBrooks Davis 	case AT_OSRELDATE:
3394c33415eSBrooks Davis 		if (buflen == sizeof(int)) {
3404c33415eSBrooks Davis 			if (osreldate != 0) {
3414c33415eSBrooks Davis 				*(int *)buf = osreldate;
3424c33415eSBrooks Davis 				res = 0;
3434c33415eSBrooks Davis 			} else
3444c33415eSBrooks Davis 				res = ENOENT;
3454c33415eSBrooks Davis 		} else
3464c33415eSBrooks Davis 			res = EINVAL;
3474c33415eSBrooks Davis 		break;
3484c33415eSBrooks Davis 	case AT_NCPUS:
3494c33415eSBrooks Davis 		if (buflen == sizeof(int)) {
3504c33415eSBrooks Davis 			if (ncpus != 0) {
3514c33415eSBrooks Davis 				*(int *)buf = ncpus;
3524c33415eSBrooks Davis 				res = 0;
3534c33415eSBrooks Davis 			} else
3544c33415eSBrooks Davis 				res = ENOENT;
3554c33415eSBrooks Davis 		} else
3564c33415eSBrooks Davis 			res = EINVAL;
3574c33415eSBrooks Davis 		break;
3584c33415eSBrooks Davis 	case AT_TIMEKEEP:
3594c33415eSBrooks Davis 		if (buflen == sizeof(void *)) {
3604c33415eSBrooks Davis 			if (timekeep != NULL) {
3614c33415eSBrooks Davis 				*(void **)buf = timekeep;
3624c33415eSBrooks Davis 				res = 0;
3634c33415eSBrooks Davis 			} else
3644c33415eSBrooks Davis 				res = ENOENT;
3654c33415eSBrooks Davis 		} else
3664c33415eSBrooks Davis 			res = EINVAL;
3674c33415eSBrooks Davis 		break;
3684c33415eSBrooks Davis 	case AT_BSDFLAGS:
3694c33415eSBrooks Davis 		if (buflen == sizeof(int)) {
3704c33415eSBrooks Davis 			*(int *)buf = bsdflags;
3714c33415eSBrooks Davis 			res = 0;
3724c33415eSBrooks Davis 		} else
3734c33415eSBrooks Davis 			res = EINVAL;
3744c33415eSBrooks Davis 		break;
3754c33415eSBrooks Davis 	case AT_PS_STRINGS:
3764c33415eSBrooks Davis 		if (buflen == sizeof(void *)) {
3774c33415eSBrooks Davis 			if (ps_strings != NULL) {
3784c33415eSBrooks Davis 				*(void **)buf = ps_strings;
3794c33415eSBrooks Davis 				res = 0;
3804c33415eSBrooks Davis 			} else
3814c33415eSBrooks Davis 				res = ENOENT;
3824c33415eSBrooks Davis 		} else
3834c33415eSBrooks Davis 			res = EINVAL;
3844c33415eSBrooks Davis 		break;
3854c33415eSBrooks Davis 	case AT_FXRNG:
3864c33415eSBrooks Davis 		if (buflen == sizeof(void *)) {
3874c33415eSBrooks Davis 			if (fxrng_seed_version != NULL) {
3884c33415eSBrooks Davis 				*(void **)buf = fxrng_seed_version;
3894c33415eSBrooks Davis 				res = 0;
3904c33415eSBrooks Davis 			} else
3914c33415eSBrooks Davis 				res = ENOENT;
3924c33415eSBrooks Davis 		} else
3934c33415eSBrooks Davis 			res = EINVAL;
3944c33415eSBrooks Davis 		break;
3954c33415eSBrooks Davis 	case AT_USRSTACKBASE:
3964c33415eSBrooks Davis 		if (buflen == sizeof(u_long)) {
3974c33415eSBrooks Davis 			if (usrstackbase != 0) {
3984c33415eSBrooks Davis 				*(u_long *)buf = usrstackbase;
3994c33415eSBrooks Davis 				res = 0;
4004c33415eSBrooks Davis 			} else
4014c33415eSBrooks Davis 				res = ENOENT;
4024c33415eSBrooks Davis 		} else
4034c33415eSBrooks Davis 			res = EINVAL;
4044c33415eSBrooks Davis 		break;
4054c33415eSBrooks Davis 	case AT_USRSTACKLIM:
4064c33415eSBrooks Davis 		if (buflen == sizeof(u_long)) {
4074c33415eSBrooks Davis 			if (usrstacklim != 0) {
4084c33415eSBrooks Davis 				*(u_long *)buf = usrstacklim;
4094c33415eSBrooks Davis 				res = 0;
4104c33415eSBrooks Davis 			} else
4114c33415eSBrooks Davis 				res = ENOENT;
4124c33415eSBrooks Davis 		} else
4134c33415eSBrooks Davis 			res = EINVAL;
4144c33415eSBrooks Davis 		break;
4154c33415eSBrooks Davis 	default:
4164c33415eSBrooks Davis 		res = ENOENT;
4174c33415eSBrooks Davis 		break;
4184c33415eSBrooks Davis 	}
4194c33415eSBrooks Davis 	return (res);
4204c33415eSBrooks Davis }
421