aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2017-10-06 08:56:47 -0400
committerLibravatar netblue30 <netblue30@yahoo.com>2017-10-06 08:56:47 -0400
commit50f4a425047bca1c99ed9e86a46bd0d7a74bf500 (patch)
tree38a8afcbbb7a267df7a6a2d3b43cce3036789067
parentFixup c6259375dff79484b9f3d587da9fbfa76a3b68b9 (diff)
downloadfirejail-50f4a425047bca1c99ed9e86a46bd0d7a74bf500.tar.gz
firejail-50f4a425047bca1c99ed9e86a46bd0d7a74bf500.tar.zst
firejail-50f4a425047bca1c99ed9e86a46bd0d7a74bf500.zip
fldd fixes
-rw-r--r--src/fldd/main.c98
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;
62static Storage *libs, *lib_paths; 63static Storage *libs = NULL;
64static Storage *lib_paths = NULL;
63 65
64// return 1 if found 66// return 1 if found
65static int storage_find(Storage *ptr, const char *name) { 67static 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
97static bool ptr_ok(const void *ptr, const void *base, const void *end, const char *name, const char *exe) { 99static 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
250static 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
246static void usage(void) { 292static 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
251int main(int argc, char **argv) { 298int 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}