diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index 0db5911f9c40..2c3d3920dfed 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -7,7 +7,7 @@ SRCS+= __getosreldate.c __xuname.c \ _once_stub.c _pthread_stubs.c _rand48.c _spinlock_stub.c \ _thread_init.c \ - alarm.c arc4random.c assert.c basename.c check_utility_compat.c \ + alarm.c arc4random.c assert.c aux.c basename.c check_utility_compat.c \ clock.c closedir.c confstr.c \ crypt.c ctermid.c daemon.c devname.c dirname.c disklabel.c \ dlfcn.c drand48.c erand48.c err.c errlst.c errno.c \ diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index 42404bcc277c..5ba18604db6a 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -492,4 +492,6 @@ FBSDprivate_1.0 { _libc_sem_timedwait_compat; _libc_sem_post_compat; _libc_sem_getvalue_compat; + + __elf_aux_vector; }; diff --git a/lib/libc/gen/__getosreldate.c b/lib/libc/gen/__getosreldate.c index 7e26845d9e6a..980f9ef1fc58 100644 --- a/lib/libc/gen/__getosreldate.c +++ b/lib/libc/gen/__getosreldate.c @@ -29,6 +29,9 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include +#include "libc_private.h" int __getosreldate(void); @@ -51,7 +54,11 @@ __getosreldate(void) if (osreldate != 0) return (osreldate); - + + error = _elf_aux_info(AT_OSRELDATE, &osreldate, sizeof(osreldate)); + if (error == 0 && osreldate != 0) + return (osreldate); + oid[0] = CTL_KERN; oid[1] = KERN_OSRELDATE; osrel = 0; diff --git a/lib/libc/gen/aux.c b/lib/libc/gen/aux.c new file mode 100644 index 000000000000..b5c079bfde56 --- /dev/null +++ b/lib/libc/gen/aux.c @@ -0,0 +1,146 @@ +/*- + * Copyright 2010 Konstantin Belousov . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include +#include +#include +#include +#include +#include "un-namespace.h" +#include "libc_private.h" + +Elf_Auxinfo *__elf_aux_vector; + +static pthread_once_t aux_once = PTHREAD_ONCE_INIT; + +static int pagesize, osreldate, canary_len, ncpus, pagesizes_len; +static char *canary, *pagesizes; + +static void +init_aux(void) +{ + Elf_Auxinfo *aux; + + for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) { + switch (aux->a_type) { + case AT_CANARY: + canary = (char *)(aux->a_un.a_ptr); + break; + + case AT_CANARYLEN: + canary_len = aux->a_un.a_val; + break; + + case AT_PAGESIZES: + pagesizes = (char *)(aux->a_un.a_ptr); + break; + + case AT_PAGESIZESLEN: + pagesizes_len = aux->a_un.a_val; + break; + + case AT_PAGESZ: + pagesize = aux->a_un.a_val; + break; + + case AT_OSRELDATE: + osreldate = aux->a_un.a_val; + break; + + case AT_NCPUS: + ncpus = aux->a_un.a_val; + break; + } + } +} + +int +_elf_aux_info(int aux, void *buf, int buflen) +{ + int res; + + if (__elf_aux_vector == NULL) + return (ENOSYS); + _once(&aux_once, init_aux); + + switch (aux) { + case AT_CANARY: + if (canary != NULL && canary_len >= buflen) { + memcpy(buf, canary, buflen); + memset(canary, 0, canary_len); + canary = NULL; + res = 0; + } else + res = ENOENT; + break; + case AT_PAGESIZES: + if (pagesizes != NULL && pagesizes_len >= buflen) { + memcpy(buf, pagesizes, buflen); + res = 0; + } else + res = ENOENT; + break; + + case AT_PAGESZ: + if (buflen == sizeof(int)) { + if (pagesize != 0) { + *(int *)buf = pagesize; + res = 0; + } else + res = ENOENT; + } else + res = EINVAL; + break; + case AT_OSRELDATE: + if (buflen == sizeof(int)) { + if (osreldate != 0) { + *(int *)buf = osreldate; + res = 0; + } else + res = ENOENT; + } else + res = EINVAL; + break; + case AT_NCPUS: + if (buflen == sizeof(int)) { + if (ncpus != 0) { + *(int *)buf = ncpus; + res = 0; + } else + res = ENOENT; + } else + res = EINVAL; + break; + default: + res = ENOENT; + break; + } + return (res); +} diff --git a/lib/libc/gen/getosreldate.c b/lib/libc/gen/getosreldate.c index 086da6a70330..83bdc85aa26d 100644 --- a/lib/libc/gen/getosreldate.c +++ b/lib/libc/gen/getosreldate.c @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include @@ -45,15 +46,17 @@ getosreldate(void) int mib[2]; size_t size; int value; - char *temp; + if ((temp = getenv("OSVERSION"))) { + value = atoi(temp); + return (value); + } + mib[0] = CTL_KERN; mib[1] = KERN_OSRELDATE; size = sizeof value; if (sysctl(mib, 2, &value, &size, NULL, 0) == -1) return (-1); - if ((temp = getenv("OSVERSION"))) - value = atoi(temp); return (value); } diff --git a/lib/libc/gen/getpagesize.c b/lib/libc/gen/getpagesize.c index d796b9d77a04..f4b812861d72 100644 --- a/lib/libc/gen/getpagesize.c +++ b/lib/libc/gen/getpagesize.c @@ -36,8 +36,12 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include #include +#include "libc_private.h" + /* * This is unlikely to change over the running time of any * program, so we cache the result to save some syscalls. @@ -52,13 +56,20 @@ getpagesize() int mib[2]; static int value; size_t size; + int error; + + if (value != 0) + return (value); + + error = _elf_aux_info(AT_PAGESZ, &value, sizeof(value)); + if (error == 0 && value != 0) + return (value); + + mib[0] = CTL_HW; + mib[1] = HW_PAGESIZE; + size = sizeof value; + if (sysctl(mib, 2, &value, &size, NULL, 0) == -1) + return (-1); - if (!value) { - mib[0] = CTL_HW; - mib[1] = HW_PAGESIZE; - size = sizeof value; - if (sysctl(mib, 2, &value, &size, NULL, 0) == -1) - return (-1); - } return (value); } diff --git a/lib/libc/gen/getpagesizes.c b/lib/libc/gen/getpagesizes.c index b0de9390f88d..534fe9e1fefe 100644 --- a/lib/libc/gen/getpagesizes.c +++ b/lib/libc/gen/getpagesizes.c @@ -32,6 +32,9 @@ __FBSDID("$FreeBSD$"); #include #include +#include + +#include "libc_private.h" /* * Retrieves page size information from the system. Specifically, returns the @@ -51,7 +54,7 @@ getpagesizes(size_t pagesize[], int nelem) static u_long ps[MAXPAGESIZES]; static int nops; size_t size; - int i; + int error, i; if (nelem < 0 || (nelem > 0 && pagesize == NULL)) { errno = EINVAL; @@ -59,9 +62,13 @@ getpagesizes(size_t pagesize[], int nelem) } /* Cache the result of the sysctl(2). */ if (nops == 0) { + error = _elf_aux_info(AT_PAGESIZES, ps, sizeof(ps)); size = sizeof(ps); - if (sysctlbyname("hw.pagesizes", ps, &size, NULL, 0) == -1) - return (-1); + if (error != 0 || ps[0] == 0) { + if (sysctlbyname("hw.pagesizes", ps, &size, NULL, 0) + == -1) + return (-1); + } /* Count the number of page sizes that are supported. */ nops = size / sizeof(ps[0]); while (nops > 0 && ps[nops - 1] == 0) diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h index cb0b40740f46..570441b1f6fa 100644 --- a/lib/libc/include/libc_private.h +++ b/lib/libc/include/libc_private.h @@ -213,4 +213,6 @@ extern int __sys_fcntl(int, int, ...); /* execve() with PATH processing to implement posix_spawnp() */ int _execvpe(const char *, char * const *, char * const *); +int _elf_aux_info(int aux, void *buf, int buflen); + #endif /* _LIBC_PRIVATE_H_ */ diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c index 1b581d41327a..f1a13efd3a9e 100644 --- a/lib/libc/stdlib/malloc.c +++ b/lib/libc/stdlib/malloc.c @@ -180,6 +180,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -194,6 +195,8 @@ __FBSDID("$FreeBSD$"); #include "un-namespace.h" +#include "libc_private.h" + #define RB_COMPACT #include "rb.h" #if (defined(MALLOC_TCACHE) && defined(MALLOC_STATS)) @@ -5353,14 +5356,20 @@ small_size2bin_init_hard(void) static unsigned malloc_ncpus(void) { + int mib[2]; unsigned ret; - size_t retlen = sizeof(ret); - int mib[] = {CTL_HW, HW_NCPU}; + int error; + size_t len; - if (sysctl(mib, sizeof(mib) / sizeof(int), &ret, &retlen, - (void *)0, 0) == -1) { - /* Error. */ - ret = 1; + error = _elf_aux_info(AT_NCPUS, &ret, sizeof(ret)); + if (error != 0 || ret == 0) { + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + len = sizeof(ret); + if (sysctl(mib, 2, &ret, &len, (void *)NULL, 0) == -1) { + /* Error. */ + ret = 1; + } } return (ret); diff --git a/lib/libc/sys/stack_protector.c b/lib/libc/sys/stack_protector.c index 14c20eb4f0b8..b0108f9ff7a5 100644 --- a/lib/libc/sys/stack_protector.c +++ b/lib/libc/sys/stack_protector.c @@ -34,10 +34,13 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include #include #include #include #include +#include "libc_private.h" extern int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen); @@ -54,9 +57,14 @@ __guard_setup(void) { int mib[2]; size_t len; + int error; if (__stack_chk_guard[0] != 0) return; + error = _elf_aux_info(AT_CANARY, __stack_chk_guard, + sizeof(__stack_chk_guard)); + if (error == 0 && __stack_chk_guard[0] != 0) + return; mib[0] = CTL_KERN; mib[1] = KERN_ARND;