Gentoo Archives: gentoo-commits

From: "Mike Frysinger (vapier)" <vapier@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] gentoo-projects commit in pax-utils: scanelf.c
Date: Tue, 27 Sep 2011 22:20:18
Message-Id: 20110927222007.C60C220036@flycatcher.gentoo.org
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;