diff options
author | netblue30 <netblue30@yahoo.com> | 2017-08-03 13:52:42 -0400 |
---|---|---|
committer | netblue30 <netblue30@yahoo.com> | 2017-08-03 13:52:42 -0400 |
commit | 0823eebfb6fc3c972d2a591ddae2ec4e668c95ff (patch) | |
tree | 9224fe3a972fe19bf8ba628c709b1f0020c0db0b /src/firejail/fs_lib.c | |
parent | Merge pull request #1426 from VladimirSchowalter20/master (diff) | |
download | firejail-0823eebfb6fc3c972d2a591ddae2ec4e668c95ff.tar.gz firejail-0823eebfb6fc3c972d2a591ddae2ec4e668c95ff.tar.zst firejail-0823eebfb6fc3c972d2a591ddae2ec4e668c95ff.zip |
private-lib: split fldd as a separate application
Diffstat (limited to 'src/firejail/fs_lib.c')
-rw-r--r-- | src/firejail/fs_lib.c | 156 |
1 files changed, 32 insertions, 124 deletions
diff --git a/src/firejail/fs_lib.c b/src/firejail/fs_lib.c index d86588792..576b4a0df 100644 --- a/src/firejail/fs_lib.c +++ b/src/firejail/fs_lib.c | |||
@@ -18,156 +18,60 @@ | |||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include <elf.h> | ||
22 | #include <fcntl.h> | ||
23 | #include <sys/mman.h> | ||
24 | #include <sys/mount.h> | 21 | #include <sys/mount.h> |
25 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
26 | #include <sys/types.h> | 23 | #include <sys/types.h> |
27 | #include <unistd.h> | 24 | #include <unistd.h> |
28 | 25 | ||
29 | #ifdef __LP64__ | ||
30 | #define Elf_Ehdr Elf64_Ehdr | ||
31 | #define Elf_Phdr Elf64_Phdr | ||
32 | #define Elf_Shdr Elf64_Shdr | ||
33 | #define Elf_Dyn Elf64_Dyn | ||
34 | #else | ||
35 | #define Elf_Ehdr Elf32_Ehdr | ||
36 | #define Elf_Phdr Elf32_Phdr | ||
37 | #define Elf_Shdr Elf32_Shdr | ||
38 | #define Elf_Dyn Elf32_Dyn | ||
39 | #endif | ||
40 | |||
41 | static const char * const lib_paths[] = { | ||
42 | "/lib", | ||
43 | "/lib/x86_64-linux-gnu", | ||
44 | "/lib64", | ||
45 | "/usr/lib", | ||
46 | "/usr/lib/x86_64-linux-gnu", | ||
47 | LIBDIR, | ||
48 | "/usr/local/lib", | ||
49 | NULL | ||
50 | }; | ||
51 | |||
52 | static void copy_libs_for_lib(const char *lib, const char *private_run_dir); | ||
53 | |||
54 | static void duplicate(const char *fname, const char *private_run_dir) { | 26 | static void duplicate(const char *fname, const char *private_run_dir) { |
55 | if (arg_debug) | 27 | if (arg_debug) |
56 | printf("copying %s to private %s\n", fname, private_run_dir); | 28 | printf("copying %s to private %s\n", fname, private_run_dir); |
57 | sbox_run(SBOX_ROOT| SBOX_SECCOMP, 4, PATH_FCOPY, "--follow-link", fname, private_run_dir); | 29 | sbox_run(SBOX_ROOT| SBOX_SECCOMP, 4, PATH_FCOPY, "--follow-link", fname, private_run_dir); |
58 | } | 30 | } |
59 | 31 | ||
60 | static void copy_libs_for_exe(const char *exe, const char *private_run_dir) { | 32 | static void copy_libs(const char *exe, const char *dir, const char *file) { |
61 | if (arg_debug) | 33 | // create an empty RUN_LIB_FILE and allow the user to write to it |
62 | printf("copy libs for %s\n", exe); | 34 | unlink(file); // in case is there |
63 | int f; | 35 | create_empty_file_as_root(file, 0644); |
64 | f = open(exe, O_RDONLY); | 36 | if (chown(file, getuid(), getgid())) |
65 | if (f < 0) | 37 | errExit("chown"); |
66 | return; | 38 | |
67 | struct stat s; | 39 | // run fldd to extact the list of file |
68 | char *base = NULL; | 40 | sbox_run(SBOX_USER | SBOX_SECCOMP | SBOX_CAPS_NONE, 3, PATH_FLDD, exe, file); |
69 | if (fstat(f, &s) == -1) | 41 | |
70 | goto error_close; | 42 | // open the list of libraries and install them on by one |
71 | base = mmap(0, s.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, f, 0); | 43 | FILE *fp = fopen(file, "r"); |
72 | if (base == MAP_FAILED) | 44 | if (!fp) |
73 | goto error_close; | 45 | errExit("fopen"); |
74 | 46 | ||
75 | Elf_Ehdr *ebuf = (Elf_Ehdr *)base; | 47 | #define MAXBUF 4096 |
76 | if (strncmp((const char *)ebuf->e_ident, ELFMAG, SELFMAG) != 0) | 48 | char buf[MAXBUF]; |
77 | goto close; | 49 | while (fgets(buf, MAXBUF, fp)) { |
78 | 50 | // remove \n | |
79 | Elf_Phdr *pbuf = (Elf_Phdr *)(base + sizeof(*ebuf)); | 51 | char *ptr = strchr(buf, '\n'); |
80 | while (ebuf->e_phnum-- > 0) { | 52 | if (ptr) |
81 | switch (pbuf->p_type) { | 53 | *ptr = '\0'; |
82 | case PT_INTERP: | 54 | duplicate(buf, dir); |
83 | // dynamic loader ld-linux.so | ||
84 | duplicate(base + pbuf->p_offset, private_run_dir); | ||
85 | break; | ||
86 | } | ||
87 | pbuf++; | ||
88 | } | ||
89 | |||
90 | Elf_Shdr *sbuf = (Elf_Shdr *)(base + ebuf->e_shoff); | ||
91 | |||
92 | // Find strings section | ||
93 | char *strbase = NULL; | ||
94 | int sections = ebuf->e_shnum; | ||
95 | while (sections-- > 0) { | ||
96 | if (sbuf->sh_type == SHT_STRTAB) { | ||
97 | strbase = base + sbuf->sh_offset; | ||
98 | break; | ||
99 | } | ||
100 | sbuf++; | ||
101 | } | 55 | } |
102 | if (strbase == NULL) | 56 | fclose(fp); |
103 | goto error_close; | ||
104 | |||
105 | // Find dynamic section | ||
106 | sections = ebuf->e_shnum; | ||
107 | while (sections-- > 0) { | ||
108 | if (sbuf->sh_type == SHT_DYNAMIC) { | ||
109 | // Find DT_NEEDED tags | ||
110 | Elf_Dyn *dbuf = (Elf_Dyn *)(base + sbuf->sh_offset); | ||
111 | while (sbuf->sh_size >= sizeof(*dbuf)) { | ||
112 | if (dbuf->d_tag == DT_NEEDED) { | ||
113 | const char *lib = strbase + dbuf->d_un.d_ptr; | ||
114 | copy_libs_for_lib(lib, private_run_dir); | ||
115 | } | ||
116 | sbuf->sh_size -= sizeof(*dbuf); | ||
117 | dbuf++; | ||
118 | } | ||
119 | } | ||
120 | sbuf++; | ||
121 | } | ||
122 | goto close; | ||
123 | |||
124 | error_close: | ||
125 | perror("copy libs"); | ||
126 | close: | ||
127 | if (base) | ||
128 | munmap(base, s.st_size); | ||
129 | close(f); | ||
130 | } | 57 | } |
131 | 58 | ||
132 | static void copy_libs_for_lib(const char *lib, const char *private_run_dir) { | ||
133 | int i; | ||
134 | for (i = 0; lib_paths[i]; i++) { | ||
135 | char *fname; | ||
136 | if (asprintf(&fname, "%s/%s", lib_paths[i], lib) == -1) | ||
137 | errExit("asprintf"); | ||
138 | if (access(fname, R_OK) == 0) { | ||
139 | char *dst; | ||
140 | if (asprintf(&dst, "%s/%s", private_run_dir, lib) == -1) | ||
141 | errExit("asprintf"); | ||
142 | |||
143 | if (access(dst, R_OK) != 0) { | ||
144 | duplicate(fname, private_run_dir); | ||
145 | // libs may need other libs | ||
146 | copy_libs_for_exe(fname, private_run_dir); | ||
147 | } | ||
148 | free(dst); | ||
149 | free(fname); | ||
150 | return; | ||
151 | } | ||
152 | free(fname); | ||
153 | } | ||
154 | errExit("library not found"); | ||
155 | } | ||
156 | 59 | ||
157 | void fs_private_lib(void) { | 60 | void fs_private_lib(void) { |
158 | char *private_list = cfg.lib_private_keep; | 61 | // char *private_list = cfg.lib_private_keep; |
159 | 62 | ||
160 | // create /run/firejail/mnt/lib directory | 63 | // create /run/firejail/mnt/lib directory |
161 | mkdir_attr(RUN_LIB_DIR, 0755, 0, 0); | 64 | mkdir_attr(RUN_LIB_DIR, 0755, 0, 0); |
162 | 65 | ||
163 | // copy the libs in the new lib directory for the main exe | 66 | // copy the libs in the new lib directory for the main exe |
164 | if (cfg.original_program_index > 0) | 67 | if (cfg.original_program_index > 0) |
165 | copy_libs_for_exe(cfg.original_argv[cfg.original_program_index], RUN_LIB_DIR); | 68 | copy_libs(cfg.original_argv[cfg.original_program_index], RUN_LIB_DIR, RUN_LIB_FILE); |
166 | 69 | ||
167 | // for the shell | 70 | // for the shell |
168 | if (!arg_shell_none) | 71 | if (!arg_shell_none) |
169 | copy_libs_for_exe(cfg.shell, RUN_LIB_DIR); | 72 | copy_libs(cfg.shell, RUN_LIB_DIR, RUN_LIB_FILE); |
170 | 73 | ||
74 | #if 0 // TODO - work in progress | ||
171 | // for the listed libs | 75 | // for the listed libs |
172 | if (private_list && *private_list != '\0') { | 76 | if (private_list && *private_list != '\0') { |
173 | if (arg_debug) | 77 | if (arg_debug) |
@@ -185,6 +89,7 @@ void fs_private_lib(void) { | |||
185 | free(dlist); | 89 | free(dlist); |
186 | fs_logger_print(); | 90 | fs_logger_print(); |
187 | } | 91 | } |
92 | #endif | ||
188 | 93 | ||
189 | // for our trace and tracelog libs | 94 | // for our trace and tracelog libs |
190 | if (arg_trace) | 95 | if (arg_trace) |
@@ -194,14 +99,17 @@ void fs_private_lib(void) { | |||
194 | 99 | ||
195 | if (arg_debug) | 100 | if (arg_debug) |
196 | printf("Mount-bind %s on top of /lib /lib64 /usr/lib\n", RUN_LIB_DIR); | 101 | printf("Mount-bind %s on top of /lib /lib64 /usr/lib\n", RUN_LIB_DIR); |
102 | |||
197 | if (mount(RUN_LIB_DIR, "/lib", NULL, MS_BIND|MS_REC, NULL) < 0 || | 103 | if (mount(RUN_LIB_DIR, "/lib", NULL, MS_BIND|MS_REC, NULL) < 0 || |
198 | mount(NULL, "/lib", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0) | 104 | mount(NULL, "/lib", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0) |
199 | errExit("mount bind"); | 105 | errExit("mount bind"); |
200 | fs_logger("mount /lib"); | 106 | fs_logger("mount /lib"); |
107 | |||
201 | if (mount(RUN_LIB_DIR, "/lib64", NULL, MS_BIND|MS_REC, NULL) < 0 || | 108 | if (mount(RUN_LIB_DIR, "/lib64", NULL, MS_BIND|MS_REC, NULL) < 0 || |
202 | mount(NULL, "/lib64", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0) | 109 | mount(NULL, "/lib64", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0) |
203 | errExit("mount bind"); | 110 | errExit("mount bind"); |
204 | fs_logger("mount /lib64"); | 111 | fs_logger("mount /lib64"); |
112 | |||
205 | if (mount(RUN_LIB_DIR, "/usr/lib", NULL, MS_BIND|MS_REC, NULL) < 0 || | 113 | if (mount(RUN_LIB_DIR, "/usr/lib", NULL, MS_BIND|MS_REC, NULL) < 0 || |
206 | mount(NULL, "/usr/lib", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0) | 114 | mount(NULL, "/usr/lib", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0) |
207 | errExit("mount bind"); | 115 | errExit("mount bind"); |