| 1 | /* Support for reading /etc/ld.so.cache files written by Linux ldconfig. |
| 2 | Copyright (C) 1999-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 | #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_unused; /* Required OS version (unused). */ |
| 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 | |