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*/
67struct file_entry
68{
69 int32_t flags; /* This is 1 for an ELF library. */
70 uint32_t key, value; /* String table indices. */
71};
72
73struct 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
85struct 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. */
119static inline bool
120dl_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. */
130enum
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
157struct 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). */
189static inline bool
190cache_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. */
202enum { cache_extension_magic = (uint32_t) -358342284 };
203
204/* Tag values for different kinds of extension sections. Similar to
205 SHT_* constants. */
206enum 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. */
229struct 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. */
248struct 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. */
259struct 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. */
272struct 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. */
279static void
280cache_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
298static bool __attribute__ ((unused))
299cache_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 (s: loaded, c: 0, n: 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
353extern int _dl_cache_libcmp (const char *p1, const char *p2) attribute_hidden;
354
355#endif /* _DL_CACHE_H */
356

source code of glibc/sysdeps/generic/dl-cache.h