Update.
[glibc.git] / sysdeps / generic / dl-sysdep.c
blob1b00775d72fb7fcebe7988af9c6f3ff1741fb4e1
1 /* Operating system support for run-time dynamic linker. Generic Unix version.
2 Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
20 #include <elf.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <sys/mman.h>
29 #include <ldsodefs.h>
30 #include <stdio-common/_itoa.h>
31 #include <fpu_control.h>
33 #include <entry.h>
34 #include <dl-machine.h>
35 #include <dl-procinfo.h>
37 extern int _dl_argc;
38 extern char **_dl_argv;
39 extern char **_environ;
40 extern size_t _dl_pagesize;
41 extern const char *_dl_platform;
42 extern unsigned long int _dl_hwcap;
43 extern size_t _dl_platformlen;
44 extern fpu_control_t _dl_fpu_control;
45 extern void _end;
46 extern void ENTRY_POINT (void);
48 /* Protect SUID program against misuse of file descriptors. */
49 extern void __libc_check_standard_fds (void);
51 ElfW(Addr) _dl_base_addr;
52 int __libc_enable_secure;
53 int __libc_multiple_libcs = 0; /* Defining this here avoids the inclusion
54 of init-first. */
55 /* This variable contains the lowest stack address ever used. */
56 void *__libc_stack_end;
57 static ElfW(auxv_t) *_dl_auxv;
58 unsigned long int _dl_hwcap_mask = HWCAP_IMPORTANT;
61 #ifndef DL_FIND_ARG_COMPONENTS
62 #define DL_FIND_ARG_COMPONENTS(cookie, argc, argv, envp, auxp) \
63 do { \
64 void **_tmp; \
65 (argc) = *(long *) cookie; \
66 (argv) = (char **) cookie + 1; \
67 (envp) = (argv) + (argc) + 1; \
68 for (_tmp = (void **) (envp); *_tmp; ++_tmp) \
69 continue; \
70 (auxp) = (void *) ++_tmp; \
71 } while (0)
72 #endif
75 ElfW(Addr)
76 _dl_sysdep_start (void **start_argptr,
77 void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phnum,
78 ElfW(Addr) *user_entry))
80 const ElfW(Phdr) *phdr = NULL;
81 ElfW(Word) phnum = 0;
82 ElfW(Addr) user_entry;
83 ElfW(auxv_t) *av;
84 uid_t uid = 0;
85 uid_t euid = 0;
86 gid_t gid = 0;
87 gid_t egid = 0;
88 unsigned int seen;
90 DL_FIND_ARG_COMPONENTS (start_argptr, _dl_argc, _dl_argv, _environ, _dl_auxv);
92 user_entry = (ElfW(Addr)) &ENTRY_POINT;
93 _dl_platform = NULL; /* Default to nothing known about the platform. */
95 seen = 0;
96 #define M(type) (1 << (type))
98 for (av = _dl_auxv; av->a_type != AT_NULL; seen |= M ((++av)->a_type))
99 switch (av->a_type)
101 case AT_PHDR:
102 phdr = av->a_un.a_ptr;
103 break;
104 case AT_PHNUM:
105 phnum = av->a_un.a_val;
106 break;
107 case AT_PAGESZ:
108 _dl_pagesize = av->a_un.a_val;
109 break;
110 case AT_ENTRY:
111 user_entry = av->a_un.a_val;
112 break;
113 case AT_BASE:
114 _dl_base_addr = av->a_un.a_val;
115 break;
116 case AT_UID:
117 uid = av->a_un.a_val;
118 break;
119 case AT_GID:
120 gid = av->a_un.a_val;
121 break;
122 case AT_EUID:
123 euid = av->a_un.a_val;
124 break;
125 case AT_EGID:
126 egid = av->a_un.a_val;
127 break;
128 case AT_PLATFORM:
129 _dl_platform = av->a_un.a_ptr;
130 break;
131 case AT_HWCAP:
132 _dl_hwcap = av->a_un.a_val;
133 break;
134 case AT_FPUCW:
135 _dl_fpu_control = av->a_un.a_val;
136 break;
139 /* Linux doesn't provide us with any of these values on the stack
140 when the dynamic linker is run directly as a program. */
142 #define SEE(UID, uid) if ((seen & M (AT_##UID)) == 0) uid = __get##uid ()
143 SEE (UID, uid);
144 SEE (GID, gid);
145 SEE (EUID, euid);
146 SEE (EGID, egid);
148 __libc_enable_secure = uid != euid || gid != egid;
150 if (_dl_pagesize == 0)
151 _dl_pagesize = __getpagesize ();
153 #ifdef DL_SYSDEP_INIT
154 DL_SYSDEP_INIT;
155 #endif
157 #ifdef DL_PLATFORM_INIT
158 DL_PLATFORM_INIT;
159 #endif
161 /* Determine the length of the platform name. */
162 if (_dl_platform != NULL)
163 _dl_platformlen = strlen (_dl_platform);
165 if (__sbrk (0) == &_end)
166 /* The dynamic linker was run as a program, and so the initial break
167 starts just after our bss, at &_end. The malloc in dl-minimal.c
168 will consume the rest of this page, so tell the kernel to move the
169 break up that far. When the user program examines its break, it
170 will see this new value and not clobber our data. */
171 __sbrk (_dl_pagesize - ((&_end - (void *) 0) & (_dl_pagesize - 1)));
173 /* If this is a SUID program we make sure that FDs 0, 1, and 2 are
174 allocated. If necessary we are doing it ourself. If it is not
175 possible we stop the program. */
176 if (__builtin_expect (__libc_enable_secure, 0))
177 __libc_check_standard_fds ();
179 (*dl_main) (phdr, phnum, &user_entry);
180 return user_entry;
183 void
184 _dl_sysdep_start_cleanup (void)
188 void
189 internal_function
190 _dl_show_auxv (void)
192 char buf[64];
193 ElfW(auxv_t) *av;
195 /* Terminate string. */
196 buf[63] = '\0';
198 for (av = _dl_auxv; av->a_type != AT_NULL; ++av)
199 switch (av->a_type)
201 case AT_PHDR:
202 _dl_sysdep_message ("AT_PHDR: 0x",
203 _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
204 16, 0),
205 "\n", NULL);
206 break;
207 case AT_PHNUM:
208 _dl_sysdep_message ("AT_PHNUM: ",
209 _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
210 10, 0),
211 "\n", NULL);
212 break;
213 case AT_PAGESZ:
214 _dl_sysdep_message ("AT_PAGESZ: ",
215 _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
216 10, 0),
217 "\n", NULL);
218 break;
219 case AT_ENTRY:
220 _dl_sysdep_message ("AT_ENTRY: 0x",
221 _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
222 16, 0),
223 "\n", NULL);
224 break;
225 case AT_BASE:
226 _dl_sysdep_message ("AT_BASE: 0x",
227 _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
228 16, 0),
229 "\n", NULL);
230 break;
231 case AT_UID:
232 _dl_sysdep_message ("AT_UID: ",
233 _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
234 10, 0),
235 "\n", NULL);
236 break;
237 case AT_GID:
238 _dl_sysdep_message ("AT_GID: ",
239 _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
240 10, 0),
241 "\n", NULL);
242 break;
243 case AT_EUID:
244 _dl_sysdep_message ("AT_EUID: ",
245 _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
246 10, 0),
247 "\n", NULL);
248 break;
249 case AT_EGID:
250 _dl_sysdep_message ("AT_EGID: ",
251 _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
252 10, 0),
253 "\n", NULL);
254 break;
255 case AT_PLATFORM:
256 _dl_sysdep_message ("AT_PLATFORM: ", av->a_un.a_ptr, "\n", NULL);
257 break;
258 case AT_HWCAP:
259 _dl_hwcap = av->a_un.a_val;
260 if (_dl_procinfo (_dl_hwcap) < 0)
261 _dl_sysdep_message ("AT_HWCAP: ",
262 _itoa_word (_dl_hwcap, buf + sizeof buf - 1,
263 16, 0),
264 "\n", NULL);
265 break;
266 case AT_FPUCW:
267 _dl_sysdep_message ("AT_FPUCW: ",
268 _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
269 10, 0),
270 "\n", NULL);
271 break;
276 /* Return an array of useful/necessary hardware capability names. */
277 const struct r_strlenpair *
278 internal_function
279 _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
280 size_t *max_capstrlen)
282 /* Determine how many important bits are set. */
283 unsigned long int masked = _dl_hwcap & _dl_hwcap_mask;
284 size_t cnt = platform != NULL;
285 size_t n, m;
286 size_t total;
287 struct r_strlenpair *temp;
288 struct r_strlenpair *result;
289 struct r_strlenpair *rp;
290 char *cp;
292 /* Count the number of bits set in the masked value. */
293 for (n = 0; (~((1UL << n) - 1) & masked) != 0; ++n)
294 if ((masked & (1UL << n)) != 0)
295 ++cnt;
297 if (cnt == 0)
299 /* If we have platform name and no important capability we only have
300 the base directory to search. */
301 result = (struct r_strlenpair *) malloc (sizeof (*result));
302 if (result == NULL)
304 no_memory:
305 _dl_signal_error (ENOMEM, NULL, "cannot create capability list");
308 result[0].str = (char *) result; /* Does not really matter. */
309 result[0].len = 0;
311 *sz = 1;
312 return result;
315 /* Create temporary data structure to generate result table. */
316 temp = (struct r_strlenpair *) alloca (cnt * sizeof (*temp));
317 m = 0;
318 for (n = 0; masked != 0; ++n)
319 if ((masked & (1UL << n)) != 0)
321 temp[m].str = _dl_hwcap_string (n);
322 temp[m].len = strlen (temp[m].str);
323 masked ^= 1UL << n;
324 ++m;
326 if (platform != NULL)
328 temp[m].str = platform;
329 temp[m].len = platform_len;
330 ++m;
333 /* Determine the total size of all strings together. */
334 if (cnt == 1)
335 total = temp[0].len;
336 else
338 total = (1 << (cnt - 2)) * (temp[0].len + temp[cnt - 1].len + 2);
339 for (n = 1; n + 1 < cnt; ++n)
340 total += (1 << (cnt - 3)) * (temp[n].len + 1);
343 /* The result structure: we use a very compressed way to store the
344 various combinations of capability names. */
345 *sz = 1 << cnt;
346 result = (struct r_strlenpair *) malloc (*sz * sizeof (*result) + total);
347 if (result == NULL)
348 goto no_memory;
350 if (cnt == 1)
352 result[0].str = (char *) (result + *sz);
353 result[0].len = temp[0].len + 1;
354 result[1].str = (char *) (result + *sz);
355 result[1].len = 0;
356 cp = __mempcpy ((char *) (result + *sz), temp[0].str, temp[0].len);
357 *cp = '/';
358 *sz = 2;
359 *max_capstrlen = result[0].len;
361 return result;
364 /* Fill in the information. This follows the following scheme
365 (indeces from TEMP for four strings):
366 entry #0: 0, 1, 2, 3 binary: 1111
367 #1: 0, 1, 3 1101
368 #2: 0, 2, 3 1011
369 #3: 0, 3 1001
370 This allows the representation of all possible combinations of
371 capability names in the string. First generate the strings. */
372 result[1].str = result[0].str = cp = (char *) (result + *sz);
373 #define add(idx) \
374 cp = __mempcpy (__mempcpy (cp, temp[idx].str, temp[idx].len), "/", 1);
375 if (cnt == 2)
377 add (1);
378 add (0);
380 else
382 n = 1 << cnt;
385 n -= 2;
387 /* We always add the last string. */
388 add (cnt - 1);
390 /* Add the strings which have the bit set in N. */
391 for (m = cnt - 2; m > 0; --m)
392 if ((n & (1 << m)) != 0)
393 add (m);
395 /* Always add the first string. */
396 add (0);
398 while (n != 0);
400 #undef add
402 /* Now we are ready to install the string pointers and length. */
403 for (n = 0; n < (1 << cnt); ++n)
404 result[n].len = 0;
405 n = cnt;
408 size_t mask = 1 << --n;
410 rp = result;
411 for (m = 1 << cnt; m > 0; ++rp)
412 if ((--m & mask) != 0)
413 rp->len += temp[n].len + 1;
415 while (n != 0);
417 /* The first half of the strings all include the first string. */
418 n = (1 << cnt) - 2;
419 rp = &result[2];
420 while (n != (1 << (cnt - 1)))
422 if ((n & 1) != 0)
423 rp[0].str = rp[-2].str + rp[-2].len;
424 else
425 rp[0].str = rp[-1].str;
426 ++rp;
427 --n;
430 /* The second have starts right after the first part of the string of
431 corresponding entry in the first half. */
434 rp[0].str = rp[-(1 << (cnt - 1))].str + temp[cnt - 1].len + 1;
435 ++rp;
437 while (--n != 0);
439 /* The maximum string length. */
440 *max_capstrlen = result[0].len;
442 return result;