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