]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/generic/dl-sysdep.c
Update.
[thirdparty/glibc.git] / sysdeps / generic / dl-sysdep.c
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.
4
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.
9
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.
14
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. */
19
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>
32
33 #include <entry.h>
34 #include <dl-machine.h>
35 #include <dl-procinfo.h>
36 #include <dl-osinfo.h>
37
38 extern int _dl_argc;
39 extern char **_dl_argv;
40 extern char **_environ;
41 extern size_t _dl_pagesize;
42 extern int _dl_clktck;
43 extern const char *_dl_platform;
44 extern unsigned long int _dl_hwcap;
45 extern size_t _dl_platformlen;
46 extern fpu_control_t _dl_fpu_control;
47 extern void _end;
48 extern void ENTRY_POINT (void);
49
50 /* Protect SUID program against misuse of file descriptors. */
51 extern void __libc_check_standard_fds (void);
52
53 ElfW(Addr) _dl_base_addr;
54 int __libc_enable_secure;
55 int __libc_multiple_libcs = 0; /* Defining this here avoids the inclusion
56 of init-first. */
57 /* This variable contains the lowest stack address ever used. */
58 void *__libc_stack_end;
59 static ElfW(auxv_t) *_dl_auxv;
60 unsigned long int _dl_hwcap_mask = HWCAP_IMPORTANT;
61
62
63 #ifndef DL_FIND_ARG_COMPONENTS
64 # define DL_FIND_ARG_COMPONENTS(cookie, argc, argv, envp, auxp) \
65 do { \
66 void **_tmp; \
67 (argc) = *(long int *) cookie; \
68 (argv) = (char **) ((long int *) cookie + 1); \
69 (envp) = (argv) + (argc) + 1; \
70 for (_tmp = (void **) (envp); *_tmp; ++_tmp) \
71 continue; \
72 (auxp) = (void *) ++_tmp; \
73 } while (0)
74 #endif
75
76
77 ElfW(Addr)
78 _dl_sysdep_start (void **start_argptr,
79 void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phnum,
80 ElfW(Addr) *user_entry))
81 {
82 const ElfW(Phdr) *phdr = NULL;
83 ElfW(Word) phnum = 0;
84 ElfW(Addr) user_entry;
85 ElfW(auxv_t) *av;
86 uid_t uid = 0;
87 uid_t euid = 0;
88 gid_t gid = 0;
89 gid_t egid = 0;
90 unsigned int seen;
91
92 DL_FIND_ARG_COMPONENTS (start_argptr, _dl_argc, _dl_argv, _environ,
93 _dl_auxv);
94
95 user_entry = (ElfW(Addr)) &ENTRY_POINT;
96 _dl_platform = NULL; /* Default to nothing known about the platform. */
97
98 seen = 0;
99 #define M(type) (1 << (type))
100
101 for (av = _dl_auxv; av->a_type != AT_NULL; seen |= M ((++av)->a_type))
102 switch (av->a_type)
103 {
104 case AT_PHDR:
105 phdr = av->a_un.a_ptr;
106 break;
107 case AT_PHNUM:
108 phnum = av->a_un.a_val;
109 break;
110 case AT_PAGESZ:
111 _dl_pagesize = av->a_un.a_val;
112 break;
113 case AT_ENTRY:
114 user_entry = av->a_un.a_val;
115 break;
116 case AT_BASE:
117 _dl_base_addr = av->a_un.a_val;
118 break;
119 case AT_UID:
120 uid = av->a_un.a_val;
121 break;
122 case AT_GID:
123 gid = av->a_un.a_val;
124 break;
125 case AT_EUID:
126 euid = av->a_un.a_val;
127 break;
128 case AT_EGID:
129 egid = av->a_un.a_val;
130 break;
131 case AT_PLATFORM:
132 _dl_platform = av->a_un.a_ptr;
133 break;
134 case AT_HWCAP:
135 _dl_hwcap = av->a_un.a_val;
136 break;
137 case AT_CLKTCK:
138 _dl_clktck = av->a_un.a_val;
139 break;
140 case AT_FPUCW:
141 _dl_fpu_control = av->a_un.a_val;
142 break;
143 }
144
145 #ifdef DL_SYSDEP_OSCHECK
146 DL_SYSDEP_OSCHECK (dl_fatal);
147 #endif
148
149 /* Linux doesn't provide us with any of these values on the stack
150 when the dynamic linker is run directly as a program. */
151
152 #define SEE(UID, uid) if ((seen & M (AT_##UID)) == 0) uid = __get##uid ()
153 SEE (UID, uid);
154 SEE (GID, gid);
155 SEE (EUID, euid);
156 SEE (EGID, egid);
157
158 __libc_enable_secure = uid != euid || gid != egid;
159
160 if (_dl_pagesize == 0)
161 _dl_pagesize = __getpagesize ();
162
163 #ifdef DL_SYSDEP_INIT
164 DL_SYSDEP_INIT;
165 #endif
166
167 #ifdef DL_PLATFORM_INIT
168 DL_PLATFORM_INIT;
169 #endif
170
171 /* Determine the length of the platform name. */
172 if (_dl_platform != NULL)
173 _dl_platformlen = strlen (_dl_platform);
174
175 if (__sbrk (0) == &_end)
176 /* The dynamic linker was run as a program, and so the initial break
177 starts just after our bss, at &_end. The malloc in dl-minimal.c
178 will consume the rest of this page, so tell the kernel to move the
179 break up that far. When the user program examines its break, it
180 will see this new value and not clobber our data. */
181 __sbrk (_dl_pagesize - ((&_end - (void *) 0) & (_dl_pagesize - 1)));
182
183 /* If this is a SUID program we make sure that FDs 0, 1, and 2 are
184 allocated. If necessary we are doing it ourself. If it is not
185 possible we stop the program. */
186 if (__builtin_expect (__libc_enable_secure, 0))
187 __libc_check_standard_fds ();
188
189 (*dl_main) (phdr, phnum, &user_entry);
190 return user_entry;
191 }
192
193 void
194 internal_function
195 _dl_sysdep_start_cleanup (void)
196 {
197 }
198
199 void
200 internal_function
201 _dl_show_auxv (void)
202 {
203 char buf[64];
204 ElfW(auxv_t) *av;
205
206 /* Terminate string. */
207 buf[63] = '\0';
208
209 for (av = _dl_auxv; av->a_type != AT_NULL; ++av)
210 switch (av->a_type)
211 {
212 case AT_PHDR:
213 _dl_sysdep_message ("AT_PHDR: 0x",
214 _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
215 16, 0),
216 "\n", NULL);
217 break;
218 case AT_PHNUM:
219 _dl_sysdep_message ("AT_PHNUM: ",
220 _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
221 10, 0),
222 "\n", NULL);
223 break;
224 case AT_PAGESZ:
225 _dl_sysdep_message ("AT_PAGESZ: ",
226 _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
227 10, 0),
228 "\n", NULL);
229 break;
230 case AT_ENTRY:
231 _dl_sysdep_message ("AT_ENTRY: 0x",
232 _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
233 16, 0),
234 "\n", NULL);
235 break;
236 case AT_BASE:
237 _dl_sysdep_message ("AT_BASE: 0x",
238 _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
239 16, 0),
240 "\n", NULL);
241 break;
242 case AT_UID:
243 _dl_sysdep_message ("AT_UID: ",
244 _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
245 10, 0),
246 "\n", NULL);
247 break;
248 case AT_GID:
249 _dl_sysdep_message ("AT_GID: ",
250 _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
251 10, 0),
252 "\n", NULL);
253 break;
254 case AT_EUID:
255 _dl_sysdep_message ("AT_EUID: ",
256 _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
257 10, 0),
258 "\n", NULL);
259 break;
260 case AT_EGID:
261 _dl_sysdep_message ("AT_EGID: ",
262 _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
263 10, 0),
264 "\n", NULL);
265 break;
266 case AT_PLATFORM:
267 _dl_sysdep_message ("AT_PLATFORM: ", av->a_un.a_ptr, "\n", NULL);
268 break;
269 case AT_HWCAP:
270 _dl_hwcap = av->a_un.a_val;
271 if (_dl_procinfo (_dl_hwcap) < 0)
272 _dl_sysdep_message ("AT_HWCAP: ",
273 _itoa_word (_dl_hwcap, buf + sizeof buf - 1,
274 16, 0),
275 "\n", NULL);
276 break;
277 case AT_CLKTCK:
278 _dl_sysdep_message ("AT_CLKTCK: ",
279 _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
280 10, 0),
281 "\n", NULL);
282 break;
283 case AT_FPUCW:
284 _dl_sysdep_message ("AT_FPUCW: ",
285 _itoa_word (av->a_un.a_val, buf + sizeof buf - 1,
286 10, 0),
287 "\n", NULL);
288 break;
289 }
290 }
291
292
293 /* Return an array of useful/necessary hardware capability names. */
294 const struct r_strlenpair *
295 internal_function
296 _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz,
297 size_t *max_capstrlen)
298 {
299 /* Determine how many important bits are set. */
300 unsigned long int masked = _dl_hwcap & _dl_hwcap_mask;
301 size_t cnt = platform != NULL;
302 size_t n, m;
303 size_t total;
304 struct r_strlenpair *temp;
305 struct r_strlenpair *result;
306 struct r_strlenpair *rp;
307 char *cp;
308
309 /* Count the number of bits set in the masked value. */
310 for (n = 0; (~((1UL << n) - 1) & masked) != 0; ++n)
311 if ((masked & (1UL << n)) != 0)
312 ++cnt;
313
314 if (cnt == 0)
315 {
316 /* If we have platform name and no important capability we only have
317 the base directory to search. */
318 result = (struct r_strlenpair *) malloc (sizeof (*result));
319 if (result == NULL)
320 {
321 no_memory:
322 _dl_signal_error (ENOMEM, NULL, "cannot create capability list");
323 }
324
325 result[0].str = (char *) result; /* Does not really matter. */
326 result[0].len = 0;
327
328 *sz = 1;
329 return result;
330 }
331
332 /* Create temporary data structure to generate result table. */
333 temp = (struct r_strlenpair *) alloca (cnt * sizeof (*temp));
334 m = 0;
335 for (n = 0; masked != 0; ++n)
336 if ((masked & (1UL << n)) != 0)
337 {
338 temp[m].str = _dl_hwcap_string (n);
339 temp[m].len = strlen (temp[m].str);
340 masked ^= 1UL << n;
341 ++m;
342 }
343 if (platform != NULL)
344 {
345 temp[m].str = platform;
346 temp[m].len = platform_len;
347 ++m;
348 }
349
350 /* Determine the total size of all strings together. */
351 if (cnt == 1)
352 total = temp[0].len;
353 else
354 {
355 total = (1 << (cnt - 2)) * (temp[0].len + temp[cnt - 1].len + 2);
356 for (n = 1; n + 1 < cnt; ++n)
357 total += (1 << (cnt - 3)) * (temp[n].len + 1);
358 }
359
360 /* The result structure: we use a very compressed way to store the
361 various combinations of capability names. */
362 *sz = 1 << cnt;
363 result = (struct r_strlenpair *) malloc (*sz * sizeof (*result) + total);
364 if (result == NULL)
365 goto no_memory;
366
367 if (cnt == 1)
368 {
369 result[0].str = (char *) (result + *sz);
370 result[0].len = temp[0].len + 1;
371 result[1].str = (char *) (result + *sz);
372 result[1].len = 0;
373 cp = __mempcpy ((char *) (result + *sz), temp[0].str, temp[0].len);
374 *cp = '/';
375 *sz = 2;
376 *max_capstrlen = result[0].len;
377
378 return result;
379 }
380
381 /* Fill in the information. This follows the following scheme
382 (indeces from TEMP for four strings):
383 entry #0: 0, 1, 2, 3 binary: 1111
384 #1: 0, 1, 3 1101
385 #2: 0, 2, 3 1011
386 #3: 0, 3 1001
387 This allows the representation of all possible combinations of
388 capability names in the string. First generate the strings. */
389 result[1].str = result[0].str = cp = (char *) (result + *sz);
390 #define add(idx) \
391 cp = __mempcpy (__mempcpy (cp, temp[idx].str, temp[idx].len), "/", 1);
392 if (cnt == 2)
393 {
394 add (1);
395 add (0);
396 }
397 else
398 {
399 n = 1 << cnt;
400 do
401 {
402 n -= 2;
403
404 /* We always add the last string. */
405 add (cnt - 1);
406
407 /* Add the strings which have the bit set in N. */
408 for (m = cnt - 2; m > 0; --m)
409 if ((n & (1 << m)) != 0)
410 add (m);
411
412 /* Always add the first string. */
413 add (0);
414 }
415 while (n != 0);
416 }
417 #undef add
418
419 /* Now we are ready to install the string pointers and length. */
420 for (n = 0; n < (1 << cnt); ++n)
421 result[n].len = 0;
422 n = cnt;
423 do
424 {
425 size_t mask = 1 << --n;
426
427 rp = result;
428 for (m = 1 << cnt; m > 0; ++rp)
429 if ((--m & mask) != 0)
430 rp->len += temp[n].len + 1;
431 }
432 while (n != 0);
433
434 /* The first half of the strings all include the first string. */
435 n = (1 << cnt) - 2;
436 rp = &result[2];
437 while (n != (1 << (cnt - 1)))
438 {
439 if ((n & 1) != 0)
440 rp[0].str = rp[-2].str + rp[-2].len;
441 else
442 rp[0].str = rp[-1].str;
443 ++rp;
444 --n;
445 }
446
447 /* The second have starts right after the first part of the string of
448 corresponding entry in the first half. */
449 do
450 {
451 rp[0].str = rp[-(1 << (cnt - 1))].str + temp[cnt - 1].len + 1;
452 ++rp;
453 }
454 while (--n != 0);
455
456 /* The maximum string length. */
457 *max_capstrlen = result[0].len;
458
459 return result;
460 }