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