1 /*-
2 * Copyright 2010, 2012 Konstantin Belousov <kib@FreeBSD.ORG>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD: stable/9/lib/libc/gen/aux.c 240819 2012-09-22 12:38:19Z kib $");
29
30 #include "namespace.h"
31 #include <elf.h>
32 #include <errno.h>
33 #include <link.h>
34 #include <pthread.h>
35 #include <string.h>
36 #include "un-namespace.h"
37 #include "libc_private.h"
38
39 extern char **environ;
40 extern int _DYNAMIC;
41 #pragma weak _DYNAMIC
42
43 void *__elf_aux_vector;
44 static pthread_once_t aux_vector_once = PTHREAD_ONCE_INIT;
45
46 static void
init_aux_vector_once(void)47 init_aux_vector_once(void)
48 {
49 Elf_Addr *sp;
50
51 sp = (Elf_Addr *)environ;
52 while (*sp++ != 0)
53 ;
54 __elf_aux_vector = (Elf_Auxinfo *)sp;
55 }
56
57 void
__init_elf_aux_vector(void)58 __init_elf_aux_vector(void)
59 {
60
61 if (&_DYNAMIC != NULL)
62 return;
63 _once(&aux_vector_once, init_aux_vector_once);
64 }
65
66 static pthread_once_t aux_once = PTHREAD_ONCE_INIT;
67 static int pagesize, osreldate, canary_len, ncpus, pagesizes_len;
68 static char *canary, *pagesizes;
69 static void *timekeep;
70
71 static void
init_aux(void)72 init_aux(void)
73 {
74 Elf_Auxinfo *aux;
75
76 for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) {
77 switch (aux->a_type) {
78 case AT_CANARY:
79 canary = (char *)(aux->a_un.a_ptr);
80 break;
81
82 case AT_CANARYLEN:
83 canary_len = aux->a_un.a_val;
84 break;
85
86 case AT_PAGESIZES:
87 pagesizes = (char *)(aux->a_un.a_ptr);
88 break;
89
90 case AT_PAGESIZESLEN:
91 pagesizes_len = aux->a_un.a_val;
92 break;
93
94 case AT_PAGESZ:
95 pagesize = aux->a_un.a_val;
96 break;
97
98 case AT_OSRELDATE:
99 osreldate = aux->a_un.a_val;
100 break;
101
102 case AT_NCPUS:
103 ncpus = aux->a_un.a_val;
104 break;
105
106 case AT_TIMEKEEP:
107 timekeep = aux->a_un.a_ptr;
108 break;
109 }
110 }
111 }
112
113 int
_elf_aux_info(int aux,void * buf,int buflen)114 _elf_aux_info(int aux, void *buf, int buflen)
115 {
116 int res;
117
118 __init_elf_aux_vector();
119 if (__elf_aux_vector == NULL)
120 return (ENOSYS);
121 _once(&aux_once, init_aux);
122
123 switch (aux) {
124 case AT_CANARY:
125 if (canary != NULL && canary_len >= buflen) {
126 memcpy(buf, canary, buflen);
127 memset(canary, 0, canary_len);
128 canary = NULL;
129 res = 0;
130 } else
131 res = ENOENT;
132 break;
133 case AT_PAGESIZES:
134 if (pagesizes != NULL && pagesizes_len >= buflen) {
135 memcpy(buf, pagesizes, buflen);
136 res = 0;
137 } else
138 res = ENOENT;
139 break;
140
141 case AT_PAGESZ:
142 if (buflen == sizeof(int)) {
143 if (pagesize != 0) {
144 *(int *)buf = pagesize;
145 res = 0;
146 } else
147 res = ENOENT;
148 } else
149 res = EINVAL;
150 break;
151 case AT_OSRELDATE:
152 if (buflen == sizeof(int)) {
153 if (osreldate != 0) {
154 *(int *)buf = osreldate;
155 res = 0;
156 } else
157 res = ENOENT;
158 } else
159 res = EINVAL;
160 break;
161 case AT_NCPUS:
162 if (buflen == sizeof(int)) {
163 if (ncpus != 0) {
164 *(int *)buf = ncpus;
165 res = 0;
166 } else
167 res = ENOENT;
168 } else
169 res = EINVAL;
170 break;
171 case AT_TIMEKEEP:
172 if (buflen == sizeof(void *)) {
173 if (timekeep != NULL) {
174 *(void **)buf = timekeep;
175 res = 0;
176 } else
177 res = ENOENT;
178 } else
179 res = EINVAL;
180 break;
181 default:
182 res = ENOENT;
183 break;
184 }
185 return (res);
186 }
187