summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar Topi Miettinen <toiwoton@gmail.com>2017-07-24 11:45:13 +0300
committerLibravatar Topi Miettinen <topimiettinen@users.noreply.github.com>2017-07-30 16:35:17 +0000
commit1da9f74b4dbfe186f893a2f3712135eb00bbed09 (patch)
tree0c4e3a587e5df6f99fbd58d316e1dddb55b5da64 /src
parentmerges (diff)
downloadfirejail-1da9f74b4dbfe186f893a2f3712135eb00bbed09.tar.gz
firejail-1da9f74b4dbfe186f893a2f3712135eb00bbed09.tar.zst
firejail-1da9f74b4dbfe186f893a2f3712135eb00bbed09.zip
Private /lib feature
Diffstat (limited to 'src')
-rw-r--r--src/firejail/firejail.h6
-rw-r--r--src/firejail/fs_lib.c203
-rw-r--r--src/firejail/main.c10
-rw-r--r--src/firejail/profile.c12
-rw-r--r--src/firejail/sandbox.c10
-rw-r--r--src/man/firejail.txt28
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
328extern int arg_private_srv; // private srv directory 330extern int arg_private_srv; // private srv directory
329extern int arg_private_bin; // private bin directory 331extern int arg_private_bin; // private bin directory
330extern int arg_private_tmp; // private tmp directory 332extern int arg_private_tmp; // private tmp directory
333extern int arg_private_lib; // private lib directory
331extern int arg_scan; // arp-scan all interfaces 334extern int arg_scan; // arp-scan all interfaces
332extern int arg_whitelist; // whitelist commad 335extern int arg_whitelist; // whitelist commad
333extern int arg_nosound; // disable sound 336extern int arg_nosound; // disable sound
@@ -625,6 +628,9 @@ void pulseaudio_disable(void);
625// fs_bin.c 628// fs_bin.c
626void fs_private_bin_list(void); 629void fs_private_bin_list(void);
627 630
631// fs_lib.c
632void fs_private_lib(void);
633
628// protocol.c 634// protocol.c
629void protocol_filter_save(void); 635void protocol_filter_save(void);
630void protocol_filter_load(const char *fname); 636void 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
41static 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
52static void copy_libs_for_lib(const char *lib, const char *private_run_dir);
53
54static 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
60static 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
132static 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
156void 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
85int arg_private_srv = 0; // private srv directory 85int arg_private_srv = 0; // private srv directory
86int arg_private_bin = 0; // private bin directory 86int arg_private_bin = 0; // private bin directory
87int arg_private_tmp = 0; // private tmp directory 87int arg_private_tmp = 0; // private tmp directory
88int arg_private_lib = 0; // private lib directory
88int arg_scan = 0; // arp-scan all interfaces 89int arg_scan = 0; // arp-scan all interfaces
89int arg_whitelist = 0; // whitelist commad 90int arg_whitelist = 0; // whitelist commad
90int arg_nosound = 0; // disable sound 91int 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
1232bash cat ls sed 1232bash cat ls sed
1233 1233
1234.TP 1234.TP
1235\fB\-\-private-lib=file,file
1236Build a new /lib in a temporary filesystem. For command to be executed,
1237the shell (if \-\-shell=none is not used), and the listed libraries
1238find out dynamic libraries and copy them to the /lib directory.
1239If no listed file is found, /lib directory will be empty and no programs will be able to execute.
1240The same directory is also bind-mounted over /lib64 and /usr/lib.
1241All modifications are discarded when the sandbox is closed.
1242.br
1243
1244.br
1245Example:
1246.br
1247$ firejail \-\-noprofile \-\-shell=none \-\-private-lib= \-\-private-bin=ls /bin/ls /lib /bin
1248.br
1249Parent pid 15733, child pid 15734
1250.br
1251Child process initialized in 69.61 ms
1252.br
1253/bin:
1254.br
1255ls
1256.br
1257.br
1258/lib:
1259.br
1260ld-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
1236Create a new /dev directory. Only dri, null, full, zero, tty, pts, ptmx, random, snd, urandom, video, log and shm devices are available. 1264Create 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