aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/fs_lib.c
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/firejail/fs_lib.c
parentmerges (diff)
downloadfirejail-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.c203
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
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}