aboutsummaryrefslogtreecommitdiffstats
path: root/src/fldd/main.c
diff options
context:
space:
mode:
authorLibravatar Topi Miettinen <toiwoton@gmail.com>2017-08-05 21:19:26 +0300
committerLibravatar Topi Miettinen <toiwoton@gmail.com>2017-08-05 21:19:26 +0300
commit9ab8689b46245ee4596b3fabdbde35cbef6b1e46 (patch)
tree4a8dc96d7fa18a51687b364195fb46a6e7c5be44 /src/fldd/main.c
parentMerge pull request #1436 from SpotComms/gt (diff)
downloadfirejail-9ab8689b46245ee4596b3fabdbde35cbef6b1e46.tar.gz
firejail-9ab8689b46245ee4596b3fabdbde35cbef6b1e46.tar.zst
firejail-9ab8689b46245ee4596b3fabdbde35cbef6b1e46.zip
Improve library handling: use DT_RPATH/DT_RUNPATH to find more libs
Helps in more complex cases like this: libpulse.so wants libpulsecommon-10.0.so, which is located in /usr/lib/x86_64-linux-gnu/pulseaudio. This path is specified with DT_RUNPATH.
Diffstat (limited to 'src/fldd/main.c')
-rw-r--r--src/fldd/main.c92
1 files changed, 64 insertions, 28 deletions
diff --git a/src/fldd/main.c b/src/fldd/main.c
index 1c6b3dd25..d9045c425 100644
--- a/src/fldd/main.c
+++ b/src/fldd/main.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2014-2017 netblue30 (netblue30@yahoo.com) 2 * Copyright (C) 2014-2017 Firejail Authors
3 * 3 *
4 * This file is part of firejail project 4 * This file is part of firejail project
5 * 5 *
@@ -43,7 +43,7 @@
43static int arg_quiet = 0; 43static int arg_quiet = 0;
44static void copy_libs_for_lib(const char *lib); 44static void copy_libs_for_lib(const char *lib);
45 45
46static const char * const lib_paths[] = { 46static const char * const default_lib_paths[] = {
47 "/lib", 47 "/lib",
48 "/lib/x86_64-linux-gnu", 48 "/lib/x86_64-linux-gnu",
49 "/lib64", 49 "/lib64",
@@ -59,12 +59,10 @@ typedef struct storage_t {
59 struct storage_t *next; 59 struct storage_t *next;
60 const char *name; 60 const char *name;
61} Storage; 61} Storage;
62static Storage *head; 62static Storage *libs, *lib_paths;
63 63
64// return 1 if found 64// return 1 if found
65static int storage_find(const char *name) { 65static int storage_find(Storage *ptr, const char *name) {
66 Storage *ptr = head;
67
68 while (ptr) { 66 while (ptr) {
69 if (strcmp(ptr->name, name) == 0) 67 if (strcmp(ptr->name, name) == 0)
70 return 1; 68 return 1;
@@ -74,31 +72,36 @@ static int storage_find(const char *name) {
74 return 0; 72 return 0;
75} 73}
76 74
77static void storage_add(const char *name) { 75static void storage_add(Storage **head, const char *name) {
78 if (storage_find(name)) 76 if (storage_find(*head, name))
79 return; 77 return;
80 78
81 Storage *s = malloc(sizeof(Storage)); 79 Storage *s = malloc(sizeof(Storage));
82 if (!s) 80 if (!s)
83 errExit("malloc"); 81 errExit("malloc");
84 s->next = head; 82 s->next = *head;
85 head = s; 83 *head = s;
86 s->name = strdup(name); 84 s->name = strdup(name);
87 if (!s->name) 85 if (!s->name)
88 errExit("strdup"); 86 errExit("strdup");
89} 87}
90 88
91 89
92static void storage_print(int fd) { 90static void storage_print(Storage *ptr, int fd) {
93 Storage *ptr = head;
94
95 while (ptr) { 91 while (ptr) {
96 dprintf(fd, "%s\n", ptr->name); 92 dprintf(fd, "%s\n", ptr->name);
97 ptr = ptr->next; 93 ptr = ptr->next;
98 } 94 }
99} 95}
100 96
97static bool ptr_ok(const void *ptr, const void *base, const void *end, const char *name) {
98 bool r;
101 99
100 r = (ptr >= base && ptr <= end);
101 if (!r && !arg_quiet)
102 fprintf(stderr, "Warning: fldd: bad pointer %s\n", name);
103 return r;
104}
102 105
103static void copy_libs_for_exe(const char *exe) { 106static void copy_libs_for_exe(const char *exe) {
104 int f; 107 int f;
@@ -110,13 +113,14 @@ static void copy_libs_for_exe(const char *exe) {
110 } 113 }
111 114
112 struct stat s; 115 struct stat s;
113 char *base = NULL; 116 char *base = NULL, *end;
114 if (fstat(f, &s) == -1) 117 if (fstat(f, &s) == -1)
115 goto error_close; 118 goto error_close;
116 base = mmap(0, s.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, f, 0); 119 base = mmap(0, s.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, f, 0);
117 if (base == MAP_FAILED) 120 if (base == MAP_FAILED)
118 goto error_close; 121 goto error_close;
119 122
123 end = base + s.st_size;
120 124
121 Elf_Ehdr *ebuf = (Elf_Ehdr *)base; 125 Elf_Ehdr *ebuf = (Elf_Ehdr *)base;
122 if (strncmp((const char *)ebuf->e_ident, ELFMAG, SELFMAG) != 0) { 126 if (strncmp((const char *)ebuf->e_ident, ELFMAG, SELFMAG) != 0) {
@@ -126,24 +130,31 @@ static void copy_libs_for_exe(const char *exe) {
126 } 130 }
127 131
128 Elf_Phdr *pbuf = (Elf_Phdr *)(base + sizeof(*ebuf)); 132 Elf_Phdr *pbuf = (Elf_Phdr *)(base + sizeof(*ebuf));
129 while (ebuf->e_phnum-- > 0) { 133 while (ebuf->e_phnum-- > 0 && ptr_ok(pbuf, base, end, "pbuf")) {
130 switch (pbuf->p_type) { 134 switch (pbuf->p_type) {
131 case PT_INTERP: 135 case PT_INTERP:
132 // dynamic loader ld-linux.so 136 // dynamic loader ld-linux.so
133 storage_add(base + pbuf->p_offset); 137 if (!ptr_ok(base + pbuf->p_offset, base, end, "base + pbuf->p_offset"))
138 goto close;
139
140 storage_add(&libs, base + pbuf->p_offset);
134 break; 141 break;
135 } 142 }
136 pbuf++; 143 pbuf++;
137 } 144 }
138 145
139 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"))
148 goto close;
140 149
141 // Find strings section 150 // Find strings section
142 char *strbase = NULL; 151 char *strbase = NULL;
143 int sections = ebuf->e_shnum; 152 int sections = ebuf->e_shnum;
144 while (sections-- > 0) { 153 while (sections-- > 0 && ptr_ok(sbuf, base, end, "sbuf")) {
145 if (sbuf->sh_type == SHT_STRTAB) { 154 if (sbuf->sh_type == SHT_STRTAB) {
146 strbase = base + sbuf->sh_offset; 155 strbase = base + sbuf->sh_offset;
156 if (!ptr_ok(strbase, base, end, "strbase"))
157 goto close;
147 break; 158 break;
148 } 159 }
149 sbuf++; 160 sbuf++;
@@ -153,7 +164,7 @@ static void copy_libs_for_exe(const char *exe) {
153 164
154 // Find dynamic section 165 // Find dynamic section
155 sections = ebuf->e_shnum; 166 sections = ebuf->e_shnum;
156 while (sections-- > 0) { 167 while (sections-- > 0 && ptr_ok(sbuf, base, end, "sbuf")) {
157// 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)
158// 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)
159// 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
@@ -161,14 +172,32 @@ static void copy_libs_for_exe(const char *exe) {
161 if (sbuf->sh_type == SHT_NULL) 172 if (sbuf->sh_type == SHT_NULL)
162 break; 173 break;
163 if (sbuf->sh_type == SHT_DYNAMIC) { 174 if (sbuf->sh_type == SHT_DYNAMIC) {
164 // Find DT_NEEDED tags
165 Elf_Dyn *dbuf = (Elf_Dyn *)(base + sbuf->sh_offset); 175 Elf_Dyn *dbuf = (Elf_Dyn *)(base + sbuf->sh_offset);
166 while (sbuf->sh_size >= sizeof(*dbuf)) { 176 if (!ptr_ok(dbuf, base, end, "dbuf"))
177 goto close;
178 // Find DT_RPATH/DT_RUNPATH tags first
179 long size = sbuf->sh_size;
180 while (size >= sizeof(*dbuf) && ptr_ok(dbuf, base, end, "dbuf")) {
181 if (dbuf->d_tag == DT_RPATH || dbuf->d_tag == DT_RUNPATH) {
182 const char *searchpath = strbase + dbuf->d_un.d_ptr;
183 if (!ptr_ok(searchpath, base, end, "searchpath"))
184 goto close;
185 storage_add(&lib_paths, searchpath);
186 }
187 size -= sizeof(*dbuf);
188 dbuf++;
189 }
190 // Find DT_NEEDED tags
191 dbuf = (Elf_Dyn *)(base + sbuf->sh_offset);
192 size = sbuf->sh_size;
193 while (size >= sizeof(*dbuf) && ptr_ok(dbuf, base, end, "dbuf")) {
167 if (dbuf->d_tag == DT_NEEDED) { 194 if (dbuf->d_tag == DT_NEEDED) {
168 const char *lib = strbase + dbuf->d_un.d_ptr; 195 const char *lib = strbase + dbuf->d_un.d_ptr;
196 if (!ptr_ok(lib, base, end, "lib"))
197 goto close;
169 copy_libs_for_lib(lib); 198 copy_libs_for_lib(lib);
170 } 199 }
171 sbuf->sh_size -= sizeof(*dbuf); 200 size -= sizeof(*dbuf);
172 dbuf++; 201 dbuf++;
173 } 202 }
174 } 203 }
@@ -186,14 +215,14 @@ static void copy_libs_for_exe(const char *exe) {
186} 215}
187 216
188static void copy_libs_for_lib(const char *lib) { 217static void copy_libs_for_lib(const char *lib) {
189 int i; 218 Storage *lib_path;
190 for (i = 0; lib_paths[i]; i++) { 219 for (lib_path = lib_paths; lib_path; lib_path = lib_path->next) {
191 char *fname; 220 char *fname;
192 if (asprintf(&fname, "%s/%s", lib_paths[i], lib) == -1) 221 if (asprintf(&fname, "%s/%s", lib_path->name, lib) == -1)
193 errExit("asprintf"); 222 errExit("asprintf");
194 if (access(fname, R_OK) == 0) { 223 if (access(fname, R_OK) == 0) {
195 if (!storage_find(fname)) { 224 if (!storage_find(libs, fname)) {
196 storage_add(fname); 225 storage_add(&libs, fname);
197 // libs may need other libs 226 // libs may need other libs
198 copy_libs_for_exe(fname); 227 copy_libs_for_exe(fname);
199 } 228 }
@@ -208,6 +237,12 @@ static void copy_libs_for_lib(const char *lib) {
208 fprintf(stderr, "Warning fldd: cannot find %s, skipping...\n", lib); 237 fprintf(stderr, "Warning fldd: cannot find %s, skipping...\n", lib);
209} 238}
210 239
240static void lib_paths_init(void) {
241 int i;
242 for (i = 0; default_lib_paths[i]; i++)
243 storage_add(&lib_paths, default_lib_paths[i]);
244}
245
211static void usage(void) { 246static void usage(void) {
212 printf("Usage: fldd program [file]\n"); 247 printf("Usage: fldd program [file]\n");
213 printf("print a list of libraries used by program or store it in the file.\n"); 248 printf("print a list of libraries used by program or store it in the file.\n");
@@ -255,9 +290,10 @@ printf("\n");
255 exit(1); 290 exit(1);
256 } 291 }
257 } 292 }
258 293
294 lib_paths_init();
259 copy_libs_for_exe(argv[1]); 295 copy_libs_for_exe(argv[1]);
260 storage_print(fd); 296 storage_print(libs, fd);
261 if (argc == 3) 297 if (argc == 3)
262 close(fd); 298 close(fd);
263 299