Gentoo Archives: gentoo-commits

From: Mike Frysinger <vapier@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/pax-utils:master commit in: /
Date: Fri, 16 Apr 2021 19:03:40
Message-Id: 1618599595.c68cfa4e47d59e9903509a1d90da178a982eb27e.vapier@gentoo
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 }