diff options
author | 2017-10-06 08:56:47 -0400 | |
---|---|---|
committer | 2017-10-06 08:56:47 -0400 | |
commit | 50f4a425047bca1c99ed9e86a46bd0d7a74bf500 (patch) | |
tree | 38a8afcbbb7a267df7a6a2d3b43cce3036789067 /src/fldd/main.c | |
parent | Fixup c6259375dff79484b9f3d587da9fbfa76a3b68b9 (diff) | |
download | firejail-50f4a425047bca1c99ed9e86a46bd0d7a74bf500.tar.gz firejail-50f4a425047bca1c99ed9e86a46bd0d7a74bf500.tar.zst firejail-50f4a425047bca1c99ed9e86a46bd0d7a74bf500.zip |
fldd fixes
Diffstat (limited to 'src/fldd/main.c')
-rw-r--r-- | src/fldd/main.c | 98 |
1 files changed, 78 insertions, 20 deletions
diff --git a/src/fldd/main.c b/src/fldd/main.c index 6127a4a87..c04daa0ed 100644 --- a/src/fldd/main.c +++ b/src/fldd/main.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <sys/stat.h> | 27 | #include <sys/stat.h> |
28 | #include <sys/types.h> | 28 | #include <sys/types.h> |
29 | #include <unistd.h> | 29 | #include <unistd.h> |
30 | #include <dirent.h> | ||
30 | 31 | ||
31 | #ifdef __LP64__ | 32 | #ifdef __LP64__ |
32 | #define Elf_Ehdr Elf64_Ehdr | 33 | #define Elf_Ehdr Elf64_Ehdr |
@@ -59,7 +60,8 @@ typedef struct storage_t { | |||
59 | struct storage_t *next; | 60 | struct storage_t *next; |
60 | const char *name; | 61 | const char *name; |
61 | } Storage; | 62 | } Storage; |
62 | static Storage *libs, *lib_paths; | 63 | static Storage *libs = NULL; |
64 | static Storage *lib_paths = NULL; | ||
63 | 65 | ||
64 | // return 1 if found | 66 | // return 1 if found |
65 | static int storage_find(Storage *ptr, const char *name) { | 67 | static int storage_find(Storage *ptr, const char *name) { |
@@ -94,12 +96,10 @@ static void storage_print(Storage *ptr, int fd) { | |||
94 | } | 96 | } |
95 | } | 97 | } |
96 | 98 | ||
97 | static bool ptr_ok(const void *ptr, const void *base, const void *end, const char *name, const char *exe) { | 99 | static bool ptr_ok(const void *ptr, const void *base, const void *end, const char *name) { |
98 | bool r; | 100 | bool r; |
99 | 101 | ||
100 | r = (ptr >= base && ptr <= end); | 102 | r = (ptr >= base && ptr < end); |
101 | if (!r && !arg_quiet) | ||
102 | fprintf(stderr, "Warning: fldd: bad pointer %s for %s\n", name, exe); | ||
103 | return r; | 103 | return r; |
104 | } | 104 | } |
105 | 105 | ||
@@ -130,11 +130,11 @@ static void copy_libs_for_exe(const char *exe) { | |||
130 | } | 130 | } |
131 | 131 | ||
132 | Elf_Phdr *pbuf = (Elf_Phdr *)(base + sizeof(*ebuf)); | 132 | Elf_Phdr *pbuf = (Elf_Phdr *)(base + sizeof(*ebuf)); |
133 | while (ebuf->e_phnum-- > 0 && ptr_ok(pbuf, base, end, "pbuf", exe)) { | 133 | while (ebuf->e_phnum-- > 0 && ptr_ok(pbuf, base, end, "pbuf")) { |
134 | switch (pbuf->p_type) { | 134 | switch (pbuf->p_type) { |
135 | case PT_INTERP: | 135 | case PT_INTERP: |
136 | // dynamic loader ld-linux.so | 136 | // dynamic loader ld-linux.so |
137 | if (!ptr_ok(base + pbuf->p_offset, base, end, "base + pbuf->p_offset", exe)) | 137 | if (!ptr_ok(base + pbuf->p_offset, base, end, "base + pbuf->p_offset")) |
138 | goto close; | 138 | goto close; |
139 | 139 | ||
140 | storage_add(&libs, base + pbuf->p_offset); | 140 | storage_add(&libs, base + pbuf->p_offset); |
@@ -144,16 +144,16 @@ static void copy_libs_for_exe(const char *exe) { | |||
144 | } | 144 | } |
145 | 145 | ||
146 | Elf_Shdr *sbuf = (Elf_Shdr *)(base + ebuf->e_shoff); | 146 | Elf_Shdr *sbuf = (Elf_Shdr *)(base + ebuf->e_shoff); |
147 | if (!ptr_ok(sbuf, base, end, "sbuf", exe)) | 147 | if (!ptr_ok(sbuf, base, end, "sbuf")) |
148 | goto close; | 148 | goto close; |
149 | 149 | ||
150 | // Find strings section | 150 | // Find strings section |
151 | char *strbase = NULL; | 151 | char *strbase = NULL; |
152 | int sections = ebuf->e_shnum; | 152 | int sections = ebuf->e_shnum; |
153 | while (sections-- > 0 && ptr_ok(sbuf, base, end, "sbuf", exe)) { | 153 | while (sections-- > 0 && ptr_ok(sbuf, base, end, "sbuf")) { |
154 | if (sbuf->sh_type == SHT_STRTAB) { | 154 | if (sbuf->sh_type == SHT_STRTAB) { |
155 | strbase = base + sbuf->sh_offset; | 155 | strbase = base + sbuf->sh_offset; |
156 | if (!ptr_ok(strbase, base, end, "strbase", exe)) | 156 | if (!ptr_ok(strbase, base, end, "strbase")) |
157 | goto close; | 157 | goto close; |
158 | break; | 158 | break; |
159 | } | 159 | } |
@@ -164,23 +164,26 @@ static void copy_libs_for_exe(const char *exe) { | |||
164 | 164 | ||
165 | // Find dynamic section | 165 | // Find dynamic section |
166 | sections = ebuf->e_shnum; | 166 | sections = ebuf->e_shnum; |
167 | while (sections-- > 0 && ptr_ok(sbuf, base, end, "sbuf", exe)) { | 167 | while (sections-- > 0 && ptr_ok(sbuf, base, end, "sbuf")) { |
168 | // TODO: running fldd on large gui programs (fldd /usr/bin/transmission-qt) | 168 | // TODO: running fldd on large gui programs (fldd /usr/bin/transmission-qt) |
169 | // crash on accessing memory location sbuf->sh_type if sbuf->sh_type in the previous section was 0 (SHT_NULL) | 169 | // crash on accessing memory location sbuf->sh_type if sbuf->sh_type in the previous section was 0 (SHT_NULL) |
170 | // for now we just exit the while loop - this is probably incorrect | 170 | // for now we just exit the while loop - this is probably incorrect |
171 | // printf("sbuf %p #%s#, sections %d, type %u\n", sbuf, exe, sections, sbuf->sh_type); | 171 | // printf("sbuf %p #%s#, sections %d, type %u\n", sbuf, exe, sections, sbuf->sh_type); |
172 | if (!ptr_ok(sbuf, base, end, "sbuf")) | ||
173 | goto close; | ||
174 | |||
172 | if (sbuf->sh_type == SHT_NULL) | 175 | if (sbuf->sh_type == SHT_NULL) |
173 | break; | 176 | break; |
174 | if (sbuf->sh_type == SHT_DYNAMIC) { | 177 | if (sbuf->sh_type == SHT_DYNAMIC) { |
175 | Elf_Dyn *dbuf = (Elf_Dyn *)(base + sbuf->sh_offset); | 178 | Elf_Dyn *dbuf = (Elf_Dyn *)(base + sbuf->sh_offset); |
176 | if (!ptr_ok(dbuf, base, end, "dbuf", exe)) | 179 | if (!ptr_ok(dbuf, base, end, "dbuf")) |
177 | goto close; | 180 | goto close; |
178 | // Find DT_RPATH/DT_RUNPATH tags first | 181 | // Find DT_RPATH/DT_RUNPATH tags first |
179 | unsigned long size = sbuf->sh_size; | 182 | unsigned long size = sbuf->sh_size; |
180 | while (size >= sizeof(*dbuf) && ptr_ok(dbuf, base, end, "dbuf", exe)) { | 183 | while (size >= sizeof(*dbuf) && ptr_ok(dbuf, base, end, "dbuf")) { |
181 | if (dbuf->d_tag == DT_RPATH || dbuf->d_tag == DT_RUNPATH) { | 184 | if (dbuf->d_tag == DT_RPATH || dbuf->d_tag == DT_RUNPATH) { |
182 | const char *searchpath = strbase + dbuf->d_un.d_ptr; | 185 | const char *searchpath = strbase + dbuf->d_un.d_ptr; |
183 | if (!ptr_ok(searchpath, base, end, "searchpath", exe)) | 186 | if (!ptr_ok(searchpath, base, end, "searchpath")) |
184 | goto close; | 187 | goto close; |
185 | storage_add(&lib_paths, searchpath); | 188 | storage_add(&lib_paths, searchpath); |
186 | } | 189 | } |
@@ -190,10 +193,10 @@ static void copy_libs_for_exe(const char *exe) { | |||
190 | // Find DT_NEEDED tags | 193 | // Find DT_NEEDED tags |
191 | dbuf = (Elf_Dyn *)(base + sbuf->sh_offset); | 194 | dbuf = (Elf_Dyn *)(base + sbuf->sh_offset); |
192 | size = sbuf->sh_size; | 195 | size = sbuf->sh_size; |
193 | while (size >= sizeof(*dbuf) && ptr_ok(dbuf, base, end, "dbuf", exe)) { | 196 | while (size >= sizeof(*dbuf) && ptr_ok(dbuf, base, end, "dbuf")) { |
194 | if (dbuf->d_tag == DT_NEEDED) { | 197 | if (dbuf->d_tag == DT_NEEDED) { |
195 | const char *lib = strbase + dbuf->d_un.d_ptr; | 198 | const char *lib = strbase + dbuf->d_un.d_ptr; |
196 | if (!ptr_ok(lib, base, end, "lib", exe)) | 199 | if (!ptr_ok(lib, base, end, "lib")) |
197 | goto close; | 200 | goto close; |
198 | copy_libs_for_lib(lib); | 201 | copy_libs_for_lib(lib); |
199 | } | 202 | } |
@@ -243,9 +246,53 @@ static void lib_paths_init(void) { | |||
243 | storage_add(&lib_paths, default_lib_paths[i]); | 246 | storage_add(&lib_paths, default_lib_paths[i]); |
244 | } | 247 | } |
245 | 248 | ||
249 | |||
250 | static void walk_directory(const char *dirname) { | ||
251 | assert(dirname); | ||
252 | |||
253 | DIR *dir = opendir(dirname); | ||
254 | if (dir) { | ||
255 | struct dirent *entry; | ||
256 | while ((entry = readdir(dir)) != NULL) { | ||
257 | if (strcmp(entry->d_name, ".") == 0) | ||
258 | continue; | ||
259 | if (strcmp(entry->d_name, "..") == 0) | ||
260 | continue; | ||
261 | |||
262 | // build full path | ||
263 | char *path; | ||
264 | if (asprintf(&path, "%s/%s", dirname, entry->d_name) == -1) | ||
265 | errExit("asprintf"); | ||
266 | |||
267 | // check regular so library | ||
268 | char *ptr = strstr(entry->d_name, ".so"); | ||
269 | if (ptr) { | ||
270 | if (*(ptr + 3) == '\0' || *(ptr + 3) == '.') { | ||
271 | copy_libs_for_exe(path); | ||
272 | free(path); | ||
273 | continue; | ||
274 | } | ||
275 | } | ||
276 | |||
277 | // check directory | ||
278 | // entry->d_type field is supported in glibc since version 2.19 (Feb 2014) | ||
279 | // we'll use stat to check for directories | ||
280 | struct stat s; | ||
281 | if (stat(path, &s) == -1) | ||
282 | errExit("stat"); | ||
283 | if (S_ISDIR(s.st_mode)) | ||
284 | walk_directory(path); | ||
285 | } | ||
286 | closedir(dir); | ||
287 | } | ||
288 | } | ||
289 | |||
290 | |||
291 | |||
246 | static void usage(void) { | 292 | static void usage(void) { |
247 | printf("Usage: fldd program [file]\n"); | 293 | printf("Usage: fldd program_or_directory [file]\n"); |
248 | printf("print a list of libraries used by program or store it in the file.\n"); | 294 | printf("Print a list of libraries used by program or store it in the file.\n"); |
295 | printf("Print a list of libraries used by all .so files in a directory or store it in the file.\n"); | ||
249 | } | 296 | } |
250 | 297 | ||
251 | int main(int argc, char **argv) { | 298 | int main(int argc, char **argv) { |
@@ -296,11 +343,22 @@ printf("\n"); | |||
296 | } | 343 | } |
297 | } | 344 | } |
298 | 345 | ||
346 | // initialize local storage | ||
299 | lib_paths_init(); | 347 | lib_paths_init(); |
300 | copy_libs_for_exe(argv[1]); | 348 | |
349 | // process files | ||
350 | struct stat s; | ||
351 | if (stat(argv[1], &s) == -1) | ||
352 | errExit("stat"); | ||
353 | if (S_ISDIR(s.st_mode)) | ||
354 | walk_directory(argv[1]); | ||
355 | else | ||
356 | copy_libs_for_exe(argv[1]); | ||
357 | |||
358 | |||
359 | // print libraries and exit | ||
301 | storage_print(libs, fd); | 360 | storage_print(libs, fd); |
302 | if (argc == 3) | 361 | if (argc == 3) |
303 | close(fd); | 362 | close(fd); |
304 | |||
305 | return 0; | 363 | return 0; |
306 | } | 364 | } |