rtld: properly handle root directory in load path (bug 30435)
[platform/upstream/glibc.git] / elf / dl-misc.c
1 /* Miscellaneous support functions for dynamic linker
2    Copyright (C) 1997-2023 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 Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the 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    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18
19 #include <_itoa.h>
20 #include <fcntl.h>
21 #include <ldsodefs.h>
22 #include <link.h>
23 #include <not-cancel.h>
24 #include <stdint.h>
25 #include <stdlib.h>
26 #include <sys/mman.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29
30 /* Read the whole contents of FILE into new mmap'd space with given
31    protections.  *SIZEP gets the size of the file.  On error MAP_FAILED
32    is returned.  */
33
34 void *
35 _dl_sysdep_read_whole_file (const char *file, size_t *sizep, int prot)
36 {
37   void *result = MAP_FAILED;
38   struct __stat64_t64 st;
39   int fd = __open64_nocancel (file, O_RDONLY | O_CLOEXEC);
40   if (fd >= 0)
41     {
42       if (__fstat64_time64 (fd, &st) >= 0)
43         {
44           *sizep = st.st_size;
45
46           /* No need to map the file if it is empty.  */
47           if (*sizep != 0)
48             /* Map a copy of the file contents.  */
49             result = __mmap (NULL, *sizep, prot,
50 #ifdef MAP_COPY
51                              MAP_COPY
52 #else
53                              MAP_PRIVATE
54 #endif
55 #ifdef MAP_FILE
56                              | MAP_FILE
57 #endif
58                              , fd, 0);
59         }
60       __close_nocancel (fd);
61     }
62   return result;
63 }
64
65 /* Test whether given NAME matches any of the names of the given object.  */
66 int
67 _dl_name_match_p (const char *name, const struct link_map *map)
68 {
69   if (strcmp (name, map->l_name) == 0)
70     return 1;
71
72   struct libname_list *runp = map->l_libname;
73
74   while (runp != NULL)
75     if (strcmp (name, runp->name) == 0)
76       return 1;
77     else
78       /* Synchronize with the release MO store in add_name_to_object.
79          See CONCURRENCY NOTES in add_name_to_object in dl-load.c.  */
80       runp = atomic_load_acquire (&runp->next);
81
82   return 0;
83 }
84
85 unsigned long int
86 _dl_higher_prime_number (unsigned long int n)
87 {
88   /* These are primes that are near, but slightly smaller than, a
89      power of two.  */
90   static const uint32_t primes[] = {
91     UINT32_C (7),
92     UINT32_C (13),
93     UINT32_C (31),
94     UINT32_C (61),
95     UINT32_C (127),
96     UINT32_C (251),
97     UINT32_C (509),
98     UINT32_C (1021),
99     UINT32_C (2039),
100     UINT32_C (4093),
101     UINT32_C (8191),
102     UINT32_C (16381),
103     UINT32_C (32749),
104     UINT32_C (65521),
105     UINT32_C (131071),
106     UINT32_C (262139),
107     UINT32_C (524287),
108     UINT32_C (1048573),
109     UINT32_C (2097143),
110     UINT32_C (4194301),
111     UINT32_C (8388593),
112     UINT32_C (16777213),
113     UINT32_C (33554393),
114     UINT32_C (67108859),
115     UINT32_C (134217689),
116     UINT32_C (268435399),
117     UINT32_C (536870909),
118     UINT32_C (1073741789),
119     UINT32_C (2147483647),
120                                        /* 4294967291L */
121     UINT32_C (2147483647) + UINT32_C (2147483644)
122   };
123
124   const uint32_t *low = &primes[0];
125   const uint32_t *high = &primes[sizeof (primes) / sizeof (primes[0])];
126
127   while (low != high)
128     {
129       const uint32_t *mid = low + (high - low) / 2;
130       if (n > *mid)
131        low = mid + 1;
132       else
133        high = mid;
134     }
135
136 #if 0
137   /* If we've run out of primes, abort.  */
138   if (n > *low)
139     {
140       fprintf (stderr, "Cannot find prime bigger than %lu\n", n);
141       abort ();
142     }
143 #endif
144
145   return *low;
146 }
147
148 /* A stripped down strtoul-like implementation for very early use.  It
149    does not set errno if the result is outside bounds because it may get
150    called before errno may have been set up.  */
151
152 uint64_t
153 _dl_strtoul (const char *nptr, char **endptr)
154 {
155   uint64_t result = 0;
156   bool positive = true;
157   unsigned max_digit;
158
159   while (*nptr == ' ' || *nptr == '\t')
160     ++nptr;
161
162   if (*nptr == '-')
163     {
164       positive = false;
165       ++nptr;
166     }
167   else if (*nptr == '+')
168     ++nptr;
169
170   if (*nptr < '0' || *nptr > '9')
171     {
172       if (endptr != NULL)
173         *endptr = (char *) nptr;
174       return 0UL;
175     }
176
177   int base = 10;
178   max_digit = 9;
179   if (*nptr == '0')
180     {
181       if (nptr[1] == 'x' || nptr[1] == 'X')
182         {
183           base = 16;
184           nptr += 2;
185         }
186       else
187         {
188           base = 8;
189           max_digit = 7;
190         }
191     }
192
193   while (1)
194     {
195       int digval;
196       if (*nptr >= '0' && *nptr <= '0' + max_digit)
197         digval = *nptr - '0';
198       else if (base == 16)
199         {
200           if (*nptr >= 'a' && *nptr <= 'f')
201             digval = *nptr - 'a' + 10;
202           else if (*nptr >= 'A' && *nptr <= 'F')
203             digval = *nptr - 'A' + 10;
204           else
205             break;
206         }
207       else
208         break;
209
210       if (result >= (UINT64_MAX - digval) / base)
211         {
212           if (endptr != NULL)
213             *endptr = (char *) nptr;
214           return UINT64_MAX;
215         }
216       result *= base;
217       result += digval;
218       ++nptr;
219     }
220
221   if (endptr != NULL)
222     *endptr = (char *) nptr;
223
224   /* Avoid 64-bit multiplication.  */
225   if (!positive)
226     result = -result;
227
228   return result;
229 }