]>
Commit | Line | Data |
---|---|---|
c41baa79 | 1 | /* Support for reading /etc/ld.so.cache files written by Linux ldconfig. |
2b778ceb | 2 | Copyright (C) 1999-2021 Free Software Foundation, Inc. |
c41baa79 UD |
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 | |
41bdb6e2 AJ |
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. | |
c41baa79 UD |
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 | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
c41baa79 | 14 | |
41bdb6e2 | 15 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 | 16 | License along with the GNU C Library; if not, see |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
c41baa79 | 18 | |
84ba719b FW |
19 | #ifndef _DL_CACHE_H |
20 | #define _DL_CACHE_H | |
21 | ||
22 | #include <endian.h> | |
23 | #include <stdbool.h> | |
dfb3f101 | 24 | #include <stddef.h> |
a8fd59b0 | 25 | #include <stdint.h> |
dfb3f101 | 26 | #include <string.h> |
a8fd59b0 | 27 | |
e25054c4 AJ |
28 | #ifndef _DL_CACHE_DEFAULT_ID |
29 | # define _DL_CACHE_DEFAULT_ID 3 | |
30 | #endif | |
c41baa79 | 31 | |
e25054c4 AJ |
32 | #ifndef _dl_cache_check_flags |
33 | # define _dl_cache_check_flags(flags) \ | |
c41baa79 | 34 | ((flags) == 1 || (flags) == _DL_CACHE_DEFAULT_ID) |
e25054c4 | 35 | #endif |
45eca4d1 UD |
36 | |
37 | #ifndef LD_SO_CACHE | |
8ca91b36 | 38 | # define LD_SO_CACHE SYSCONFDIR "/ld.so.cache" |
45eca4d1 UD |
39 | #endif |
40 | ||
bd89c0b5 UD |
41 | #ifndef add_system_dir |
42 | # define add_system_dir(dir) add_dir (dir) | |
43 | #endif | |
44 | ||
45eca4d1 UD |
45 | #define CACHEMAGIC "ld.so-1.7.0" |
46 | ||
47 | /* libc5 and glibc 2.0/2.1 use the same format. For glibc 2.2 another | |
48 | format has been added in a compatible way: | |
49 | The beginning of the string table is used for the new table: | |
e25054c4 | 50 | old_magic |
45eca4d1 UD |
51 | nlibs |
52 | libs[0] | |
53 | ... | |
54 | libs[nlibs-1] | |
e25054c4 AJ |
55 | pad, new magic needs to be aligned |
56 | - this is string[0] for the old format | |
57 | new magic - this is string[0] for the new format | |
45eca4d1 UD |
58 | newnlibs |
59 | ... | |
60 | newlibs[0] | |
61 | ... | |
62 | newlibs[newnlibs-1] | |
63 | string 1 | |
64 | string 2 | |
65 | ... | |
66 | */ | |
67 | struct file_entry | |
68 | { | |
de1a9197 FW |
69 | int32_t flags; /* This is 1 for an ELF library. */ |
70 | uint32_t key, value; /* String table indices. */ | |
45eca4d1 UD |
71 | }; |
72 | ||
73 | struct cache_file | |
74 | { | |
75 | char magic[sizeof CACHEMAGIC - 1]; | |
76 | unsigned int nlibs; | |
77 | struct file_entry libs[0]; | |
78 | }; | |
79 | ||
80 | #define CACHEMAGIC_NEW "glibc-ld.so.cache" | |
a8fd59b0 | 81 | #define CACHE_VERSION "1.1" |
ea029468 | 82 | #define CACHEMAGIC_VERSION_NEW CACHEMAGIC_NEW CACHE_VERSION |
45eca4d1 UD |
83 | |
84 | ||
85 | struct file_entry_new | |
86 | { | |
de1a9197 FW |
87 | union |
88 | { | |
89 | /* Fields shared with struct file_entry. */ | |
90 | struct file_entry entry; | |
91 | /* Also expose these fields directly. */ | |
92 | struct | |
93 | { | |
94 | int32_t flags; /* This is 1 for an ELF library. */ | |
95 | uint32_t key, value; /* String table indices. */ | |
96 | }; | |
97 | }; | |
a986484f | 98 | uint32_t osversion; /* Required OS version. */ |
a8fd59b0 | 99 | uint64_t hwcap; /* Hwcap entry. */ |
45eca4d1 UD |
100 | }; |
101 | ||
b44ac4f4 FW |
102 | /* This bit in the hwcap field of struct file_entry_new indicates that |
103 | the lower 32 bits contain an index into the | |
104 | cache_extension_tag_glibc_hwcaps section. Older glibc versions do | |
105 | not know about this HWCAP bit, so they will ignore these | |
106 | entries. */ | |
107 | #define DL_CACHE_HWCAP_EXTENSION (1ULL << 62) | |
108 | ||
109 | /* Return true if the ENTRY->hwcap value indicates that | |
110 | DL_CACHE_HWCAP_EXTENSION is used. */ | |
111 | static inline bool | |
112 | dl_cache_hwcap_extension (struct file_entry_new *entry) | |
113 | { | |
114 | /* If DL_CACHE_HWCAP_EXTENSION is set, but other bits as well, this | |
115 | is a different kind of extension. */ | |
116 | return (entry->hwcap >> 32) == (DL_CACHE_HWCAP_EXTENSION >> 32); | |
117 | } | |
118 | ||
84ba719b FW |
119 | /* See flags member of struct cache_file_new below. */ |
120 | enum | |
121 | { | |
122 | /* No endianness information available. An old ldconfig version | |
123 | without endianness support wrote the file. */ | |
124 | cache_file_new_flags_endian_unset = 0, | |
125 | ||
126 | /* Cache is invalid and should be ignored. */ | |
127 | cache_file_new_flags_endian_invalid = 1, | |
128 | ||
129 | /* Cache format is little endian. */ | |
130 | cache_file_new_flags_endian_little = 2, | |
131 | ||
132 | /* Cache format is big endian. */ | |
133 | cache_file_new_flags_endian_big = 3, | |
134 | ||
135 | /* Bit mask to extract the cache_file_new_flags_endian_* | |
136 | values. */ | |
137 | cache_file_new_flags_endian_mask = 3, | |
138 | ||
139 | /* Expected value of the endian bits in the flags member for the | |
140 | current architecture. */ | |
141 | cache_file_new_flags_endian_current | |
142 | = (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ | |
143 | ? cache_file_new_flags_endian_little | |
144 | : cache_file_new_flags_endian_big), | |
145 | }; | |
146 | ||
45eca4d1 UD |
147 | struct cache_file_new |
148 | { | |
149 | char magic[sizeof CACHEMAGIC_NEW - 1]; | |
150 | char version[sizeof CACHE_VERSION - 1]; | |
a8fd59b0 AJ |
151 | uint32_t nlibs; /* Number of entries. */ |
152 | uint32_t len_strings; /* Size of string table. */ | |
84ba719b FW |
153 | |
154 | /* flags & cache_file_new_flags_endian_mask is one of the values | |
155 | cache_file_new_flags_endian_unset, cache_file_new_flags_endian_invalid, | |
156 | cache_file_new_flags_endian_little, cache_file_new_flags_endian_big. | |
157 | ||
158 | The remaining bits are unused and should be generated as zero and | |
159 | ignored by readers. */ | |
160 | uint8_t flags; | |
161 | ||
162 | uint8_t padding_unsed[3]; /* Not used, for future extensions. */ | |
163 | ||
dfb3f101 FW |
164 | /* File offset of the extension directory. See struct |
165 | cache_extension below. Must be a multiple of four. */ | |
166 | uint32_t extension_offset; | |
167 | ||
168 | uint32_t unused[3]; /* Leave space for future extensions | |
a8fd59b0 | 169 | and align to 8 byte boundary. */ |
45eca4d1 | 170 | struct file_entry_new libs[0]; /* Entries describing libraries. */ |
a8fd59b0 | 171 | /* After this the string table of size len_strings is found. */ |
45eca4d1 | 172 | }; |
84ba719b FW |
173 | _Static_assert (sizeof (struct cache_file_new) == 48, |
174 | "size of struct cache_file_new"); | |
175 | ||
176 | /* Returns false if *CACHE has the wrong endianness for this | |
177 | architecture, and true if the endianness matches (or is | |
178 | unknown). */ | |
179 | static inline bool | |
180 | cache_file_new_matches_endian (const struct cache_file_new *cache) | |
181 | { | |
182 | /* A zero value for cache->flags means that no endianness | |
183 | information is available. */ | |
184 | return cache->flags == 0 | |
185 | || ((cache->flags & cache_file_new_flags_endian_big) | |
186 | == cache_file_new_flags_endian_current); | |
187 | } | |
188 | ||
45eca4d1 | 189 | |
dfb3f101 FW |
190 | /* Randomly chosen magic value, which allows for additional |
191 | consistency verification. */ | |
192 | enum { cache_extension_magic = (uint32_t) -358342284 }; | |
193 | ||
194 | /* Tag values for different kinds of extension sections. Similar to | |
195 | SHT_* constants. */ | |
196 | enum cache_extension_tag | |
197 | { | |
198 | /* Array of bytes containing the glibc version that generated this | |
199 | cache file. */ | |
200 | cache_extension_tag_generator, | |
201 | ||
b44ac4f4 FW |
202 | /* glibc-hwcaps subdirectory information. An array of uint32_t |
203 | values, which are indices into the string table. The strings | |
204 | are sorted lexicographically (according to strcmp). The extra | |
205 | level of indirection (instead of using string table indices | |
206 | directly) allows the dynamic loader to compute the preference | |
207 | order of the hwcaps names more efficiently. | |
208 | ||
209 | For this section, 4-byte alignment is required, and the section | |
210 | size must be a multiple of 4. */ | |
211 | cache_extension_tag_glibc_hwcaps, | |
212 | ||
dfb3f101 FW |
213 | /* Total number of known cache extension tags. */ |
214 | cache_extension_count | |
215 | }; | |
216 | ||
217 | /* Element in the array following struct cache_extension. Similar to | |
218 | an ELF section header. */ | |
219 | struct cache_extension_section | |
220 | { | |
221 | /* Type of the extension section. A enum cache_extension_tag value. */ | |
222 | uint32_t tag; | |
223 | ||
224 | /* Extension-specific flags. Currently generated as zero. */ | |
225 | uint32_t flags; | |
226 | ||
227 | /* Offset from the start of the file for the data in this extension | |
228 | section. Specific extensions can have alignment constraints. */ | |
229 | uint32_t offset; | |
230 | ||
231 | /* Length in bytes of the extension data. Specific extensions may | |
232 | have size requirements. */ | |
233 | uint32_t size; | |
234 | }; | |
235 | ||
236 | /* The extension directory in the cache. An array of struct | |
237 | cache_extension_section entries. */ | |
238 | struct cache_extension | |
239 | { | |
240 | uint32_t magic; /* Always cache_extension_magic. */ | |
241 | uint32_t count; /* Number of following entries. */ | |
242 | ||
243 | /* count section descriptors of type struct cache_extension_section | |
244 | follow. */ | |
245 | struct cache_extension_section sections[]; | |
246 | }; | |
247 | ||
248 | /* A relocated version of struct cache_extension_section. */ | |
249 | struct cache_extension_loaded | |
250 | { | |
251 | /* Address and size of this extension section. base is NULL if the | |
252 | section is missing from the file. */ | |
253 | const void *base; | |
254 | size_t size; | |
255 | ||
256 | /* Flags from struct cache_extension_section. */ | |
257 | uint32_t flags; | |
258 | }; | |
259 | ||
260 | /* All supported extension sections, relocated. Filled in by | |
261 | cache_extension_load below. */ | |
262 | struct cache_extension_all_loaded | |
263 | { | |
264 | struct cache_extension_loaded sections[cache_extension_count]; | |
265 | }; | |
266 | ||
b44ac4f4 FW |
267 | /* Performs basic data validation based on section tag, and removes |
268 | the sections which are invalid. */ | |
269 | static void | |
270 | cache_extension_verify (struct cache_extension_all_loaded *loaded) | |
271 | { | |
272 | { | |
273 | /* Section must not be empty, it must be aligned at 4 bytes, and | |
274 | the size must be a multiple of 4. */ | |
275 | struct cache_extension_loaded *hwcaps | |
276 | = &loaded->sections[cache_extension_tag_glibc_hwcaps]; | |
277 | if (hwcaps->size == 0 | |
278 | || ((uintptr_t) hwcaps->base % 4) != 0 | |
279 | || (hwcaps->size % 4) != 0) | |
280 | { | |
281 | hwcaps->base = NULL; | |
282 | hwcaps->size = 0; | |
283 | hwcaps->flags = 0; | |
284 | } | |
285 | } | |
286 | } | |
287 | ||
dfb3f101 FW |
288 | static bool __attribute__ ((unused)) |
289 | cache_extension_load (const struct cache_file_new *cache, | |
290 | const void *file_base, size_t file_size, | |
291 | struct cache_extension_all_loaded *loaded) | |
292 | { | |
293 | memset (loaded, 0, sizeof (*loaded)); | |
294 | if (cache->extension_offset == 0) | |
295 | /* No extensions present. This is not a format error. */ | |
296 | return true; | |
297 | if ((cache->extension_offset % 4) != 0) | |
298 | /* Extension offset is misaligned. */ | |
299 | return false; | |
300 | size_t size_tmp; | |
301 | if (__builtin_add_overflow (cache->extension_offset, | |
302 | sizeof (struct cache_extension), &size_tmp) | |
303 | || size_tmp > file_size) | |
304 | /* Extension extends beyond the end of the file. */ | |
305 | return false; | |
306 | const struct cache_extension *ext = file_base + cache->extension_offset; | |
307 | if (ext->magic != cache_extension_magic) | |
308 | return false; | |
309 | if (__builtin_mul_overflow (ext->count, | |
310 | sizeof (struct cache_extension_section), | |
311 | &size_tmp) | |
312 | || __builtin_add_overflow (cache->extension_offset | |
313 | + sizeof (struct cache_extension), size_tmp, | |
314 | &size_tmp) | |
315 | || size_tmp > file_size) | |
316 | /* Extension array extends beyond the end of the file. */ | |
317 | return false; | |
318 | for (uint32_t i = 0; i < ext->count; ++i) | |
319 | { | |
320 | if (__builtin_add_overflow (ext->sections[i].offset, | |
321 | ext->sections[i].size, &size_tmp) | |
322 | || size_tmp > file_size) | |
323 | /* Extension data extends beyond the end of the file. */ | |
324 | return false; | |
325 | ||
326 | uint32_t tag = ext->sections[i].tag; | |
327 | if (tag >= cache_extension_count) | |
328 | /* Tag is out of range and unrecognized. */ | |
329 | continue; | |
330 | loaded->sections[tag].base = file_base + ext->sections[i].offset; | |
331 | loaded->sections[tag].size = ext->sections[i].size; | |
332 | loaded->sections[tag].flags = ext->sections[i].flags; | |
333 | } | |
b44ac4f4 | 334 | cache_extension_verify (loaded); |
dfb3f101 FW |
335 | return true; |
336 | } | |
337 | ||
e25054c4 AJ |
338 | /* Used to align cache_file_new. */ |
339 | #define ALIGN_CACHE(addr) \ | |
340 | (((addr) + __alignof__ (struct cache_file_new) -1) \ | |
341 | & (~(__alignof__ (struct cache_file_new) - 1))) | |
342 | ||
17e00cc6 | 343 | extern int _dl_cache_libcmp (const char *p1, const char *p2) attribute_hidden; |
84ba719b FW |
344 | |
345 | #endif /* _DL_CACHE_H */ |