diff options
author | Topi Miettinen <toiwoton@gmail.com> | 2017-07-24 11:45:13 +0300 |
---|---|---|
committer | Topi Miettinen <topimiettinen@users.noreply.github.com> | 2017-07-30 16:35:17 +0000 |
commit | 1da9f74b4dbfe186f893a2f3712135eb00bbed09 (patch) | |
tree | 0c4e3a587e5df6f99fbd58d316e1dddb55b5da64 /src | |
parent | merges (diff) | |
download | firejail-1da9f74b4dbfe186f893a2f3712135eb00bbed09.tar.gz firejail-1da9f74b4dbfe186f893a2f3712135eb00bbed09.tar.zst firejail-1da9f74b4dbfe186f893a2f3712135eb00bbed09.zip |
Private /lib feature
Diffstat (limited to 'src')
-rw-r--r-- | src/firejail/firejail.h | 6 | ||||
-rw-r--r-- | src/firejail/fs_lib.c | 203 | ||||
-rw-r--r-- | src/firejail/main.c | 10 | ||||
-rw-r--r-- | src/firejail/profile.c | 12 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 10 | ||||
-rw-r--r-- | src/man/firejail.txt | 28 |
6 files changed, 269 insertions, 0 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index b90c8d8ed..37e4aeb30 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -48,6 +48,7 @@ | |||
48 | #define RUN_SRV_DIR "/run/firejail/mnt/srv" | 48 | #define RUN_SRV_DIR "/run/firejail/mnt/srv" |
49 | #define RUN_BIN_DIR "/run/firejail/mnt/bin" | 49 | #define RUN_BIN_DIR "/run/firejail/mnt/bin" |
50 | #define RUN_PULSE_DIR "/run/firejail/mnt/pulse" | 50 | #define RUN_PULSE_DIR "/run/firejail/mnt/pulse" |
51 | #define RUN_LIB_DIR "/run/firejail/mnt/lib" | ||
51 | 52 | ||
52 | #define RUN_SECCOMP_PROTOCOL "/run/firejail/mnt/seccomp.protocol" // protocol filter | 53 | #define RUN_SECCOMP_PROTOCOL "/run/firejail/mnt/seccomp.protocol" // protocol filter |
53 | #define RUN_SECCOMP_CFG "/run/firejail/mnt/seccomp" // configured filter | 54 | #define RUN_SECCOMP_CFG "/run/firejail/mnt/seccomp" // configured filter |
@@ -207,6 +208,7 @@ typedef struct config_t { | |||
207 | char *opt_private_keep; // keep list for private opt directory | 208 | char *opt_private_keep; // keep list for private opt directory |
208 | char *srv_private_keep; // keep list for private srv directory | 209 | char *srv_private_keep; // keep list for private srv directory |
209 | char *bin_private_keep; // keep list for private bin directory | 210 | char *bin_private_keep; // keep list for private bin directory |
211 | char *lib_private_keep; // keep list for private bin directory | ||
210 | char *cwd; // current working directory | 212 | char *cwd; // current working directory |
211 | char *overlay_dir; | 213 | char *overlay_dir; |
212 | char *private_template; // template dir for tmpfs home | 214 | char *private_template; // template dir for tmpfs home |
@@ -328,6 +330,7 @@ extern int arg_private_opt; // private opt directory | |||
328 | extern int arg_private_srv; // private srv directory | 330 | extern int arg_private_srv; // private srv directory |
329 | extern int arg_private_bin; // private bin directory | 331 | extern int arg_private_bin; // private bin directory |
330 | extern int arg_private_tmp; // private tmp directory | 332 | extern int arg_private_tmp; // private tmp directory |
333 | extern int arg_private_lib; // private lib directory | ||
331 | extern int arg_scan; // arp-scan all interfaces | 334 | extern int arg_scan; // arp-scan all interfaces |
332 | extern int arg_whitelist; // whitelist commad | 335 | extern int arg_whitelist; // whitelist commad |
333 | extern int arg_nosound; // disable sound | 336 | extern int arg_nosound; // disable sound |
@@ -625,6 +628,9 @@ void pulseaudio_disable(void); | |||
625 | // fs_bin.c | 628 | // fs_bin.c |
626 | void fs_private_bin_list(void); | 629 | void fs_private_bin_list(void); |
627 | 630 | ||
631 | // fs_lib.c | ||
632 | void fs_private_lib(void); | ||
633 | |||
628 | // protocol.c | 634 | // protocol.c |
629 | void protocol_filter_save(void); | 635 | void protocol_filter_save(void); |
630 | void protocol_filter_load(const char *fname); | 636 | void protocol_filter_load(const char *fname); |
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 | } | ||
diff --git a/src/firejail/main.c b/src/firejail/main.c index c055a1537..4ed8e30c9 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -85,6 +85,7 @@ int arg_private_opt = 0; // private opt directory | |||
85 | int arg_private_srv = 0; // private srv directory | 85 | int arg_private_srv = 0; // private srv directory |
86 | int arg_private_bin = 0; // private bin directory | 86 | int arg_private_bin = 0; // private bin directory |
87 | int arg_private_tmp = 0; // private tmp directory | 87 | int arg_private_tmp = 0; // private tmp directory |
88 | int arg_private_lib = 0; // private lib directory | ||
88 | int arg_scan = 0; // arp-scan all interfaces | 89 | int arg_scan = 0; // arp-scan all interfaces |
89 | int arg_whitelist = 0; // whitelist commad | 90 | int arg_whitelist = 0; // whitelist commad |
90 | int arg_nosound = 0; // disable sound | 91 | int arg_nosound = 0; // disable sound |
@@ -1622,6 +1623,15 @@ int main(int argc, char **argv) { | |||
1622 | cfg.bin_private_keep = argv[i] + 14; | 1623 | cfg.bin_private_keep = argv[i] + 14; |
1623 | arg_private_bin = 1; | 1624 | arg_private_bin = 1; |
1624 | } | 1625 | } |
1626 | else if (strncmp(argv[i], "--private-lib=", 14) == 0) { | ||
1627 | // extract private lib list (if any) | ||
1628 | if (cfg.lib_private_keep) { | ||
1629 | if (asprintf(&cfg.lib_private_keep, "%s,%s", cfg.lib_private_keep, argv[i] + 14) < 0 ) | ||
1630 | errExit("asprintf"); | ||
1631 | } else | ||
1632 | cfg.lib_private_keep = argv[i] + 14; | ||
1633 | arg_private_lib = 1; | ||
1634 | } | ||
1625 | else if (strcmp(argv[i], "--private-tmp") == 0) { | 1635 | else if (strcmp(argv[i], "--private-tmp") == 0) { |
1626 | arg_private_tmp = 1; | 1636 | arg_private_tmp = 1; |
1627 | } | 1637 | } |
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 18891ac58..f084edaad 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -849,6 +849,18 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
849 | return 0; | 849 | return 0; |
850 | } | 850 | } |
851 | 851 | ||
852 | // private /lib list of files | ||
853 | if (strncmp(ptr, "private-lib ", 12) == 0) { | ||
854 | if (cfg.lib_private_keep) { | ||
855 | if (asprintf(&cfg.lib_private_keep, "%s,%s", cfg.lib_private_keep, ptr + 12) < 0 ) | ||
856 | errExit("asprintf"); | ||
857 | } else { | ||
858 | cfg.lib_private_keep = ptr + 12; | ||
859 | } | ||
860 | arg_private_lib = 1; | ||
861 | return 0; | ||
862 | } | ||
863 | |||
852 | 864 | ||
853 | #ifdef HAVE_OVERLAYFS | 865 | #ifdef HAVE_OVERLAYFS |
854 | if (strncmp(ptr, "overlay-named ", 14) == 0) { | 866 | if (strncmp(ptr, "overlay-named ", 14) == 0) { |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 55733d5d7..4b30cb991 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -811,6 +811,16 @@ int sandbox(void* sandbox_arg) { | |||
811 | } | 811 | } |
812 | } | 812 | } |
813 | 813 | ||
814 | if (arg_private_lib) { | ||
815 | if (cfg.chrootdir) | ||
816 | fwarning("private-lib feature is disabled in chroot\n"); | ||
817 | else if (arg_overlay) | ||
818 | fwarning("private-lib feature is disabled in overlay\n"); | ||
819 | else { | ||
820 | fs_private_lib(); | ||
821 | } | ||
822 | } | ||
823 | |||
814 | if (arg_private_tmp) { | 824 | if (arg_private_tmp) { |
815 | if (cfg.chrootdir) | 825 | if (cfg.chrootdir) |
816 | fwarning("private-tmp feature is disabled in chroot\n"); | 826 | fwarning("private-tmp feature is disabled in chroot\n"); |
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index cd47800c5..0ce72f845 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -1232,6 +1232,34 @@ $ ls /bin | |||
1232 | bash cat ls sed | 1232 | bash cat ls sed |
1233 | 1233 | ||
1234 | .TP | 1234 | .TP |
1235 | \fB\-\-private-lib=file,file | ||
1236 | Build a new /lib in a temporary filesystem. For command to be executed, | ||
1237 | the shell (if \-\-shell=none is not used), and the listed libraries | ||
1238 | find out dynamic libraries and copy them to the /lib directory. | ||
1239 | If no listed file is found, /lib directory will be empty and no programs will be able to execute. | ||
1240 | The same directory is also bind-mounted over /lib64 and /usr/lib. | ||
1241 | All modifications are discarded when the sandbox is closed. | ||
1242 | .br | ||
1243 | |||
1244 | .br | ||
1245 | Example: | ||
1246 | .br | ||
1247 | $ firejail \-\-noprofile \-\-shell=none \-\-private-lib= \-\-private-bin=ls /bin/ls /lib /bin | ||
1248 | .br | ||
1249 | Parent pid 15733, child pid 15734 | ||
1250 | .br | ||
1251 | Child process initialized in 69.61 ms | ||
1252 | .br | ||
1253 | /bin: | ||
1254 | .br | ||
1255 | ls | ||
1256 | .br | ||
1257 | .br | ||
1258 | /lib: | ||
1259 | .br | ||
1260 | ld-linux-x86-64.so.2 libc.so.6 libdl.so.2 libpcre.so.3 libpthread.so.0 libselinux.so.1 | ||
1261 | |||
1262 | .TP | ||
1235 | \fB\-\-private-dev | 1263 | \fB\-\-private-dev |
1236 | Create a new /dev directory. Only dri, null, full, zero, tty, pts, ptmx, random, snd, urandom, video, log and shm devices are available. | 1264 | Create a new /dev directory. Only dri, null, full, zero, tty, pts, ptmx, random, snd, urandom, video, log and shm devices are available. |
1237 | .br | 1265 | .br |