diff options
author | netblue30 <netblue30@yahoo.com> | 2017-08-04 11:14:04 -0400 |
---|---|---|
committer | netblue30 <netblue30@yahoo.com> | 2017-08-04 11:14:04 -0400 |
commit | a9babdfbce0a88dd7a21584a514b1479bc4c98f6 (patch) | |
tree | 4966fc0ec278654b57a3bc9f865022fb1f21f49a /src/fldd | |
parent | Merge branch 'master' of https://github.com/netblue30/firejail (diff) | |
download | firejail-a9babdfbce0a88dd7a21584a514b1479bc4c98f6.tar.gz firejail-a9babdfbce0a88dd7a21584a514b1479bc4c98f6.tar.zst firejail-a9babdfbce0a88dd7a21584a514b1479bc4c98f6.zip |
private-lib: add src/fldd
Diffstat (limited to 'src/fldd')
-rw-r--r-- | src/fldd/Makefile.in | 45 | ||||
-rw-r--r-- | src/fldd/main.c | 262 |
2 files changed, 307 insertions, 0 deletions
diff --git a/src/fldd/Makefile.in b/src/fldd/Makefile.in new file mode 100644 index 000000000..7369c835b --- /dev/null +++ b/src/fldd/Makefile.in | |||
@@ -0,0 +1,45 @@ | |||
1 | all: fldd | ||
2 | |||
3 | CC=@CC@ | ||
4 | prefix=@prefix@ | ||
5 | exec_prefix=@exec_prefix@ | ||
6 | libdir=@libdir@ | ||
7 | sysconfdir=@sysconfdir@ | ||
8 | |||
9 | VERSION=@PACKAGE_VERSION@ | ||
10 | NAME=@PACKAGE_NAME@ | ||
11 | HAVE_SECCOMP_H=@HAVE_SECCOMP_H@ | ||
12 | HAVE_SECCOMP=@HAVE_SECCOMP@ | ||
13 | HAVE_CHROOT=@HAVE_CHROOT@ | ||
14 | HAVE_BIND=@HAVE_BIND@ | ||
15 | HAVE_FATAL_WARNINGS=@HAVE_FATAL_WARNINGS@ | ||
16 | HAVE_NETWORK=@HAVE_NETWORK@ | ||
17 | HAVE_USERNS=@HAVE_USERNS@ | ||
18 | HAVE_X11=@HAVE_X11@ | ||
19 | HAVE_FILE_TRANSFER=@HAVE_FILE_TRANSFER@ | ||
20 | HAVE_WHITELIST=@HAVE_WHITELIST@ | ||
21 | HAVE_GLOBALCFG=@HAVE_GLOBALCFG@ | ||
22 | HAVE_APPARMOR=@HAVE_APPARMOR@ | ||
23 | HAVE_OVERLAYFS=@HAVE_OVERLAYFS@ | ||
24 | HAVE_PRIVATE_HOME=@HAVE_PRIVATE_HOME@ | ||
25 | EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@ | ||
26 | HAVE_GCOV=@HAVE_GCOV@ | ||
27 | EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@ | ||
28 | |||
29 | H_FILE_LIST = $(sort $(wildcard *.[h])) | ||
30 | C_FILE_LIST = $(sort $(wildcard *.c)) | ||
31 | OBJS = $(C_FILE_LIST:.c=.o) | ||
32 | BINOBJS = $(foreach file, $(OBJS), $file) | ||
33 | CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' $(HAVE_GCOV) -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_SECCOMP) $(HAVE_GLOBALCFG) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_BIND) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security | ||
34 | LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread | ||
35 | |||
36 | %.o : %.c $(H_FILE_LIST) ../include/common.h ../include/syscall.h | ||
37 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ | ||
38 | |||
39 | fldd: $(OBJS) | ||
40 | $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(EXTRA_LDFLAGS) | ||
41 | |||
42 | clean:; rm -f *.o fldd *.gcov *.gcda *.gcno | ||
43 | |||
44 | distclean: clean | ||
45 | rm -fr Makefile | ||
diff --git a/src/fldd/main.c b/src/fldd/main.c new file mode 100644 index 000000000..8b54242a4 --- /dev/null +++ b/src/fldd/main.c | |||
@@ -0,0 +1,262 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2017 netblue30 (netblue30@yahoo.com) | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #include "../include/common.h" | ||
22 | |||
23 | #include <elf.h> | ||
24 | #include <fcntl.h> | ||
25 | #include <sys/mman.h> | ||
26 | #include <sys/mount.h> | ||
27 | #include <sys/stat.h> | ||
28 | #include <sys/types.h> | ||
29 | #include <unistd.h> | ||
30 | |||
31 | #ifdef __LP64__ | ||
32 | #define Elf_Ehdr Elf64_Ehdr | ||
33 | #define Elf_Phdr Elf64_Phdr | ||
34 | #define Elf_Shdr Elf64_Shdr | ||
35 | #define Elf_Dyn Elf64_Dyn | ||
36 | #else | ||
37 | #define Elf_Ehdr Elf32_Ehdr | ||
38 | #define Elf_Phdr Elf32_Phdr | ||
39 | #define Elf_Shdr Elf32_Shdr | ||
40 | #define Elf_Dyn Elf32_Dyn | ||
41 | #endif | ||
42 | |||
43 | static int arg_quiet = 0; | ||
44 | static void copy_libs_for_lib(const char *lib); | ||
45 | |||
46 | static const char * const lib_paths[] = { | ||
47 | "/lib", | ||
48 | "/lib/x86_64-linux-gnu", | ||
49 | "/lib64", | ||
50 | "/usr/lib", | ||
51 | "/usr/lib/x86_64-linux-gnu", | ||
52 | LIBDIR, | ||
53 | "/usr/local/lib", | ||
54 | NULL | ||
55 | }; // Note: this array is duplicated in src/firejail/fs_lib.c | ||
56 | |||
57 | |||
58 | typedef struct storage_t { | ||
59 | struct storage_t *next; | ||
60 | const char *name; | ||
61 | } Storage; | ||
62 | static Storage *head; | ||
63 | |||
64 | // return 1 if found | ||
65 | static int storage_find(const char *name) { | ||
66 | Storage *ptr = head; | ||
67 | |||
68 | while (ptr) { | ||
69 | if (strcmp(ptr->name, name) == 0) | ||
70 | return 1; | ||
71 | ptr = ptr->next; | ||
72 | } | ||
73 | |||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static void storage_add(const char *name) { | ||
78 | if (storage_find(name)) | ||
79 | return; | ||
80 | |||
81 | Storage *s = malloc(sizeof(Storage)); | ||
82 | if (!s) | ||
83 | errExit("malloc"); | ||
84 | s->next = head; | ||
85 | head = s; | ||
86 | s->name = strdup(name); | ||
87 | if (!s->name) | ||
88 | errExit("strdup"); | ||
89 | } | ||
90 | |||
91 | |||
92 | static void storage_print(int fd) { | ||
93 | Storage *ptr = head; | ||
94 | |||
95 | while (ptr) { | ||
96 | dprintf(fd, "%s\n", ptr->name); | ||
97 | ptr = ptr->next; | ||
98 | } | ||
99 | } | ||
100 | |||
101 | |||
102 | |||
103 | static void copy_libs_for_exe(const char *exe) { | ||
104 | int f; | ||
105 | f = open(exe, O_RDONLY); | ||
106 | if (f < 0) { | ||
107 | if (!arg_quiet) | ||
108 | fprintf(stderr, "Warning fldd: cannot open %s\n", exe); | ||
109 | return; | ||
110 | } | ||
111 | |||
112 | struct stat s; | ||
113 | char *base = NULL; | ||
114 | if (fstat(f, &s) == -1) | ||
115 | goto error_close; | ||
116 | base = mmap(0, s.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, f, 0); | ||
117 | if (base == MAP_FAILED) | ||
118 | goto error_close; | ||
119 | |||
120 | |||
121 | Elf_Ehdr *ebuf = (Elf_Ehdr *)base; | ||
122 | if (strncmp((const char *)ebuf->e_ident, ELFMAG, SELFMAG) != 0) { | ||
123 | if (!arg_quiet) | ||
124 | fprintf(stderr, "Warning fldd: %s is not an ELF executable or library\n", exe); | ||
125 | goto close; | ||
126 | } | ||
127 | |||
128 | Elf_Phdr *pbuf = (Elf_Phdr *)(base + sizeof(*ebuf)); | ||
129 | while (ebuf->e_phnum-- > 0) { | ||
130 | switch (pbuf->p_type) { | ||
131 | case PT_INTERP: | ||
132 | // dynamic loader ld-linux.so | ||
133 | storage_add(base + pbuf->p_offset); | ||
134 | break; | ||
135 | } | ||
136 | pbuf++; | ||
137 | } | ||
138 | |||
139 | Elf_Shdr *sbuf = (Elf_Shdr *)(base + ebuf->e_shoff); | ||
140 | |||
141 | // Find strings section | ||
142 | char *strbase = NULL; | ||
143 | int sections = ebuf->e_shnum; | ||
144 | while (sections-- > 0) { | ||
145 | if (sbuf->sh_type == SHT_STRTAB) { | ||
146 | strbase = base + sbuf->sh_offset; | ||
147 | break; | ||
148 | } | ||
149 | sbuf++; | ||
150 | } | ||
151 | if (strbase == NULL) | ||
152 | goto error_close; | ||
153 | |||
154 | // Find dynamic section | ||
155 | sections = ebuf->e_shnum; | ||
156 | while (sections-- > 0) { | ||
157 | // 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) | ||
159 | // for now we just exit the while loop - this is probably incorrect | ||
160 | // printf("sbuf %p #%s#, sections %d, type %u\n", sbuf, exe, sections, sbuf->sh_type); | ||
161 | if (sbuf->sh_type == SHT_NULL) | ||
162 | break; | ||
163 | if (sbuf->sh_type == SHT_DYNAMIC) { | ||
164 | // Find DT_NEEDED tags | ||
165 | Elf_Dyn *dbuf = (Elf_Dyn *)(base + sbuf->sh_offset); | ||
166 | while (sbuf->sh_size >= sizeof(*dbuf)) { | ||
167 | if (dbuf->d_tag == DT_NEEDED) { | ||
168 | const char *lib = strbase + dbuf->d_un.d_ptr; | ||
169 | copy_libs_for_lib(lib); | ||
170 | } | ||
171 | sbuf->sh_size -= sizeof(*dbuf); | ||
172 | dbuf++; | ||
173 | } | ||
174 | } | ||
175 | sbuf++; | ||
176 | } | ||
177 | goto close; | ||
178 | |||
179 | error_close: | ||
180 | perror("copy libs"); | ||
181 | close: | ||
182 | if (base) | ||
183 | munmap(base, s.st_size); | ||
184 | |||
185 | close(f); | ||
186 | } | ||
187 | |||
188 | static void copy_libs_for_lib(const char *lib) { | ||
189 | int i; | ||
190 | for (i = 0; lib_paths[i]; i++) { | ||
191 | char *fname; | ||
192 | if (asprintf(&fname, "%s/%s", lib_paths[i], lib) == -1) | ||
193 | errExit("asprintf"); | ||
194 | if (access(fname, R_OK) == 0) { | ||
195 | if (!storage_find(fname)) { | ||
196 | storage_add(fname); | ||
197 | // libs may need other libs | ||
198 | copy_libs_for_exe(fname); | ||
199 | } | ||
200 | free(fname); | ||
201 | return; | ||
202 | } | ||
203 | free(fname); | ||
204 | } | ||
205 | errExit("library not found"); | ||
206 | } | ||
207 | |||
208 | static void usage(void) { | ||
209 | printf("Usage: fldd program [file]\n"); | ||
210 | printf("print a list of libraries used by program or store it in the file.\n"); | ||
211 | } | ||
212 | |||
213 | int main(int argc, char **argv) { | ||
214 | #if 0 | ||
215 | { | ||
216 | //system("cat /proc/self/status"); | ||
217 | int i; | ||
218 | for (i = 0; i < argc; i++) | ||
219 | printf("*%s* ", argv[i]); | ||
220 | printf("\n"); | ||
221 | } | ||
222 | #endif | ||
223 | if (argc < 2) { | ||
224 | fprintf(stderr, "Error fldd: invalid arguments\n"); | ||
225 | usage(); | ||
226 | exit(1); | ||
227 | } | ||
228 | |||
229 | |||
230 | // check program access | ||
231 | if (access(argv[1], R_OK)) { | ||
232 | fprintf(stderr, "Error fldd: cannot access %s\n", argv[1]); | ||
233 | exit(1); | ||
234 | } | ||
235 | |||
236 | char *quiet = getenv("FIREJAIL_QUIET"); | ||
237 | if (quiet && strcmp(quiet, "yes") == 0) | ||
238 | arg_quiet = 1; | ||
239 | |||
240 | if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { | ||
241 | usage(); | ||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | int fd = STDOUT_FILENO; | ||
246 | // attempt to open the file | ||
247 | if (argc == 3) { | ||
248 | fd = open(argv[2], O_CREAT | O_TRUNC | O_WRONLY, 0644); | ||
249 | if (!fd) { | ||
250 | fprintf(stderr, "Error fldd: invalid arguments\n"); | ||
251 | usage(); | ||
252 | exit(1); | ||
253 | } | ||
254 | } | ||
255 | |||
256 | copy_libs_for_exe(argv[1]); | ||
257 | storage_print(fd); | ||
258 | if (argc == 3) | ||
259 | close(fd); | ||
260 | |||
261 | return 0; | ||
262 | } | ||