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