diff options
author | Topi Miettinen <toiwoton@gmail.com> | 2017-08-05 21:19:26 +0300 |
---|---|---|
committer | Topi Miettinen <toiwoton@gmail.com> | 2017-08-05 21:19:26 +0300 |
commit | 9ab8689b46245ee4596b3fabdbde35cbef6b1e46 (patch) | |
tree | 4a8dc96d7fa18a51687b364195fb46a6e7c5be44 | |
parent | Merge pull request #1436 from SpotComms/gt (diff) | |
download | firejail-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.
-rw-r--r-- | src/fldd/main.c | 92 |
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 @@ | |||
43 | static int arg_quiet = 0; | 43 | static int arg_quiet = 0; |
44 | static void copy_libs_for_lib(const char *lib); | 44 | static void copy_libs_for_lib(const char *lib); |
45 | 45 | ||
46 | static const char * const lib_paths[] = { | 46 | static 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; |
62 | static Storage *head; | 62 | static Storage *libs, *lib_paths; |
63 | 63 | ||
64 | // return 1 if found | 64 | // return 1 if found |
65 | static int storage_find(const char *name) { | 65 | static 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 | ||
77 | static void storage_add(const char *name) { | 75 | static 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 | ||
92 | static void storage_print(int fd) { | 90 | static 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 | ||
97 | static 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 | ||
103 | static void copy_libs_for_exe(const char *exe) { | 106 | static 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 | ||
188 | static void copy_libs_for_lib(const char *lib) { | 217 | static 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 | ||
240 | static 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 | |||
211 | static void usage(void) { | 246 | static 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 | ||