1 |
commit: c68cfa4e47d59e9903509a1d90da178a982eb27e |
2 |
Author: Mike Frysinger <vapier <AT> chromium <DOT> org> |
3 |
AuthorDate: Fri Apr 16 18:59:55 2021 +0000 |
4 |
Commit: Mike Frysinger <vapier <AT> gentoo <DOT> org> |
5 |
CommitDate: Fri Apr 16 18:59:55 2021 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/pax-utils.git/commit/?id=c68cfa4e |
7 |
|
8 |
paxldso: add support for "new" glibc cache format |
9 |
|
10 |
Glibc has supported a "new" cache format for a while now (almost 20 |
11 |
years), but since it generated both, we didn't bother to implement |
12 |
it, only relying on the old cache format. With glibc-2.32+ though, |
13 |
it now only outputs the new format. |
14 |
|
15 |
Rework the code so we support the old, new, and compat cache formats |
16 |
(where the new format is appended to the old one). |
17 |
|
18 |
Bug: https://bugs.gentoo.org/739014 |
19 |
Signed-off-by: Mike Frysinger <vapier <AT> gentoo.org> |
20 |
|
21 |
paxldso.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++--------------- |
22 |
1 file changed, 179 insertions(+), 56 deletions(-) |
23 |
|
24 |
diff --git a/paxldso.c b/paxldso.c |
25 |
index d89210d..150f490 100644 |
26 |
--- a/paxldso.c |
27 |
+++ b/paxldso.c |
28 |
@@ -14,19 +14,28 @@ |
29 |
|
30 |
#if PAX_LDSO_CACHE |
31 |
|
32 |
-static void *ldcache = NULL; |
33 |
+/* Memory region containing a specific cache. Will be a subset of the mmap. */ |
34 |
+static const void *ldcache = NULL; |
35 |
static size_t ldcache_size = 0; |
36 |
|
37 |
+/* Entire memory mapped cache file. */ |
38 |
+static void *ldcache_mmap_base = NULL; |
39 |
+static size_t ldcache_mmap_size = 0; |
40 |
+ |
41 |
static char *ldso_cache_buf = NULL; |
42 |
static size_t ldso_cache_buf_size = 0; |
43 |
|
44 |
#if defined(__GLIBC__) || defined(__UCLIBC__) |
45 |
|
46 |
/* Defines can be seen in glibc's sysdeps/generic/ldconfig.h */ |
47 |
-#define LDSO_CACHE_MAGIC "ld.so-" |
48 |
-#define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1) |
49 |
-#define LDSO_CACHE_VER "1.7.0" |
50 |
-#define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1) |
51 |
+#define LDSO_CACHE_MAGIC_OLD "ld.so-" |
52 |
+#define LDSO_CACHE_MAGIC_OLD_LEN (sizeof LDSO_CACHE_MAGIC_OLD - 1) |
53 |
+#define LDSO_CACHE_VER_OLD "1.7.0" |
54 |
+#define LDSO_CACHE_VER_OLD_LEN (sizeof LDSO_CACHE_VER_OLD - 1) |
55 |
+#define LDSO_CACHE_MAGIC_NEW "glibc-ld.so.cache" |
56 |
+#define LDSO_CACHE_MAGIC_NEW_LEN (sizeof LDSO_CACHE_MAGIC_NEW - 1) |
57 |
+#define LDSO_CACHE_VER_NEW "1.1" |
58 |
+#define LDSO_CACHE_VER_NEW_LEN (sizeof LDSO_CACHE_VER_NEW - 1) |
59 |
#define FLAG_ANY -1 |
60 |
#define FLAG_TYPE_MASK 0x00ff |
61 |
#define FLAG_LIBC4 0x0000 |
62 |
@@ -48,14 +57,45 @@ static size_t ldso_cache_buf_size = 0; |
63 |
#define FLAG_MIPS_LIB32_NAN2008 0x0c00 |
64 |
#define FLAG_MIPS64_LIBN32_NAN2008 0x0d00 |
65 |
#define FLAG_MIPS64_LIBN64_NAN2008 0x0e00 |
66 |
+#define FLAG_RISCV_FLOAT_ABI_SOFT 0x0f00 |
67 |
+#define FLAG_RISCV_FLOAT_ABI_DOUBLE 0x1000 |
68 |
|
69 |
typedef struct { |
70 |
int flags; |
71 |
unsigned int sooffset; |
72 |
unsigned int liboffset; |
73 |
-} libentry_t; |
74 |
+} libentry_old_t; |
75 |
+ |
76 |
+typedef struct { |
77 |
+ const char magic[LDSO_CACHE_MAGIC_OLD_LEN]; |
78 |
+ const char version[LDSO_CACHE_VER_OLD_LEN]; |
79 |
+ unsigned int nlibs; |
80 |
+ libentry_old_t libs[0]; |
81 |
+} header_old_t; |
82 |
+ |
83 |
+typedef struct { |
84 |
+ int32_t flags; |
85 |
+ uint32_t sooffset; |
86 |
+ uint32_t liboffset; |
87 |
+ uint32_t osversion; |
88 |
+ uint64_t hwcap; |
89 |
+} libentry_new_t; |
90 |
|
91 |
-static bool is_compatible(elfobj *elf, libentry_t *libent) |
92 |
+typedef struct { |
93 |
+ const char magic[LDSO_CACHE_MAGIC_NEW_LEN]; |
94 |
+ const char version[LDSO_CACHE_VER_NEW_LEN]; |
95 |
+ uint32_t nlibs; |
96 |
+ uint32_t len_strings; |
97 |
+ uint8_t flags; |
98 |
+ uint8_t _pad_flags[3]; |
99 |
+ uint32_t extension_offset; |
100 |
+ uint32_t _pad_ext[3]; |
101 |
+ libentry_new_t libs[0]; |
102 |
+} header_new_t; |
103 |
+ |
104 |
+static bool ldcache_is_new; |
105 |
+ |
106 |
+static bool is_compatible(elfobj *elf, const libentry_old_t *libent) |
107 |
{ |
108 |
int flags = libent->flags & FLAG_REQUIRED_MASK; |
109 |
|
110 |
@@ -136,74 +176,124 @@ static bool is_compatible(elfobj *elf, libentry_t *libent) |
111 |
return false; |
112 |
} |
113 |
|
114 |
-char *ldso_cache_lookup_lib(elfobj *elf, const char *fname) |
115 |
+static void ldso_cache_load(void) |
116 |
{ |
117 |
- unsigned int nlib; |
118 |
- char *ret = NULL; |
119 |
- char *strs; |
120 |
+ int fd; |
121 |
+ const char *cachefile; |
122 |
+ struct stat st; |
123 |
+ const header_old_t *header_old; |
124 |
+ const header_new_t *header_new; |
125 |
|
126 |
- typedef struct { |
127 |
- char magic[LDSO_CACHE_MAGIC_LEN]; |
128 |
- char version[LDSO_CACHE_VER_LEN]; |
129 |
- unsigned int nlibs; |
130 |
- } header_t; |
131 |
- header_t *header; |
132 |
+ if (ldcache_mmap_base != NULL) |
133 |
+ return; |
134 |
|
135 |
- libentry_t *libent; |
136 |
+ cachefile = root_rel_path(ldcache_path); |
137 |
|
138 |
- if (fname == NULL) |
139 |
- return NULL; |
140 |
+ if (fstatat(root_fd, cachefile, &st, 0)) |
141 |
+ return; |
142 |
|
143 |
- if (ldcache == NULL) { |
144 |
- int fd; |
145 |
- const char *cachefile = root_rel_path(ldcache_path); |
146 |
- struct stat st; |
147 |
+ fd = openat(root_fd, cachefile, O_RDONLY); |
148 |
+ if (fd == -1) |
149 |
+ return; |
150 |
|
151 |
- if (fstatat(root_fd, cachefile, &st, 0)) |
152 |
- return NULL; |
153 |
+ /* cache these values so we only map/unmap the cache file once */ |
154 |
+ ldcache_mmap_size = st.st_size; |
155 |
+ ldcache_mmap_base = mmap(0, ldcache_mmap_size, PROT_READ, MAP_SHARED, fd, 0); |
156 |
+ close(fd); |
157 |
|
158 |
- fd = openat(root_fd, cachefile, O_RDONLY); |
159 |
- if (fd == -1) |
160 |
- return NULL; |
161 |
- |
162 |
- /* cache these values so we only map/unmap the cache file once */ |
163 |
- ldcache_size = st.st_size; |
164 |
- header = ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0); |
165 |
- close(fd); |
166 |
+ if (ldcache_mmap_base == MAP_FAILED) { |
167 |
+ ldcache_mmap_base = NULL; |
168 |
+ return; |
169 |
+ } |
170 |
|
171 |
- if (ldcache == MAP_FAILED) { |
172 |
- ldcache = NULL; |
173 |
- return NULL; |
174 |
+ ldcache_size = ldcache_mmap_size; |
175 |
+ ldcache = ldcache_mmap_base; |
176 |
+ header_old = ldcache; |
177 |
+ header_new = ldcache; |
178 |
+#define memeq(mem1, mem2) (memcmp(mem1, mem2, sizeof(mem2) - 1) == 0) |
179 |
+ if (memeq(header_new->magic, LDSO_CACHE_MAGIC_NEW) && |
180 |
+ memeq(header_new->version, LDSO_CACHE_VER_NEW)) { |
181 |
+ ldcache_is_new = true; |
182 |
+ } else if (memeq(header_old->magic, LDSO_CACHE_MAGIC_OLD) && |
183 |
+ memeq(header_old->version, LDSO_CACHE_VER_OLD)) { |
184 |
+ /* See if the new cache format is appended after the old cache. */ |
185 |
+ uintptr_t end = |
186 |
+ (uintptr_t)ldcache + sizeof(header_old_t) + |
187 |
+ (header_old->nlibs * sizeof(libentry_old_t)); |
188 |
+ header_new = (const void *)ALIGN_UP(end, __alignof__(header_new_t)); |
189 |
+ if (memeq(header_new->magic, LDSO_CACHE_MAGIC_NEW) && |
190 |
+ memeq(header_new->version, LDSO_CACHE_VER_NEW)) { |
191 |
+ ldcache_is_new = true; |
192 |
+ ldcache_size -= ((uintptr_t)header_new - (uintptr_t)ldcache); |
193 |
+ ldcache = header_new; |
194 |
+ } else { |
195 |
+ ldcache_is_new = false; |
196 |
} |
197 |
+ } else { |
198 |
+ munmap(ldcache_mmap_base, ldcache_mmap_size); |
199 |
+ ldcache_mmap_base = NULL; |
200 |
+ return; |
201 |
+ } |
202 |
+#undef memq |
203 |
|
204 |
- if (memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN) || |
205 |
- memcmp(header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN)) |
206 |
- { |
207 |
- munmap(ldcache, ldcache_size); |
208 |
- ldcache = NULL; |
209 |
- return NULL; |
210 |
- } |
211 |
+ ldso_cache_buf_size = 4096; |
212 |
+ ldso_cache_buf = xrealloc(ldso_cache_buf, ldso_cache_buf_size); |
213 |
+} |
214 |
|
215 |
- ldso_cache_buf_size = 4096; |
216 |
- ldso_cache_buf = xrealloc(ldso_cache_buf, ldso_cache_buf_size); |
217 |
- } else |
218 |
- header = ldcache; |
219 |
+char *ldso_cache_lookup_lib(elfobj *elf, const char *fname) |
220 |
+{ |
221 |
+ unsigned int nlib, nlibs; |
222 |
+ char *ret = NULL; |
223 |
+ const char *strs; |
224 |
+ const libentry_old_t *libent_old; |
225 |
+ const libentry_new_t *libent_new; |
226 |
|
227 |
- libent = ldcache + sizeof(header_t); |
228 |
- strs = (char *) &libent[header->nlibs]; |
229 |
+ if (fname == NULL) |
230 |
+ return NULL; |
231 |
|
232 |
- for (nlib = 0; nlib < header->nlibs; ++nlib) { |
233 |
+ ldso_cache_load(); |
234 |
+ if (ldcache == NULL) |
235 |
+ return NULL; |
236 |
+ |
237 |
+ if (ldcache_is_new) { |
238 |
+ const header_new_t *header = ldcache; |
239 |
+ libent_old = NULL; |
240 |
+ libent_new = &header->libs[0]; |
241 |
+ strs = (const char *)header; |
242 |
+ nlibs = header->nlibs; |
243 |
+ } else { |
244 |
+ const header_old_t *header = ldcache; |
245 |
+ libent_old = &header->libs[0]; |
246 |
+ libent_new = NULL; |
247 |
+ strs = (const char *)&libent_old[header->nlibs]; |
248 |
+ nlibs = header->nlibs; |
249 |
+ } |
250 |
+ |
251 |
+ /* |
252 |
+ * TODO: Should add memory range checking in case cache file is corrupt. |
253 |
+ * TODO: We search the cache from start to finish, but since we know the cache |
254 |
+ * is sorted, we really should be doing a binary search to speed it up. |
255 |
+ */ |
256 |
+ for (nlib = 0; nlib < nlibs; ++nlib) { |
257 |
const char *lib; |
258 |
size_t lib_len; |
259 |
|
260 |
- if (!is_compatible(elf, &libent[nlib])) |
261 |
+ /* The first few fields are the same between new/old formats. */ |
262 |
+ const libentry_old_t *libent; |
263 |
+ if (ldcache_is_new) { |
264 |
+ libent = (void *)&libent_new[nlib]; |
265 |
+ } else { |
266 |
+ libent = &libent_old[nlib]; |
267 |
+ } |
268 |
+ |
269 |
+ if (!is_compatible(elf, libent)) |
270 |
continue; |
271 |
|
272 |
- if (strcmp(fname, strs + libent[nlib].sooffset) != 0) |
273 |
+ if (strcmp(fname, strs + libent->sooffset) != 0) |
274 |
continue; |
275 |
|
276 |
/* Return first hit because that is how the ldso rolls */ |
277 |
- lib = strs + libent[nlib].liboffset; |
278 |
+ lib = strs + libent->liboffset; |
279 |
lib_len = strlen(lib) + 1; |
280 |
if (lib_len > ldso_cache_buf_size) { |
281 |
ldso_cache_buf = xrealloc(ldso_cache_buf, ldso_cache_buf_size + 4096); |
282 |
@@ -223,8 +313,8 @@ static void ldso_cache_cleanup(void) |
283 |
{ |
284 |
free(ldso_cache_buf); |
285 |
|
286 |
- if (ldcache != NULL) |
287 |
- munmap(ldcache, ldcache_size); |
288 |
+ if (ldcache_mmap_base != NULL) |
289 |
+ munmap(ldcache_mmap_base, ldcache_mmap_size); |
290 |
} |
291 |
|
292 |
#else |
293 |
@@ -379,12 +469,45 @@ const char argv0[] = "paxldso"; |
294 |
int main(int argc, char *argv[]) |
295 |
{ |
296 |
elfobj *elf = readelf(argv[0]); |
297 |
+ ldso_cache_load(); |
298 |
+ printf("cache file memory base is %p\n", ldcache_mmap_base); |
299 |
+ printf("cache memory base is %p\n", ldcache); |
300 |
for (int i = 1; i < argc; ++i) { |
301 |
const char *search = argv[i]; |
302 |
const char *lib = ldso_cache_lookup_lib(elf, search); |
303 |
printf("%s -> %s\n", search, lib); |
304 |
} |
305 |
unreadelf(elf); |
306 |
+ |
307 |
+ if (ldcache) { |
308 |
+ unsigned int nlib; |
309 |
+ const char *strs, *s; |
310 |
+ |
311 |
+ if (ldcache_is_new) { |
312 |
+ const header_new_t *header = ldcache; |
313 |
+ const libentry_new_t *libents = &header->libs[0]; |
314 |
+ strs = (const char *)header; |
315 |
+ printf("dumping new cache format\n"); |
316 |
+ |
317 |
+ for (nlib = 0; nlib < header->nlibs; ++nlib) { |
318 |
+ const libentry_new_t *libent = &libents[nlib]; |
319 |
+ s = strs + libent->sooffset; |
320 |
+ printf("%p: %s\n", libent, s); |
321 |
+ } |
322 |
+ } else { |
323 |
+ const header_old_t *header = ldcache; |
324 |
+ const libentry_old_t *libents = &header->libs[0]; |
325 |
+ strs = (const char *)&libents[header->nlibs]; |
326 |
+ printf("dumping old cache format\n"); |
327 |
+ |
328 |
+ for (nlib = 0; nlib < header->nlibs; ++nlib) { |
329 |
+ const libentry_old_t *libent = &libents[nlib]; |
330 |
+ s = strs + libent->sooffset; |
331 |
+ printf("%p: %s\n", libent, s); |
332 |
+ } |
333 |
+ } |
334 |
+ } |
335 |
+ |
336 |
paxldso_cleanup(); |
337 |
} |