diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/firejail/fs_lib.c | 89 | ||||
-rw-r--r-- | src/fldd/main.c | 26 |
2 files changed, 97 insertions, 18 deletions
diff --git a/src/firejail/fs_lib.c b/src/firejail/fs_lib.c index cdfd4a6e2..abd7cee1a 100644 --- a/src/firejail/fs_lib.c +++ b/src/firejail/fs_lib.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
23 | #include <sys/types.h> | 23 | #include <sys/types.h> |
24 | #include <unistd.h> | 24 | #include <unistd.h> |
25 | #include <dirent.h> | ||
25 | 26 | ||
26 | #define MAXBUF 4096 | 27 | #define MAXBUF 4096 |
27 | 28 | ||
@@ -133,6 +134,85 @@ static char *valid_file(const char *lib) { | |||
133 | return NULL; | 134 | return NULL; |
134 | } | 135 | } |
135 | 136 | ||
137 | // standard libc libraries based on Debian's libc6 package | ||
138 | // selinux seems to be linked in most command line utilities | ||
139 | // locale (/usr/lib/locale) - without it, the program will default to "C" locale | ||
140 | typedef struct liblist_t { | ||
141 | const char *name; | ||
142 | int len; | ||
143 | } LibList; | ||
144 | |||
145 | static LibList libc_list[] = { | ||
146 | // { "locale", 0 }, hardcoded! | ||
147 | { "libselinux.so.", 0 }, | ||
148 | { "ld-linux-x86-64.so.", 0 }, | ||
149 | { "libanl.so.", 0 }, | ||
150 | { "libc.so.", 0 }, | ||
151 | { "libcidn.so.", 0 }, | ||
152 | { "libcrypt.so.", 0 }, | ||
153 | { "libdl.so.", 0 }, | ||
154 | { "libm.so.", 0 }, | ||
155 | { "libmemusage.so", 0 }, | ||
156 | { "libmvec.so.", 0 }, | ||
157 | { "libnsl.so.", 0 }, | ||
158 | { "libnss_compat.so.", 0 }, | ||
159 | { "libnss_dns.so.", 0 }, | ||
160 | { "libnss_files.so.", 0 }, | ||
161 | { "libnss_hesiod.so.", 0 }, | ||
162 | { "libnss_nisplus.so.", 0 }, | ||
163 | { "libnss_nis.so.", 0 }, | ||
164 | { "libpthread.so.", 0 }, | ||
165 | { "libresolv.so.", 0 }, | ||
166 | { "librt.so.", 0 }, | ||
167 | { "libthread_db.so.", 0 }, | ||
168 | { "libutil.so.", 0 }, | ||
169 | { NULL, 0} | ||
170 | }; | ||
171 | |||
172 | static int find(const char *name) { | ||
173 | assert(name); | ||
174 | |||
175 | int i = 0; | ||
176 | while (libc_list[i].name) { | ||
177 | if (libc_list[i].len == 0) | ||
178 | libc_list[i].len = strlen(libc_list[i].name); | ||
179 | if (strncmp(name, libc_list[i].name, libc_list[i].len) == 0) | ||
180 | return 1; | ||
181 | i++; | ||
182 | } | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | // compare the files in dirname against liblist above | ||
187 | static void walk_directory(const char *dirname, const char *destdir) { | ||
188 | assert(dirname); | ||
189 | assert(destdir); | ||
190 | |||
191 | DIR *dir = opendir(dirname); | ||
192 | if (dir) { | ||
193 | struct dirent *entry; | ||
194 | while ((entry = readdir(dir)) != NULL) { | ||
195 | if (strcmp(entry->d_name, ".") == 0) | ||
196 | continue; | ||
197 | if (strcmp(entry->d_name, "..") == 0) | ||
198 | continue; | ||
199 | |||
200 | if (find(entry->d_name)) { | ||
201 | char *fname; | ||
202 | if (asprintf(&fname, "%s/%s", dirname, entry->d_name) == -1) | ||
203 | errExit("asprintf"); | ||
204 | |||
205 | if (is_dir(fname)) | ||
206 | copy_directory(fname, entry->d_name, RUN_LIB_DIR); | ||
207 | else | ||
208 | duplicate(fname, destdir); | ||
209 | } | ||
210 | } | ||
211 | closedir(dir); | ||
212 | } | ||
213 | else | ||
214 | fprintf(stderr, "Error: cannot open %s in order to set --private-lib\n", dirname); | ||
215 | } | ||
136 | 216 | ||
137 | void fs_private_lib(void) { | 217 | void fs_private_lib(void) { |
138 | #ifndef __x86_64__ | 218 | #ifndef __x86_64__ |
@@ -149,14 +229,13 @@ void fs_private_lib(void) { | |||
149 | // create /run/firejail/mnt/lib directory | 229 | // create /run/firejail/mnt/lib directory |
150 | mkdir_attr(RUN_LIB_DIR, 0755, 0, 0); | 230 | mkdir_attr(RUN_LIB_DIR, 0755, 0, 0); |
151 | 231 | ||
152 | // fix libselinux linking problem on Debian stretch; the library is | ||
153 | // linked in most basic command utilities (ls, cp, find etc.), and it | ||
154 | // seems to have a path hardlinked under /lib/x86_64-linux-gnu directory. | ||
155 | struct stat s; | 232 | struct stat s; |
156 | if (stat("/lib/x86_64-linux-gnu/libselinux.so.1", &s) == 0) { | 233 | if (stat("/lib/x86_64-linux-gnu", &s) == 0) { |
157 | mkdir_attr(RUN_LIB_DIR "/x86_64-linux-gnu", 0755, 0, 0); | 234 | mkdir_attr(RUN_LIB_DIR "/x86_64-linux-gnu", 0755, 0, 0); |
158 | duplicate("/lib/x86_64-linux-gnu/libselinux.so.1", RUN_LIB_DIR "/x86_64-linux-gnu"); | 235 | walk_directory("/lib/x86_64-linux-gnu", RUN_LIB_DIR "/x86_64-linux-gnu"); |
159 | } | 236 | } |
237 | if (stat("/usr/lib/locale", &s) == 0) | ||
238 | copy_directory("/usr/lib/locale", "locale", RUN_LIB_DIR); | ||
160 | 239 | ||
161 | // copy the libs in the new lib directory for the main exe | 240 | // copy the libs in the new lib directory for the main exe |
162 | if (cfg.original_program_index > 0) | 241 | if (cfg.original_program_index > 0) |
diff --git a/src/fldd/main.c b/src/fldd/main.c index 5fda45266..6127a4a87 100644 --- a/src/fldd/main.c +++ b/src/fldd/main.c | |||
@@ -94,12 +94,12 @@ static void storage_print(Storage *ptr, int fd) { | |||
94 | } | 94 | } |
95 | } | 95 | } |
96 | 96 | ||
97 | static bool ptr_ok(const void *ptr, const void *base, const void *end, const char *name) { | 97 | static bool ptr_ok(const void *ptr, const void *base, const void *end, const char *name, const char *exe) { |
98 | bool r; | 98 | bool r; |
99 | 99 | ||
100 | r = (ptr >= base && ptr <= end); | 100 | r = (ptr >= base && ptr <= end); |
101 | if (!r && !arg_quiet) | 101 | if (!r && !arg_quiet) |
102 | fprintf(stderr, "Warning: fldd: bad pointer %s\n", name); | 102 | fprintf(stderr, "Warning: fldd: bad pointer %s for %s\n", name, exe); |
103 | return r; | 103 | return r; |
104 | } | 104 | } |
105 | 105 | ||
@@ -130,11 +130,11 @@ static void copy_libs_for_exe(const char *exe) { | |||
130 | } | 130 | } |
131 | 131 | ||
132 | Elf_Phdr *pbuf = (Elf_Phdr *)(base + sizeof(*ebuf)); | 132 | Elf_Phdr *pbuf = (Elf_Phdr *)(base + sizeof(*ebuf)); |
133 | while (ebuf->e_phnum-- > 0 && ptr_ok(pbuf, base, end, "pbuf")) { | 133 | while (ebuf->e_phnum-- > 0 && ptr_ok(pbuf, base, end, "pbuf", exe)) { |
134 | switch (pbuf->p_type) { | 134 | switch (pbuf->p_type) { |
135 | case PT_INTERP: | 135 | case PT_INTERP: |
136 | // dynamic loader ld-linux.so | 136 | // dynamic loader ld-linux.so |
137 | if (!ptr_ok(base + pbuf->p_offset, base, end, "base + pbuf->p_offset")) | 137 | if (!ptr_ok(base + pbuf->p_offset, base, end, "base + pbuf->p_offset", exe)) |
138 | goto close; | 138 | goto close; |
139 | 139 | ||
140 | storage_add(&libs, base + pbuf->p_offset); | 140 | storage_add(&libs, base + pbuf->p_offset); |
@@ -144,16 +144,16 @@ static void copy_libs_for_exe(const char *exe) { | |||
144 | } | 144 | } |
145 | 145 | ||
146 | Elf_Shdr *sbuf = (Elf_Shdr *)(base + ebuf->e_shoff); | 146 | Elf_Shdr *sbuf = (Elf_Shdr *)(base + ebuf->e_shoff); |
147 | if (!ptr_ok(sbuf, base, end, "sbuf")) | 147 | if (!ptr_ok(sbuf, base, end, "sbuf", exe)) |
148 | goto close; | 148 | goto close; |
149 | 149 | ||
150 | // Find strings section | 150 | // Find strings section |
151 | char *strbase = NULL; | 151 | char *strbase = NULL; |
152 | int sections = ebuf->e_shnum; | 152 | int sections = ebuf->e_shnum; |
153 | while (sections-- > 0 && ptr_ok(sbuf, base, end, "sbuf")) { | 153 | while (sections-- > 0 && ptr_ok(sbuf, base, end, "sbuf", exe)) { |
154 | if (sbuf->sh_type == SHT_STRTAB) { | 154 | if (sbuf->sh_type == SHT_STRTAB) { |
155 | strbase = base + sbuf->sh_offset; | 155 | strbase = base + sbuf->sh_offset; |
156 | if (!ptr_ok(strbase, base, end, "strbase")) | 156 | if (!ptr_ok(strbase, base, end, "strbase", exe)) |
157 | goto close; | 157 | goto close; |
158 | break; | 158 | break; |
159 | } | 159 | } |
@@ -164,7 +164,7 @@ static void copy_libs_for_exe(const char *exe) { | |||
164 | 164 | ||
165 | // Find dynamic section | 165 | // Find dynamic section |
166 | sections = ebuf->e_shnum; | 166 | sections = ebuf->e_shnum; |
167 | while (sections-- > 0 && ptr_ok(sbuf, base, end, "sbuf")) { | 167 | while (sections-- > 0 && ptr_ok(sbuf, base, end, "sbuf", exe)) { |
168 | // TODO: running fldd on large gui programs (fldd /usr/bin/transmission-qt) | 168 | // TODO: running fldd on large gui programs (fldd /usr/bin/transmission-qt) |
169 | // crash on accessing memory location sbuf->sh_type if sbuf->sh_type in the previous section was 0 (SHT_NULL) | 169 | // crash on accessing memory location sbuf->sh_type if sbuf->sh_type in the previous section was 0 (SHT_NULL) |
170 | // for now we just exit the while loop - this is probably incorrect | 170 | // for now we just exit the while loop - this is probably incorrect |
@@ -173,14 +173,14 @@ static void copy_libs_for_exe(const char *exe) { | |||
173 | break; | 173 | break; |
174 | if (sbuf->sh_type == SHT_DYNAMIC) { | 174 | if (sbuf->sh_type == SHT_DYNAMIC) { |
175 | Elf_Dyn *dbuf = (Elf_Dyn *)(base + sbuf->sh_offset); | 175 | Elf_Dyn *dbuf = (Elf_Dyn *)(base + sbuf->sh_offset); |
176 | if (!ptr_ok(dbuf, base, end, "dbuf")) | 176 | if (!ptr_ok(dbuf, base, end, "dbuf", exe)) |
177 | goto close; | 177 | goto close; |
178 | // Find DT_RPATH/DT_RUNPATH tags first | 178 | // Find DT_RPATH/DT_RUNPATH tags first |
179 | unsigned long size = sbuf->sh_size; | 179 | unsigned long size = sbuf->sh_size; |
180 | while (size >= sizeof(*dbuf) && ptr_ok(dbuf, base, end, "dbuf")) { | 180 | while (size >= sizeof(*dbuf) && ptr_ok(dbuf, base, end, "dbuf", exe)) { |
181 | if (dbuf->d_tag == DT_RPATH || dbuf->d_tag == DT_RUNPATH) { | 181 | if (dbuf->d_tag == DT_RPATH || dbuf->d_tag == DT_RUNPATH) { |
182 | const char *searchpath = strbase + dbuf->d_un.d_ptr; | 182 | const char *searchpath = strbase + dbuf->d_un.d_ptr; |
183 | if (!ptr_ok(searchpath, base, end, "searchpath")) | 183 | if (!ptr_ok(searchpath, base, end, "searchpath", exe)) |
184 | goto close; | 184 | goto close; |
185 | storage_add(&lib_paths, searchpath); | 185 | storage_add(&lib_paths, searchpath); |
186 | } | 186 | } |
@@ -190,10 +190,10 @@ static void copy_libs_for_exe(const char *exe) { | |||
190 | // Find DT_NEEDED tags | 190 | // Find DT_NEEDED tags |
191 | dbuf = (Elf_Dyn *)(base + sbuf->sh_offset); | 191 | dbuf = (Elf_Dyn *)(base + sbuf->sh_offset); |
192 | size = sbuf->sh_size; | 192 | size = sbuf->sh_size; |
193 | while (size >= sizeof(*dbuf) && ptr_ok(dbuf, base, end, "dbuf")) { | 193 | while (size >= sizeof(*dbuf) && ptr_ok(dbuf, base, end, "dbuf", exe)) { |
194 | if (dbuf->d_tag == DT_NEEDED) { | 194 | if (dbuf->d_tag == DT_NEEDED) { |
195 | const char *lib = strbase + dbuf->d_un.d_ptr; | 195 | const char *lib = strbase + dbuf->d_un.d_ptr; |
196 | if (!ptr_ok(lib, base, end, "lib")) | 196 | if (!ptr_ok(lib, base, end, "lib", exe)) |
197 | goto close; | 197 | goto close; |
198 | copy_libs_for_lib(lib); | 198 | copy_libs_for_lib(lib); |
199 | } | 199 | } |