diff options
author | 2017-07-24 11:45:13 +0300 | |
---|---|---|
committer | 2017-07-30 16:35:17 +0000 | |
commit | 1da9f74b4dbfe186f893a2f3712135eb00bbed09 (patch) | |
tree | 0c4e3a587e5df6f99fbd58d316e1dddb55b5da64 /src/firejail/fs_lib.c | |
parent | merges (diff) | |
download | firejail-1da9f74b4dbfe186f893a2f3712135eb00bbed09.tar.gz firejail-1da9f74b4dbfe186f893a2f3712135eb00bbed09.tar.zst firejail-1da9f74b4dbfe186f893a2f3712135eb00bbed09.zip |
Private /lib feature
Diffstat (limited to 'src/firejail/fs_lib.c')
-rw-r--r-- | src/firejail/fs_lib.c | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/src/firejail/fs_lib.c b/src/firejail/fs_lib.c new file mode 100644 index 000000000..4d328af7f --- /dev/null +++ b/src/firejail/fs_lib.c | |||
@@ -0,0 +1,203 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 Firejail Authors | ||
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 | #include "firejail.h" | ||
21 | #include <elf.h> | ||
22 | #include <fcntl.h> | ||
23 | #include <sys/mman.h> | ||
24 | #include <sys/mount.h> | ||
25 | #include <sys/stat.h> | ||
26 | #include <sys/types.h> | ||
27 | #include <unistd.h> | ||
28 | |||
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) { | ||
55 | if (arg_debug) | ||
56 | 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); | ||
58 | } | ||
59 | |||
60 | static void copy_libs_for_exe(const char *exe, const char *private_run_dir) { | ||
61 | if (arg_debug) | ||
62 | printf("copy libs for %s\n", exe); | ||
63 | int f; | ||
64 | f = open(exe, O_RDONLY); | ||
65 | if (f < 0) | ||
66 | return; | ||
67 | struct stat s; | ||
68 | char *base = NULL; | ||
69 | if (fstat(f, &s) == -1) | ||
70 | goto error_close; | ||
71 | base = mmap(0, s.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, f, 0); | ||
72 | if (base == MAP_FAILED) | ||
73 | goto error_close; | ||
74 | |||
75 | Elf_Ehdr *ebuf = (Elf_Ehdr *)base; | ||
76 | if (strncmp((const char *)ebuf->e_ident, ELFMAG, SELFMAG) != 0) | ||
77 | goto close; | ||
78 | |||
79 | Elf_Phdr *pbuf = (Elf_Phdr *)(base + sizeof(*ebuf)); | ||
80 | while (ebuf->e_phnum-- > 0) { | ||
81 | switch (pbuf->p_type) { | ||
82 | case PT_INTERP: | ||
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 | } | ||
102 | if (strbase == NULL) | ||
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 | } | ||
131 | |||
132 | static void copy_libs_for_lib(const char *lib, const char *private_run_dir) { | ||
133 | for (int i = 0; lib_paths[i]; i++) { | ||
134 | char *fname; | ||
135 | if (asprintf(&fname, "%s/%s", lib_paths[i], lib) == -1) | ||
136 | errExit("asprintf"); | ||
137 | if (access(fname, R_OK) == 0) { | ||
138 | char *dst; | ||
139 | if (asprintf(&dst, "%s/%s", private_run_dir, lib) == -1) | ||
140 | errExit("asprintf"); | ||
141 | |||
142 | if (access(dst, R_OK) != 0) { | ||
143 | duplicate(fname, private_run_dir); | ||
144 | // libs may need other libs | ||
145 | copy_libs_for_exe(fname, private_run_dir); | ||
146 | } | ||
147 | free(dst); | ||
148 | free(fname); | ||
149 | return; | ||
150 | } | ||
151 | free(fname); | ||
152 | } | ||
153 | errExit("library not found"); | ||
154 | } | ||
155 | |||
156 | void fs_private_lib(void) { | ||
157 | char *private_list = cfg.lib_private_keep; | ||
158 | assert(private_list); | ||
159 | |||
160 | // create /run/firejail/mnt/lib directory | ||
161 | mkdir_attr(RUN_LIB_DIR, 0755, 0, 0); | ||
162 | |||
163 | // copy the libs in the new lib directory for the main exe | ||
164 | if (cfg.original_program_index > 0) | ||
165 | copy_libs_for_exe(cfg.original_argv[cfg.original_program_index], RUN_LIB_DIR); | ||
166 | |||
167 | // for the shell | ||
168 | if (!arg_shell_none) | ||
169 | copy_libs_for_exe(cfg.shell, RUN_LIB_DIR); | ||
170 | |||
171 | // for the listed libs | ||
172 | if (*private_list != '\0') { | ||
173 | if (arg_debug) | ||
174 | printf("Copying extra files in the new lib directory:\n"); | ||
175 | |||
176 | char *dlist = strdup(private_list); | ||
177 | if (!dlist) | ||
178 | errExit("strdup"); | ||
179 | |||
180 | char *ptr = strtok(dlist, ","); | ||
181 | copy_libs_for_lib(ptr, RUN_LIB_DIR); | ||
182 | |||
183 | while ((ptr = strtok(NULL, ",")) != NULL) | ||
184 | copy_libs_for_lib(ptr, RUN_LIB_DIR); | ||
185 | free(dlist); | ||
186 | fs_logger_print(); | ||
187 | } | ||
188 | |||
189 | if (arg_debug) | ||
190 | printf("Mount-bind %s on top of /lib /lib64 /usr/lib\n", RUN_LIB_DIR); | ||
191 | if (mount(RUN_LIB_DIR, "/lib", NULL, MS_BIND|MS_REC, NULL) < 0 || | ||
192 | mount(NULL, "/lib", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0) | ||
193 | errExit("mount bind"); | ||
194 | fs_logger("mount /lib"); | ||
195 | if (mount(RUN_LIB_DIR, "/lib64", NULL, MS_BIND|MS_REC, NULL) < 0 || | ||
196 | mount(NULL, "/lib64", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0) | ||
197 | errExit("mount bind"); | ||
198 | fs_logger("mount /lib64"); | ||
199 | if (mount(RUN_LIB_DIR, "/usr/lib", NULL, MS_BIND|MS_REC, NULL) < 0 || | ||
200 | mount(NULL, "/usr/lib", NULL, MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NODEV|MS_REC, NULL) < 0) | ||
201 | errExit("mount bind"); | ||
202 | fs_logger("mount /usr/lib"); | ||
203 | } | ||