1 |
vapier 11/09/27 22:20:07 |
2 |
|
3 |
Modified: scanelf.c |
4 |
Log: |
5 |
redo root support to use *at funcs and avoid memory operations where possible |
6 |
|
7 |
Revision Changes Path |
8 |
1.232 pax-utils/scanelf.c |
9 |
|
10 |
file : http://sources.gentoo.org/viewvc.cgi/gentoo-projects/pax-utils/scanelf.c?rev=1.232&view=markup |
11 |
plain: http://sources.gentoo.org/viewvc.cgi/gentoo-projects/pax-utils/scanelf.c?rev=1.232&content-type=text/plain |
12 |
diff : http://sources.gentoo.org/viewvc.cgi/gentoo-projects/pax-utils/scanelf.c?r1=1.231&r2=1.232 |
13 |
|
14 |
Index: scanelf.c |
15 |
=================================================================== |
16 |
RCS file: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v |
17 |
retrieving revision 1.231 |
18 |
retrieving revision 1.232 |
19 |
diff -u -r1.231 -r1.232 |
20 |
--- scanelf.c 27 Sep 2011 19:58:09 -0000 1.231 |
21 |
+++ scanelf.c 27 Sep 2011 22:20:07 -0000 1.232 |
22 |
@@ -1,13 +1,13 @@ |
23 |
/* |
24 |
* Copyright 2003-2007 Gentoo Foundation |
25 |
* Distributed under the terms of the GNU General Public License v2 |
26 |
- * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.231 2011/09/27 19:58:09 vapier Exp $ |
27 |
+ * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.232 2011/09/27 22:20:07 vapier Exp $ |
28 |
* |
29 |
* Copyright 2003-2007 Ned Ludd - <solar@g.o> |
30 |
* Copyright 2004-2007 Mike Frysinger - <vapier@g.o> |
31 |
*/ |
32 |
|
33 |
-static const char rcsid[] = "$Id: scanelf.c,v 1.231 2011/09/27 19:58:09 vapier Exp $"; |
34 |
+static const char rcsid[] = "$Id: scanelf.c,v 1.232 2011/09/27 22:20:07 vapier Exp $"; |
35 |
const char argv0[] = "scanelf"; |
36 |
|
37 |
#include "paxinc.h" |
38 |
@@ -59,7 +59,7 @@ |
39 |
static char **qa_textrels = NULL; |
40 |
static char **qa_execstack = NULL; |
41 |
static char **qa_wx_load = NULL; |
42 |
-static char *root; |
43 |
+static int root_fd = AT_FDCWD; |
44 |
|
45 |
static int match_bits = 0; |
46 |
static unsigned int match_perms = 0; |
47 |
@@ -89,6 +89,34 @@ |
48 |
return 0; |
49 |
} |
50 |
|
51 |
+static FILE *fopenat_r(int dir_fd, const char *path) |
52 |
+{ |
53 |
+ int fd = openat(dir_fd, path, O_RDONLY|O_CLOEXEC); |
54 |
+ if (fd == -1) |
55 |
+ return NULL; |
56 |
+ return fdopen(fd, "re"); |
57 |
+} |
58 |
+ |
59 |
+static const char *root_rel_path(const char *path) |
60 |
+{ |
61 |
+ /* |
62 |
+ * openat() will ignore the dirfd if path starts with |
63 |
+ * a /, so consume all of that noise |
64 |
+ * |
65 |
+ * XXX: we don't handle relative paths like ../ that |
66 |
+ * break out of the --root option, but for now, just |
67 |
+ * don't do that :P. |
68 |
+ */ |
69 |
+ if (root_fd != AT_FDCWD) { |
70 |
+ while (*path == '/') |
71 |
+ ++path; |
72 |
+ if (*path == '\0') |
73 |
+ path = "."; |
74 |
+ } |
75 |
+ |
76 |
+ return path; |
77 |
+} |
78 |
+ |
79 |
/* 1 on failure. 0 otherwise */ |
80 |
static int rematch(const char *regex, const char *match, int cflags) |
81 |
{ |
82 |
@@ -114,7 +142,7 @@ |
83 |
return ret; |
84 |
} |
85 |
|
86 |
-/* sub-funcs for scanelf_file() */ |
87 |
+/* sub-funcs for scanelf_fileat() */ |
88 |
static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) |
89 |
{ |
90 |
/* find the best SHT_DYNSYM and SHT_STRTAB sections */ |
91 |
@@ -466,7 +494,6 @@ |
92 |
Elf ## B ## _Addr end_addr = offset_tmp + EGET(func->st_size); \ |
93 |
char *sysbuf; \ |
94 |
size_t syslen; \ |
95 |
- int sysret; \ |
96 |
const char sysfmt[] = "objdump -r -R -d -w -l --start-address=0x%lX --stop-address=0x%lX %s | grep --color -i -C 3 '.*[[:space:]]%lX:[[:space:]]*R_.*'\n"; \ |
97 |
syslen = sizeof(sysfmt) + strlen(elf->filename) + 3 * sizeof(unsigned long) + 1; \ |
98 |
sysbuf = xmalloc(syslen); \ |
99 |
@@ -479,7 +506,7 @@ |
100 |
elf->filename, \ |
101 |
(unsigned long)r_offset); \ |
102 |
fflush(stdout); \ |
103 |
- sysret = system(sysbuf); \ |
104 |
+ if (system(sysbuf)) /* don't care */; \ |
105 |
fflush(stdout); \ |
106 |
free(sysbuf); \ |
107 |
} \ |
108 |
@@ -688,7 +715,7 @@ |
109 |
int fd; |
110 |
char *strs; |
111 |
static char buf[__PAX_UTILS_PATH_MAX] = ""; |
112 |
- const char cachefile[] = "/etc/ld.so.cache"; |
113 |
+ const char *cachefile = root_rel_path("/etc/ld.so.cache"); |
114 |
struct stat st; |
115 |
|
116 |
typedef struct { |
117 |
@@ -709,10 +736,10 @@ |
118 |
return NULL; |
119 |
|
120 |
if (ldcache == NULL) { |
121 |
- if (stat(cachefile, &st)) |
122 |
+ if (fstatat(root_fd, cachefile, &st, 0)) |
123 |
return NULL; |
124 |
|
125 |
- fd = open(cachefile, O_RDONLY); |
126 |
+ fd = openat(root_fd, cachefile, O_RDONLY); |
127 |
if (fd == -1) |
128 |
return NULL; |
129 |
|
130 |
@@ -1482,7 +1509,7 @@ |
131 |
return 0; |
132 |
} |
133 |
/* scan a file which may be an elf or an archive or some other magical beast */ |
134 |
-static int scanelf_file(const char *filename, const struct stat *st_cache) |
135 |
+static int scanelf_fileat(int dir_fd, const char *filename, const struct stat *st_cache) |
136 |
{ |
137 |
const struct stat *st = st_cache; |
138 |
struct stat symlink_st; |
139 |
@@ -1490,8 +1517,9 @@ |
140 |
|
141 |
/* always handle regular files and handle symlinked files if no -y */ |
142 |
if (S_ISLNK(st->st_mode)) { |
143 |
- if (!scan_symlink) return 1; |
144 |
- stat(filename, &symlink_st); |
145 |
+ if (!scan_symlink) |
146 |
+ return 1; |
147 |
+ fstatat(dir_fd, filename, &symlink_st, 0); |
148 |
st = &symlink_st; |
149 |
} |
150 |
|
151 |
@@ -1504,81 +1532,88 @@ |
152 |
if ((st->st_mode | match_perms) != st->st_mode) |
153 |
return 1; |
154 |
} |
155 |
- if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1) |
156 |
+ fd = openat(dir_fd, filename, (fix_elf ? O_RDWR : O_RDONLY) | O_CLOEXEC); |
157 |
+ if (fd == -1) |
158 |
return 1; |
159 |
|
160 |
if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives) |
161 |
/* if it isn't an ELF, maybe it's an .a archive */ |
162 |
scanelf_archive(filename, fd, st->st_size); |
163 |
|
164 |
+ /* XXX: unreadelf() implicitly closes its fd */ |
165 |
close(fd); |
166 |
return 0; |
167 |
} |
168 |
|
169 |
-static const char *maybe_add_root(const char *fname, char *buf) |
170 |
-{ |
171 |
- if (root && strncmp(fname, root, strlen(root))) { |
172 |
- strcpy(buf, root); |
173 |
- strncat(buf, fname, __PAX_UTILS_PATH_MAX - strlen(root) - 1); |
174 |
- fname = buf; |
175 |
- } |
176 |
- return fname; |
177 |
-} |
178 |
- |
179 |
/* scan a directory for ET_EXEC files and print when we find one */ |
180 |
-static int scanelf_dir(const char *path) |
181 |
+static int scanelf_dirat(int dir_fd, const char *path) |
182 |
{ |
183 |
register DIR *dir; |
184 |
register struct dirent *dentry; |
185 |
struct stat st_top, st; |
186 |
- char buf[__PAX_UTILS_PATH_MAX]; |
187 |
- char _path[__PAX_UTILS_PATH_MAX]; |
188 |
+ char buf[__PAX_UTILS_PATH_MAX], *subpath; |
189 |
size_t pathlen = 0, len = 0; |
190 |
int ret = 0; |
191 |
- |
192 |
- path = maybe_add_root(path, _path); |
193 |
+ int subdir_fd; |
194 |
|
195 |
/* make sure path exists */ |
196 |
- if (lstat(path, &st_top) == -1) { |
197 |
+ if (fstatat(dir_fd, path, &st_top, AT_SYMLINK_NOFOLLOW) == -1) { |
198 |
if (be_verbose > 2) printf("%s: does not exist\n", path); |
199 |
return 1; |
200 |
} |
201 |
|
202 |
/* ok, if it isn't a directory, assume we can open it */ |
203 |
- if (!S_ISDIR(st_top.st_mode)) { |
204 |
- return scanelf_file(path, &st_top); |
205 |
- } |
206 |
+ if (!S_ISDIR(st_top.st_mode)) |
207 |
+ return scanelf_fileat(dir_fd, path, &st_top); |
208 |
|
209 |
/* now scan the dir looking for fun stuff */ |
210 |
- if ((dir = opendir(path)) == NULL) { |
211 |
+ subdir_fd = openat(dir_fd, path, O_RDONLY|O_CLOEXEC); |
212 |
+ if (subdir_fd == -1) |
213 |
+ dir = NULL; |
214 |
+ else |
215 |
+ dir = fdopendir(subdir_fd); |
216 |
+ if (dir == NULL) { |
217 |
+ if (subdir_fd != -1) |
218 |
+ close(subdir_fd); |
219 |
warnf("could not opendir %s: %s", path, strerror(errno)); |
220 |
return 1; |
221 |
} |
222 |
if (be_verbose > 1) printf("%s: scanning dir\n", path); |
223 |
|
224 |
- pathlen = strlen(path); |
225 |
+ subpath = stpcpy(buf, path); |
226 |
+ *subpath++ = '/'; |
227 |
+ pathlen = subpath - buf; |
228 |
while ((dentry = readdir(dir))) { |
229 |
if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) |
230 |
continue; |
231 |
- len = (pathlen + 1 + strlen(dentry->d_name) + 1); |
232 |
- if (len >= sizeof(buf)) { |
233 |
- warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path, |
234 |
- (unsigned long)len, (unsigned long)sizeof(buf)); |
235 |
+ |
236 |
+ if (fstatat(subdir_fd, dentry->d_name, &st, AT_SYMLINK_NOFOLLOW) == -1) |
237 |
+ continue; |
238 |
+ |
239 |
+ len = strlen(dentry->d_name); |
240 |
+ if (len + pathlen + 1 >= sizeof(buf)) { |
241 |
+ warnf("Skipping '%s%s': len > sizeof(buf); %zu > %zu\n", |
242 |
+ path, dentry->d_name, len + pathlen + 1, sizeof(buf)); |
243 |
continue; |
244 |
} |
245 |
- snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name); |
246 |
- if (lstat(buf, &st) != -1) { |
247 |
- if (S_ISREG(st.st_mode)) |
248 |
- ret = scanelf_file(buf, &st); |
249 |
- else if (dir_recurse && S_ISDIR(st.st_mode)) { |
250 |
- if (dir_crossmount || (st_top.st_dev == st.st_dev)) |
251 |
- ret = scanelf_dir(buf); |
252 |
- } |
253 |
+ memcpy(subpath, dentry->d_name, len); |
254 |
+ subpath[len] = '\0'; |
255 |
+ |
256 |
+ if (S_ISREG(st.st_mode)) |
257 |
+ ret = scanelf_fileat(dir_fd, buf, &st); |
258 |
+ else if (dir_recurse && S_ISDIR(st.st_mode)) { |
259 |
+ if (dir_crossmount || (st_top.st_dev == st.st_dev)) |
260 |
+ ret = scanelf_dirat(dir_fd, buf); |
261 |
} |
262 |
} |
263 |
closedir(dir); |
264 |
+ |
265 |
return ret; |
266 |
} |
267 |
+static int scanelf_dir(const char *path) |
268 |
+{ |
269 |
+ return scanelf_dirat(root_fd, root_rel_path(path)); |
270 |
+} |
271 |
|
272 |
static int scanelf_from_file(const char *filename) |
273 |
{ |
274 |
@@ -1616,11 +1651,10 @@ |
275 |
FILE *fp = NULL; |
276 |
char *p, *path; |
277 |
size_t len; |
278 |
- char _fname[__PAX_UTILS_PATH_MAX]; |
279 |
+ int curr_fd = -1; |
280 |
|
281 |
- fname = maybe_add_root(fname, _fname); |
282 |
- |
283 |
- if ((fp = fopen(fname, "r")) == NULL) |
284 |
+ fp = fopenat_r(root_fd, root_rel_path(fname)); |
285 |
+ if (fp == NULL) |
286 |
return i; |
287 |
|
288 |
path = NULL; |
289 |
@@ -1635,16 +1669,21 @@ |
290 |
if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) { |
291 |
glob_t gl; |
292 |
size_t x; |
293 |
- char gpath[__PAX_UTILS_PATH_MAX]; |
294 |
- |
295 |
- memset(gpath, 0, sizeof(gpath)); |
296 |
- if (root) |
297 |
- strcpy(gpath, root); |
298 |
+ const char *gpath; |
299 |
|
300 |
+ /* re-use existing path buffer ... need to be creative */ |
301 |
if (path[8] != '/') |
302 |
- snprintf(gpath+strlen(gpath), sizeof(gpath)-strlen(gpath), "/etc/%s", &path[8]); |
303 |
+ gpath = memcpy(path + 3, "/etc/", 5); |
304 |
else |
305 |
- strncpy(gpath+strlen(gpath), &path[8], sizeof(gpath)-strlen(gpath)); |
306 |
+ gpath = path + 8; |
307 |
+ if (root_fd != AT_FDCWD) { |
308 |
+ if (curr_fd == -1) { |
309 |
+ curr_fd = open(".", O_RDONLY|O_CLOEXEC); |
310 |
+ if (fchdir(root_fd)) |
311 |
+ errp("unable to change to root dir"); |
312 |
+ } |
313 |
+ gpath = root_rel_path(gpath); |
314 |
+ } |
315 |
|
316 |
if (glob(gpath, 0, NULL, &gl) == 0) { |
317 |
for (x = 0; x < gl.gl_pathc; ++x) { |
318 |
@@ -1654,8 +1693,10 @@ |
319 |
i = load_ld_cache_config(i, gl.gl_pathv[x]); |
320 |
} |
321 |
globfree(&gl); |
322 |
- continue; |
323 |
} |
324 |
+ |
325 |
+ /* failed globs are ignored by glibc */ |
326 |
+ continue; |
327 |
} |
328 |
|
329 |
if (*path != '/') |
330 |
@@ -1667,6 +1708,12 @@ |
331 |
|
332 |
fclose(fp); |
333 |
|
334 |
+ if (curr_fd != -1) { |
335 |
+ if (fchdir(curr_fd)) |
336 |
+ /* don't care */; |
337 |
+ close(curr_fd); |
338 |
+ } |
339 |
+ |
340 |
return i; |
341 |
} |
342 |
|
343 |
@@ -1677,11 +1724,9 @@ |
344 |
FILE *fp = NULL; |
345 |
char *b = NULL, *p; |
346 |
struct elfhints_hdr hdr; |
347 |
- char _fname[__PAX_UTILS_PATH_MAX]; |
348 |
- |
349 |
- fname = maybe_add_root(fname, _fname); |
350 |
|
351 |
- if ((fp = fopen(fname, "r")) == NULL) |
352 |
+ fp = fopenat_r(root_fd, root_rel_path(fname)); |
353 |
+ if (fp == NULL) |
354 |
return i; |
355 |
|
356 |
if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) || |
357 |
@@ -2015,7 +2060,9 @@ |
358 |
case 'I': show_osabi = 1; break; |
359 |
case 'Y': show_eabi = 1; break; |
360 |
case 128: |
361 |
- root = optarg; |
362 |
+ root_fd = open(optarg, O_RDONLY|O_CLOEXEC); |
363 |
+ if (root_fd == -1) |
364 |
+ err("Could not open root: %s", optarg); |
365 |
break; |
366 |
case ':': |
367 |
err("Option '%c' is missing parameter", optopt); |
368 |
@@ -2194,7 +2241,7 @@ |
369 |
#ifdef __PAX_UTILS_CLEANUP |
370 |
cleanup(); |
371 |
warn("The calls to add/delete heap should be off:\n" |
372 |
- "\t- 1 due to the out_buffer not being freed in scanelf_file()\n" |
373 |
+ "\t- 1 due to the out_buffer not being freed in scanelf_fileat()\n" |
374 |
"\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD"); |
375 |
#endif |
376 |
return ret; |