aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar valoq <valoq@mailbox.org>2016-11-19 22:12:51 +0100
committerLibravatar valoq <valoq@mailbox.org>2016-11-19 22:12:51 +0100
commit530db20edeee191a3b60d56b3b87999a3d10979e (patch)
tree9053d21580917bdf0e6480b2b2875e90b08b1d8c /src
parentreadme updated (diff)
parentqemu profile (diff)
downloadfirejail-530db20edeee191a3b60d56b3b87999a3d10979e.tar.gz
firejail-530db20edeee191a3b60d56b3b87999a3d10979e.tar.zst
firejail-530db20edeee191a3b60d56b3b87999a3d10979e.zip
fixed readme
Diffstat (limited to 'src')
-rw-r--r--src/fcopy/Makefile.in45
-rw-r--r--src/fcopy/main.c340
-rw-r--r--src/firejail/appimage.c27
-rw-r--r--src/firejail/firejail.h5
-rw-r--r--src/firejail/fs_bin.c171
-rw-r--r--src/firejail/fs_etc.c146
-rw-r--r--src/firejail/fs_home.c315
-rw-r--r--src/firejail/fs_hostname.c28
-rw-r--r--src/firejail/main.c3
-rw-r--r--src/firejail/profile.c3
-rw-r--r--src/firejail/sandbox.c1
-rw-r--r--src/firejail/util.c10
-rw-r--r--src/firemon/caps.c1
-rw-r--r--src/firemon/netstats.c3
-rw-r--r--src/firemon/procevent.c6
-rw-r--r--src/firemon/seccomp.c4
-rw-r--r--src/firemon/top.c3
-rw-r--r--src/fnet/main.c6
-rw-r--r--src/fseccomp/main.c4
-rw-r--r--src/ftee/main.c32
20 files changed, 582 insertions, 571 deletions
diff --git a/src/fcopy/Makefile.in b/src/fcopy/Makefile.in
new file mode 100644
index 000000000..278957a4f
--- /dev/null
+++ b/src/fcopy/Makefile.in
@@ -0,0 +1,45 @@
1all: fcopy
2
3prefix=@prefix@
4exec_prefix=@exec_prefix@
5libdir=@libdir@
6sysconfdir=@sysconfdir@
7
8VERSION=@PACKAGE_VERSION@
9NAME=@PACKAGE_NAME@
10HAVE_SECCOMP_H=@HAVE_SECCOMP_H@
11HAVE_SECCOMP=@HAVE_SECCOMP@
12HAVE_CHROOT=@HAVE_CHROOT@
13HAVE_BIND=@HAVE_BIND@
14HAVE_FATAL_WARNINGS=@HAVE_FATAL_WARNINGS@
15HAVE_NETWORK=@HAVE_NETWORK@
16HAVE_USERNS=@HAVE_USERNS@
17HAVE_X11=@HAVE_X11@
18HAVE_FILE_TRANSFER=@HAVE_FILE_TRANSFER@
19HAVE_WHITELIST=@HAVE_WHITELIST@
20HAVE_GLOBALCFG=@HAVE_GLOBALCFG@
21HAVE_APPARMOR=@HAVE_APPARMOR@
22HAVE_OVERLAYFS=@HAVE_OVERLAYFS@
23HAVE_PRIVATE_HOME=@HAVE_PRIVATE_HOME@
24EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@
25HAVE_GCOV=@HAVE_GCOV@
26EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@
27
28H_FILE_LIST = $(sort $(wildcard *.[h]))
29C_FILE_LIST = $(sort $(wildcard *.c))
30OBJS = $(C_FILE_LIST:.c=.o)
31BINOBJS = $(foreach file, $(OBJS), $file)
32CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' $(HAVE_GCOV) -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_SECCOMP) $(HAVE_GLOBALCFG) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_BIND) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security
33LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread
34
35%.o : %.c $(H_FILE_LIST) ../include/common.h ../include/syscall.h
36 $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
37
38fcopy: $(OBJS)
39 $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(EXTRA_LDFLAGS)
40
41clean:; rm -f *.o fcopy *.gcov *.gcda *.gcno
42
43distclean: clean
44 rm -fr Makefile
45
diff --git a/src/fcopy/main.c b/src/fcopy/main.c
new file mode 100644
index 000000000..b1e2813db
--- /dev/null
+++ b/src/fcopy/main.c
@@ -0,0 +1,340 @@
1/*
2 * Copyright (C) 2014-2016 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
21#include "../include/common.h"
22#include <fcntl.h>
23#include <ftw.h>
24
25
26#define COPY_LIMIT (500 * 1024 *1024)
27static int size_limit_reached = 0;
28static unsigned file_cnt = 0;
29static unsigned size_cnt = 0;
30
31static char *outpath = NULL;
32static char *inpath = NULL;
33
34
35// modified version of the function from util.c
36static void copy_file(const char *srcname, const char *destname, mode_t mode, uid_t uid, gid_t gid) {
37 assert(srcname);
38 assert(destname);
39 mode &= 07777;
40
41 // open source
42 int src = open(srcname, O_RDONLY);
43 if (src < 0) {
44 fprintf(stderr, "Warning: cannot open %s, file not copied\n", srcname);
45 return;
46 }
47
48 // open destination
49 int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC, 0755);
50 if (dst < 0) {
51 fprintf(stderr, "Warning fcopy: cannot open %s, file not copied\n", destname);
52 close(src);
53 return;
54 }
55
56 // copy
57 ssize_t len;
58 static const int BUFLEN = 1024;
59 unsigned char buf[BUFLEN];
60 while ((len = read(src, buf, BUFLEN)) > 0) {
61 int done = 0;
62 while (done != len) {
63 int rv = write(dst, buf + done, len - done);
64 if (rv == -1)
65 goto errexit;
66 done += rv;
67 }
68 }
69 fflush(0);
70
71 if (fchown(dst, uid, gid) == -1)
72 goto errexit;
73 if (fchmod(dst, mode) == -1)
74 goto errexit;
75
76 close(src);
77 close(dst);
78
79 return;
80
81errexit:
82 close(src);
83 close(dst);
84 unlink(destname);
85 fprintf(stderr, "Warning fcopy: cannot copy %s\n", destname);
86}
87
88
89
90// modified version of the function in firejail/util.c
91static void mkdir_attr(const char *fname, mode_t mode, uid_t uid, gid_t gid) {
92 assert(fname);
93 mode &= 07777;
94
95 if (mkdir(fname, mode) == -1 ||
96 chmod(fname, mode) == -1) {
97 fprintf(stderr, "Error fcopy: failed to create %s directory\n", fname);
98 errExit("mkdir/chmod");
99 }
100 if (chown(fname, uid, gid))
101 fprintf(stderr, "Warning fcopy: failed to change ownership of %s\n", fname);
102}
103
104void copy_link(const char *target, const char *linkpath, mode_t mode, uid_t uid, gid_t gid) {
105 (void) mode;
106 (void) uid;
107 (void) gid;
108 char *rp = realpath(target, NULL);
109 if (rp) {
110 if (symlink(rp, linkpath) == -1)
111 goto errout;
112 free(rp);
113 }
114 else
115 goto errout;
116
117 return;
118errout:
119 fprintf(stderr, "Warning fcopy: cannot create symbolic link %s\n", target);
120}
121
122static int first = 1;
123static int fs_copydir(const char *infname, const struct stat *st, int ftype, struct FTW *sftw) {
124 (void) st;
125 (void) sftw;
126 assert(infname);
127 assert(*infname != '\0');
128 assert(outpath);
129 assert(*outpath != '\0');
130 assert(inpath);
131
132 // check size limit
133 if (size_limit_reached)
134 return 0;
135
136
137 char *outfname;
138 if (asprintf(&outfname, "%s%s", outpath, infname + strlen(inpath)) == -1)
139 errExit("asprintf");
140
141//printf("outpaht %s\n", outpath);
142//printf("inpath %s\n", inpath);
143//printf("infname %s\n", infname);
144//printf("outfname %s\n\n", outfname);
145
146 // don't copy it if we already have the file
147 struct stat s;
148 if (stat(outfname, &s) == 0) {
149 if (first)
150 first = 0;
151 else
152 fprintf(stderr, "Warning fcopy: skipping %s, file already present\n", infname);
153 free(outfname);
154 return 0;
155 }
156
157 // extract mode and ownership
158 if (stat(infname, &s) != 0) {
159 fprintf(stderr, "Warning fcopy: skipping %s, cannot find inode\n", infname);
160 free(outfname);
161 return 0;
162 }
163 uid_t uid = s.st_uid;
164 gid_t gid = s.st_gid;
165 mode_t mode = s.st_mode;
166
167 // recalculate size
168 if ((s.st_size + size_cnt) > COPY_LIMIT) {
169 fprintf(stderr, "Error fcopy: size limit of %dMB reached\n", (COPY_LIMIT / 1024) / 1024);
170 size_limit_reached = 1;
171 free(outfname);
172 return 0;
173 }
174
175 file_cnt++;
176 size_cnt += s.st_size;
177
178 if(ftype == FTW_F) {
179 copy_file(infname, outfname, mode, uid, gid);
180 }
181 else if (ftype == FTW_D) {
182 mkdir_attr(outfname, mode, uid, gid);
183 }
184 else if (ftype == FTW_SL) {
185 copy_link(infname, outfname, mode, uid, gid);
186 }
187
188 return(0);
189}
190
191static char *check(const char *src) {
192 struct stat s;
193 char *rsrc = realpath(src, NULL);
194 if (!rsrc || stat(rsrc, &s) == -1)
195 goto errexit;
196
197 // check uid
198 if (s.st_uid != getuid() || s.st_gid != getgid())
199 goto errexit;
200
201 // dir, link, regular file
202 if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode) || S_ISLNK(s.st_mode))
203 return rsrc; // normal exit from the function
204
205errexit:
206 fprintf(stderr, "Error fcopy: invalid file %s\n", src);
207 exit(1);
208}
209
210static void duplicate_dir(const char *src, const char *dest, struct stat *s) {
211 (void) s;
212 char *rsrc = check(src);
213 char *rdest = check(dest);
214 inpath = rsrc;
215 outpath = rdest;
216
217 // walk
218 if(nftw(rsrc, fs_copydir, 1, FTW_PHYS) != 0) {
219 fprintf(stderr, "Error: unable to copy file\n");
220 exit(1);
221 }
222
223 free(rsrc);
224 free(rdest);
225}
226
227static void duplicate_file(const char *src, const char *dest, struct stat *s) {
228 char *rsrc = check(src);
229 char *rdest = check(dest);
230 uid_t uid = s->st_uid;
231 gid_t gid = s->st_gid;
232 mode_t mode = s->st_mode;
233
234 // build destination file name
235 char *name;
236 char *ptr = strrchr(rsrc, '/');
237 ptr++;
238 if (asprintf(&name, "%s/%s", rdest, ptr) == -1)
239 errExit("asprintf");
240
241 // copy
242 copy_file(rsrc, name, mode, uid, gid);
243
244 free(name);
245 free(rsrc);
246 free(rdest);
247}
248
249static void duplicate_link(const char *src, const char *dest, struct stat *s) {
250 char *rsrc = check(src); // we drop the result and use the original name
251 char *rdest = check(dest);
252 uid_t uid = s->st_uid;
253 gid_t gid = s->st_gid;
254 mode_t mode = s->st_mode;
255
256 // build destination file name
257 char *name;
258// char *ptr = strrchr(rsrc, '/');
259 char *ptr = strrchr(src, '/');
260 ptr++;
261 if (asprintf(&name, "%s/%s", rdest, ptr) == -1)
262 errExit("asprintf");
263
264 // copy
265 copy_link(rsrc, name, mode, uid, gid);
266
267 free(name);
268 free(rsrc);
269 free(rdest);
270}
271
272static void usage(void) {
273 printf("Usage: fcopy src dest\n");
274 printf("Copy src file in dest directory. If src is a directory, copy all the files in\n");
275 printf("src recoursively. If the destination directory does not exist, it will be created.\n");
276}
277
278int main(int argc, char **argv) {
279#if 0
280{
281//system("cat /proc/self/status");
282int i;
283for (i = 0; i < argc; i++)
284 printf("*%s* ", argv[i]);
285printf("\n");
286}
287#endif
288 if (argc != 3) {
289 fprintf(stderr, "Error fcopy: files missing\n");
290 usage();
291 exit(1);
292 }
293
294 // check the two files; remove ending /
295 char *src = argv[1];
296 int len = strlen(src);
297 if (src[len - 1] == '/')
298 src[len - 1] = '\0';
299 if (strcspn(src, "\\*&!?\"'<>%^(){}[];,") != (size_t)len) {
300 fprintf(stderr, "Error fcopy: invalid file name %s\n", src);
301 exit(1);
302 }
303
304 char *dest = argv[2];
305 len = strlen(dest);
306 if (dest[len - 1] == '/')
307 dest[len - 1] = '\0';
308 if (strcspn(dest, "\\*&!?\"'<>%^(){}[];,~") != (size_t)len) {
309 fprintf(stderr, "Error fcopy: invalid file name %s\n", dest);
310 exit(1);
311 }
312
313
314 // the destination should be a directory;
315 struct stat s;
316 if (stat(dest, &s) == -1 ||
317 !S_ISDIR(s.st_mode)) {
318 fprintf(stderr, "Error fcopy: invalid destination directory\n");
319 exit(1);
320 }
321
322 // copy files
323 if (lstat(src, &s) == -1) {
324 fprintf(stderr, "Error fcopy: cannot find source file\n");
325 exit(1);
326 }
327
328 if (S_ISDIR(s.st_mode))
329 duplicate_dir(src, dest, &s);
330 else if (S_ISREG(s.st_mode))
331 duplicate_file(src, dest, &s);
332 else if (S_ISLNK(s.st_mode))
333 duplicate_link(src, dest, &s);
334 else {
335 fprintf(stderr, "Error fcopy: source file unsupported\n");
336 exit(1);
337 }
338
339 return 0;
340}
diff --git a/src/firejail/appimage.c b/src/firejail/appimage.c
index a658173eb..6a9ca1679 100644
--- a/src/firejail/appimage.c
+++ b/src/firejail/appimage.c
@@ -31,38 +31,39 @@
31static char *devloop = NULL; // device file 31static char *devloop = NULL; // device file
32static char *mntdir = NULL; // mount point in /tmp directory 32static char *mntdir = NULL; // mount point in /tmp directory
33 33
34const char *appimage_getdir(void) { 34void appimage_set(const char *appimage) {
35 return mntdir; 35 assert(appimage);
36}
37
38void appimage_set(const char *appimage_path) {
39 assert(appimage_path);
40 assert(devloop == NULL); // don't call this twice! 36 assert(devloop == NULL); // don't call this twice!
41 EUID_ASSERT(); 37 EUID_ASSERT();
42 38
43#ifdef LOOP_CTL_GET_FREE // test for older kernels; this definition is found in /usr/include/linux/loop.h 39#ifdef LOOP_CTL_GET_FREE // test for older kernels; this definition is found in /usr/include/linux/loop.h
44 // check appimage_path 40 // check appimage file
45 if (access(appimage_path, R_OK) == -1) { 41 invalid_filename(appimage);
42 if (access(appimage, R_OK) == -1) {
46 fprintf(stderr, "Error: cannot access AppImage file\n"); 43 fprintf(stderr, "Error: cannot access AppImage file\n");
47 exit(1); 44 exit(1);
48 } 45 }
49 46
50 // get appimage type and ELF size 47 // get appimage type and ELF size
51 // a value of 0 means we are dealing with a type1 appimage 48 // a value of 0 means we are dealing with a type1 appimage
52 long unsigned int size = appimage2_size(appimage_path); 49 long unsigned int size = appimage2_size(appimage);
53 if (arg_debug) 50 if (arg_debug)
54 printf("AppImage ELF size %lu\n", size); 51 printf("AppImage ELF size %lu\n", size);
55 52
56 // open as user to prevent race condition 53 // open appimage file
57 int ffd = open(appimage_path, O_RDONLY|O_CLOEXEC); 54 int ffd = open(appimage, O_RDONLY|O_CLOEXEC);
58 if (ffd == -1) { 55 if (ffd == -1) {
59 fprintf(stderr, "Error: /dev/loop-control interface is not supported by your kernel\n"); 56 fprintf(stderr, "Error: cannot open AppImage file\n");
60 exit(1); 57 exit(1);
61 } 58 }
62 59
63 // find or allocate a free loop device to use 60 // find or allocate a free loop device to use
64 EUID_ROOT(); 61 EUID_ROOT();
65 int cfd = open("/dev/loop-control", O_RDWR); 62 int cfd = open("/dev/loop-control", O_RDWR);
63 if (cfd == -1) {
64 fprintf(stderr, "Error: /dev/loop-control interface is not supported by your kernel\n");
65 exit(1);
66 }
66 int devnr = ioctl(cfd, LOOP_CTL_GET_FREE); 67 int devnr = ioctl(cfd, LOOP_CTL_GET_FREE);
67 if (devnr == -1) { 68 if (devnr == -1) {
68 fprintf(stderr, "Error: cannot allocate a new loopback device\n"); 69 fprintf(stderr, "Error: cannot allocate a new loopback device\n");
@@ -117,7 +118,7 @@ void appimage_set(const char *appimage_path) {
117 EUID_USER(); 118 EUID_USER();
118 119
119 // set environment 120 // set environment
120 if (appimage_path && setenv("APPIMAGE", appimage_path, 1) < 0) 121 if (appimage && setenv("APPIMAGE", appimage, 1) < 0)
121 errExit("setenv"); 122 errExit("setenv");
122 if (mntdir && setenv("APPDIR", mntdir, 1) < 0) 123 if (mntdir && setenv("APPDIR", mntdir, 1) < 0)
123 errExit("setenv"); 124 errExit("setenv");
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index d7ba539e6..2562094d3 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -490,8 +490,6 @@ void fs_private_template(void);
490void fs_check_private_dir(void); 490void fs_check_private_dir(void);
491// check new private template home directory (--private-template= option) exit if it fails 491// check new private template home directory (--private-template= option) exit if it fails
492void fs_check_private_template(void); 492void fs_check_private_template(void);
493// check directory list specified by user (--private-home option) - exit if it fails
494void fs_check_home_list(void);
495void fs_private_home_list(void); 493void fs_private_home_list(void);
496 494
497 495
@@ -557,7 +555,6 @@ void network_del_run_file(pid_t pid);
557void network_set_run_file(pid_t pid); 555void network_set_run_file(pid_t pid);
558 556
559// fs_etc.c 557// fs_etc.c
560void fs_check_etc_list(void);
561void fs_private_etc_list(void); 558void fs_private_etc_list(void);
562 559
563// no_sandbox.c 560// no_sandbox.c
@@ -590,7 +587,6 @@ void pulseaudio_init(void);
590void pulseaudio_disable(void); 587void pulseaudio_disable(void);
591 588
592// fs_bin.c 589// fs_bin.c
593void fs_check_bin_list(void);
594void fs_private_bin_list(void); 590void fs_private_bin_list(void);
595 591
596// protocol.c 592// protocol.c
@@ -681,6 +677,7 @@ void build_cmdline(char **command_line, char **window_title, int argc, char **ar
681#define PATH_FNET (LIBDIR "/firejail/fnet") 677#define PATH_FNET (LIBDIR "/firejail/fnet")
682#define PATH_FIREMON (PREFIX "/bin/firemon") 678#define PATH_FIREMON (PREFIX "/bin/firemon")
683#define PATH_FSECCOMP (LIBDIR "/firejail/fseccomp") 679#define PATH_FSECCOMP (LIBDIR "/firejail/fseccomp")
680#define PATH_FCOPY (LIBDIR "/firejail/fcopy")
684// bitmapped filters for sbox_run 681// bitmapped filters for sbox_run
685#define SBOX_ROOT (1 << 0) // run the sandbox as root 682#define SBOX_ROOT (1 << 0) // run the sandbox as root
686#define SBOX_USER (1 << 1) // run the sandbox as a regular user 683#define SBOX_USER (1 << 1) // run the sandbox as a regular user
diff --git a/src/firejail/fs_bin.c b/src/firejail/fs_bin.c
index 6cc1bf3ab..421df717d 100644
--- a/src/firejail/fs_bin.c
+++ b/src/firejail/fs_bin.c
@@ -39,7 +39,6 @@ static char *paths[] = {
39// return 1 if found, 0 if not found 39// return 1 if found, 0 if not found
40static char *check_dir_or_file(const char *name) { 40static char *check_dir_or_file(const char *name) {
41 assert(name); 41 assert(name);
42 invalid_filename(name);
43 42
44 struct stat s; 43 struct stat s;
45 char *fname = NULL; 44 char *fname = NULL;
@@ -94,68 +93,13 @@ static char *check_dir_or_file(const char *name) {
94 return paths[i]; 93 return paths[i];
95} 94}
96 95
97void fs_check_bin_list(void) { 96static void duplicate(char *fname) {
98 EUID_ASSERT(); 97 if (*fname == '~' || *fname == '/' || strstr(fname, "..")) {
99 if (strstr(cfg.bin_private_keep, "..")) { 98 fprintf(stderr, "Error: \"%s\" is an invalid filename\n", fname);
100 fprintf(stderr, "Error: invalid private bin list\n");
101 exit(1); 99 exit(1);
102 } 100 }
103 101 invalid_filename(fname);
104 char *dlist = strdup(cfg.bin_private_keep);
105 if (!dlist)
106 errExit("strdup");
107
108 // create a new list removing files not found
109 char *newlist = malloc(strlen(dlist) + 1 + 1); // +',' + '\0'
110 if (!newlist)
111 errExit("malloc");
112 *newlist = '\0';
113 char *newlistptr = newlist;
114
115 // check the first file
116 char *ptr = strtok(dlist, ",");
117 int notfound = 0;
118 if (check_dir_or_file(ptr)) {
119 // file found, copy the name in the new list
120 strcpy(newlistptr, ptr);
121 strcat(newlistptr, ",");
122 newlistptr += strlen(newlistptr);
123 }
124 else
125 notfound = 1;
126
127 // check the rest of the list
128 while ((ptr = strtok(NULL, ",")) != NULL) {
129 if (check_dir_or_file(ptr)) {
130 // file found, copy the name in the new list
131 strcpy(newlistptr, ptr);
132 strcat(newlistptr, ",");
133 newlistptr += strlen(newlistptr);
134 }
135 else
136 notfound = 1;
137 }
138
139 if (*newlist == '\0') {
140// fprintf(stderr, "Warning: no --private-bin list executable found, option disabled\n");
141// cfg.bin_private_keep = NULL;
142// arg_private_bin = 0;
143 free(newlist);
144 }
145 else {
146 ptr = strrchr(newlist, ',');
147 assert(ptr);
148 *ptr = '\0';
149 if (notfound && !arg_quiet)
150 fprintf(stderr, "Warning: not all executables from --private-bin list were found. The current list is %s\n", newlist);
151
152 cfg.bin_private_keep = newlist;
153 }
154
155 free(dlist);
156}
157 102
158static void duplicate(char *fname) {
159 char *path = check_dir_or_file(fname); 103 char *path = check_dir_or_file(fname);
160 if (!path) 104 if (!path)
161 return; 105 return;
@@ -165,44 +109,9 @@ static void duplicate(char *fname) {
165 if (asprintf(&full_path, "%s/%s", path, fname) == -1) 109 if (asprintf(&full_path, "%s/%s", path, fname) == -1)
166 errExit("asprintf"); 110 errExit("asprintf");
167 111
168 char *actual_path = realpath(full_path, NULL); 112 // copy the file
169 if (actual_path) { 113 sbox_run(SBOX_ROOT| SBOX_SECCOMP, 3, PATH_FCOPY, full_path, RUN_BIN_DIR);
170 // if the file is a symbolic link not under path, make a symbolic link 114 fs_logger2("clone", fname);
171 if (is_link(full_path) && strncmp(actual_path, path, strlen(path))) {
172 char *lnkname;
173 if (asprintf(&lnkname, "%s/%s", RUN_BIN_DIR, fname) == -1)
174 errExit("asprintf");
175 int rv = symlink(actual_path, lnkname);
176 if (rv)
177 fprintf(stderr, "Warning cannot create symbolic link %s\n", lnkname);
178 else if (arg_debug)
179 printf("Created symbolic link %s -> %s\n", lnkname, actual_path);
180 free(lnkname);
181 }
182 else {
183 // copy the file
184 if (arg_debug)
185 printf("running: %s -a %s %s/%s", RUN_CP_COMMAND, actual_path, RUN_BIN_DIR, fname);
186
187 pid_t child = fork();
188 if (child < 0)
189 errExit("fork");
190 if (child == 0) {
191 char *f;
192 if (asprintf(&f, "%s/%s", RUN_BIN_DIR, fname) == -1)
193 errExit("asprintf");
194 clearenv();
195 execlp(RUN_CP_COMMAND, RUN_CP_COMMAND, "-a", actual_path, f, NULL);
196 perror("execlp");
197 _exit(1);
198 }
199 // wait for the child to finish
200 waitpid(child, NULL, 0);
201
202 }
203 free(actual_path);
204 }
205
206 free(full_path); 115 free(full_path);
207} 116}
208 117
@@ -214,42 +123,20 @@ void fs_private_bin_list(void) {
214 // create /run/firejail/mnt/bin directory 123 // create /run/firejail/mnt/bin directory
215 mkdir_attr(RUN_BIN_DIR, 0755, 0, 0); 124 mkdir_attr(RUN_BIN_DIR, 0755, 0, 0);
216 125
217 // copy the list of files in the new etc directory 126 if (arg_debug)
218 // using a new child process without root privileges 127 printf("Copying files in the new bin directory\n");
219 fs_logger_print(); // save the current log
220 pid_t child = fork();
221 if (child < 0)
222 errExit("fork");
223 if (child == 0) {
224 if (arg_debug)
225 printf("Copying files in the new home:\n");
226 128
227 // elevate privileges - files in the new /bin directory belong to root 129 // copy the list of files in the new home directory
228 if (setreuid(0, 0) < 0) 130 char *dlist = strdup(private_list);
229 errExit("setreuid"); 131 if (!dlist)
230 if (setregid(0, 0) < 0) 132 errExit("strdup");
231 errExit("setregid");
232
233 // copy the list of files in the new home directory
234 char *dlist = strdup(private_list);
235 if (!dlist)
236 errExit("strdup");
237
238 133
239 char *ptr = strtok(dlist, ","); 134 char *ptr = strtok(dlist, ",");
135 duplicate(ptr);
136 while ((ptr = strtok(NULL, ",")) != NULL)
240 duplicate(ptr); 137 duplicate(ptr);
241 138 free(dlist);
242 while ((ptr = strtok(NULL, ",")) != NULL)
243 duplicate(ptr);
244 free(dlist);
245 fs_logger_print(); 139 fs_logger_print();
246#ifdef HAVE_GCOV
247 __gcov_flush();
248#endif
249 _exit(0);
250 }
251 // wait for the child to finish
252 waitpid(child, NULL, 0);
253 140
254 // mount-bind 141 // mount-bind
255 int i = 0; 142 int i = 0;
@@ -265,29 +152,5 @@ void fs_private_bin_list(void) {
265 } 152 }
266 i++; 153 i++;
267 } 154 }
268
269 // log cloned files
270 char *dlist = strdup(private_list);
271 if (!dlist)
272 errExit("strdup");
273
274
275 char *ptr = strtok(dlist, ",");
276 while (ptr) {
277 i = 0;
278 while (paths[i]) {
279 struct stat s;
280 if (stat(paths[i], &s) == 0) {
281 char *fname;
282 if (asprintf(&fname, "%s/%s", paths[i], ptr) == -1)
283 errExit("asprintf");
284 fs_logger2("clone", fname);
285 free(fname);
286 }
287 i++;
288 }
289 ptr = strtok(NULL, ",");
290 }
291 free(dlist);
292} 155}
293 156
diff --git a/src/firejail/fs_etc.c b/src/firejail/fs_etc.c
index 7e18840fd..80329d5ba 100644
--- a/src/firejail/fs_etc.c
+++ b/src/firejail/fs_etc.c
@@ -21,20 +21,13 @@
21#include <sys/mount.h> 21#include <sys/mount.h>
22#include <sys/stat.h> 22#include <sys/stat.h>
23#include <sys/types.h> 23#include <sys/types.h>
24#include <sys/wait.h>
25#include <unistd.h> 24#include <unistd.h>
26 25
27// return 0 if file not found, 1 if found 26// return 0 if file not found, 1 if found
28static int check_dir_or_file(const char *name) { 27static int check_dir_or_file(const char *fname) {
29 assert(name); 28 assert(fname);
30 invalid_filename(name);
31 29
32 struct stat s; 30 struct stat s;
33 char *fname;
34 if (asprintf(&fname, "/etc/%s", name) == -1)
35 errExit("asprintf");
36 if (arg_debug)
37 printf("Checking %s\n", fname);
38 if (stat(fname, &s) == -1) { 31 if (stat(fname, &s) == -1) {
39 if (arg_debug) 32 if (arg_debug)
40 printf("Warning: file %s not found.\n", fname); 33 printf("Warning: file %s not found.\n", fname);
@@ -46,78 +39,46 @@ static int check_dir_or_file(const char *name) {
46 goto errexit; 39 goto errexit;
47 40
48 // dir or regular file 41 // dir or regular file
49 if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode)) { 42 if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode) || !is_link(fname))
50 free(fname); 43 return 1; // normal exit
51 return 1;
52 }
53
54 if (!is_link(fname)) {
55 free(fname);
56 return 1;
57 }
58
59 44
60errexit: 45errexit:
61 fprintf(stderr, "Error: invalid file type, %s.\n", fname); 46 fprintf(stderr, "Error: invalid file type, %s.\n", fname);
62 exit(1); 47 exit(1);
63} 48}
64 49
65void fs_check_etc_list(void) { 50static void duplicate(char *fname) {
66 EUID_ASSERT(); 51 if (*fname == '~' || *fname == '/' || strstr(fname, "..")) {
67 if (strstr(cfg.etc_private_keep, "..")) { 52 fprintf(stderr, "Error: \"%s\" is an invalid filename\n", fname);
68 fprintf(stderr, "Error: invalid private etc list\n");
69 exit(1); 53 exit(1);
70 } 54 }
71 55 invalid_filename(fname);
72 char *dlist = strdup(cfg.etc_private_keep); 56
73 if (!dlist) 57 char *src;
74 errExit("strdup"); 58 if (asprintf(&src, "/etc/%s", fname) == -1)
75 59 errExit("asprintf");
76 // build a new list only with the files found 60 if (check_dir_or_file(src) == 0) {
77 char *newlist = malloc(strlen(cfg.etc_private_keep) + 1); 61 if (!arg_quiet)
78 if (!newlist) 62 fprintf(stderr, "Warning: skipping %s for private bin\n", fname);
79 errExit("malloc"); 63 free(src);
80 *newlist = '\0'; 64 return;
81
82 char *ptr = strtok(dlist, ",");
83 if (check_dir_or_file(ptr))
84 strcat(newlist, ptr);
85 while ((ptr = strtok(NULL, ",")) != NULL) {
86 if (check_dir_or_file(ptr)) {
87 strcat(newlist, ",");
88 strcat(newlist, ptr);
89 }
90 } 65 }
91 cfg.etc_private_keep = newlist;
92
93 free(dlist);
94}
95 66
96static void duplicate(char *fname) { 67 struct stat s;
97 // copy the file 68 if (stat(src, &s) == 0 && S_ISDIR(s.st_mode)) {
98 if (arg_debug) 69 // create the directory in RUN_ETC_DIR
99 printf("running: %s -a --parents /etc/%s %s\n", RUN_CP_COMMAND, fname, RUN_MNT_DIR); 70 char *dirname;
100 71 if (asprintf(&dirname, "%s/%s", RUN_ETC_DIR, fname) == -1)
101 pid_t child = fork();
102 if (child < 0)
103 errExit("fork");
104 if (child == 0) {
105 char *f;
106 if (asprintf(&f, "/etc/%s", fname) == -1)
107 errExit("asprintf"); 72 errExit("asprintf");
108 clearenv(); 73 create_empty_dir_as_root(dirname, s.st_mode);
109 execlp(RUN_CP_COMMAND, RUN_CP_COMMAND, "-a", "--parents", f, RUN_MNT_DIR, NULL); 74 sbox_run(SBOX_ROOT| SBOX_SECCOMP, 3, PATH_FCOPY, src, dirname);
110 perror("execlp"); 75 free(dirname);
111 _exit(1);
112 } 76 }
113 // wait for the child to finish 77 else
114 waitpid(child, NULL, 0); 78 sbox_run(SBOX_ROOT| SBOX_SECCOMP, 3, PATH_FCOPY, src, RUN_ETC_DIR);
115 79
116 char *name; 80 fs_logger2("clone", src);
117 if (asprintf(&name, "/etc/%s", fname) == -1) 81 free(src);
118 errExit("asprintf");
119 fs_logger2("clone", name);
120 free(name);
121} 82}
122 83
123 84
@@ -125,12 +86,6 @@ void fs_private_etc_list(void) {
125 char *private_list = cfg.etc_private_keep; 86 char *private_list = cfg.etc_private_keep;
126 assert(private_list); 87 assert(private_list);
127 88
128 struct stat s;
129 if (stat("/etc", &s) == -1) {
130 fprintf(stderr, "Error: cannot find user /etc directory\n");
131 exit(1);
132 }
133
134 // create /run/firejail/mnt/etc directory 89 // create /run/firejail/mnt/etc directory
135 mkdir_attr(RUN_ETC_DIR, 0755, 0, 0); 90 mkdir_attr(RUN_ETC_DIR, 0755, 0, 0);
136 fs_logger("tmpfs /etc"); 91 fs_logger("tmpfs /etc");
@@ -141,39 +96,22 @@ void fs_private_etc_list(void) {
141 // copy the list of files in the new etc directory 96 // copy the list of files in the new etc directory
142 // using a new child process with root privileges 97 // using a new child process with root privileges
143 if (*private_list != '\0') { 98 if (*private_list != '\0') {
144 pid_t child = fork(); 99 if (arg_debug)
145 if (child < 0) 100 printf("Copying files in the new etc directory:\n");
146 errExit("fork"); 101
147 if (child == 0) { 102 // copy the list of files in the new home directory
148 if (arg_debug) 103 char *dlist = strdup(private_list);
149 printf("Copying files in the new etc directory:\n"); 104 if (!dlist)
105 errExit("strdup");
150 106
151 // elevate privileges - files in the new /etc directory belong to root 107
152 if (setreuid(0, 0) < 0) 108 char *ptr = strtok(dlist, ",");
153 errExit("setreuid"); 109 duplicate(ptr);
154 if (setregid(0, 0) < 0)
155 errExit("setregid");
156
157 // copy the list of files in the new home directory
158 char *dlist = strdup(private_list);
159 if (!dlist)
160 errExit("strdup");
161
162 110
163 char *ptr = strtok(dlist, ","); 111 while ((ptr = strtok(NULL, ",")) != NULL)
164 duplicate(ptr); 112 duplicate(ptr);
165 113 free(dlist);
166 while ((ptr = strtok(NULL, ",")) != NULL) 114 fs_logger_print();
167 duplicate(ptr);
168 free(dlist);
169 fs_logger_print();
170#ifdef HAVE_GCOV
171 __gcov_flush();
172#endif
173 _exit(0);
174 }
175 // wait for the child to finish
176 waitpid(child, NULL, 0);
177 } 115 }
178 116
179 if (arg_debug) 117 if (arg_debug)
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c
index 242482d26..1f8da398e 100644
--- a/src/firejail/fs_home.c
+++ b/src/firejail/fs_home.c
@@ -28,7 +28,7 @@
28#include <sys/wait.h> 28#include <sys/wait.h>
29#include <unistd.h> 29#include <unistd.h>
30#include <grp.h> 30#include <grp.h>
31#include <ftw.h> 31//#include <ftw.h>
32 32
33static void skel(const char *homedir, uid_t u, gid_t g) { 33static void skel(const char *homedir, uid_t u, gid_t g) {
34 char *fname; 34 char *fname;
@@ -212,12 +212,6 @@ void fs_private_homedir(void) {
212 212
213 uid_t u = getuid(); 213 uid_t u = getuid();
214 gid_t g = getgid(); 214 gid_t g = getgid();
215 struct stat s;
216 if (stat(homedir, &s) == -1) {
217 fprintf(stderr, "Error: cannot find user home directory\n");
218 exit(1);
219 }
220
221 215
222 // mount bind private_homedir on top of homedir 216 // mount bind private_homedir on top of homedir
223 if (arg_debug) 217 if (arg_debug)
@@ -349,122 +343,17 @@ void fs_check_private_dir(void) {
349//*********************************************************************************** 343//***********************************************************************************
350// --private-home 344// --private-home
351//*********************************************************************************** 345//***********************************************************************************
352#define PRIVATE_COPY_LIMIT (500 * 1024 *1024)
353static int size_limit_reached = 0;
354static unsigned file_cnt = 0;
355static unsigned size_cnt = 0;
356static char *check_dir_or_file(const char *name);
357
358int fs_copydir(const char *path, const struct stat *st, int ftype, struct FTW *sftw) {
359 (void) st;
360 (void) sftw;
361 if (size_limit_reached)
362 return 0;
363
364 struct stat s;
365 char *dest;
366 if (asprintf(&dest, "%s%s", RUN_HOME_DIR, path + strlen(cfg.homedir)) == -1)
367 errExit("asprintf");
368
369 // don't copy it if we already have the file
370 if (stat(dest, &s) == 0) {
371 free(dest);
372 return 0;
373 }
374
375 // extract mode and ownership
376 if (stat(path, &s) != 0) {
377 free(dest);
378 return 0;
379 }
380
381 // check uid
382 if (s.st_uid != firejail_uid || s.st_gid != firejail_gid) {
383 free(dest);
384 return 0;
385 }
386
387 if ((s.st_size + size_cnt) > PRIVATE_COPY_LIMIT) {
388 size_limit_reached = 1;
389 free(dest);
390 return 0;
391 }
392
393 file_cnt++;
394 size_cnt += s.st_size;
395
396 if(ftype == FTW_F)
397 copy_file(path, dest, firejail_uid, firejail_gid, s.st_mode);
398 else if (ftype == FTW_D) {
399 if (mkdir(dest, s.st_mode) == -1)
400 errExit("mkdir");
401 if (set_perms(dest, firejail_uid, firejail_gid, s.st_mode))
402 errExit("set_perms");
403#if 0
404struct stat s2;
405if (stat(dest, &s2) == 0) {
406 printf("%s\t", dest);
407 printf((S_ISDIR(s.st_mode)) ? "d" : "-");
408 printf((s.st_mode & S_IRUSR) ? "r" : "-");
409 printf((s.st_mode & S_IWUSR) ? "w" : "-");
410 printf((s.st_mode & S_IXUSR) ? "x" : "-");
411 printf((s.st_mode & S_IRGRP) ? "r" : "-");
412 printf((s.st_mode & S_IWGRP) ? "w" : "-");
413 printf((s.st_mode & S_IXGRP) ? "x" : "-");
414 printf((s.st_mode & S_IROTH) ? "r" : "-");
415 printf((s.st_mode & S_IWOTH) ? "w" : "-");
416 printf((s.st_mode & S_IXOTH) ? "x" : "-");
417 printf("\n");
418}
419#endif
420
421 fs_logger2("clone", path);
422 }
423
424 free(dest);
425 return(0);
426}
427
428static void duplicate(char *name) {
429 char *fname = check_dir_or_file(name);
430
431 if (arg_debug)
432 printf("Private home: duplicating %s\n", fname);
433 assert(strncmp(fname, cfg.homedir, strlen(cfg.homedir)) == 0);
434
435 struct stat s;
436 if (stat(fname, &s) == -1) {
437 free(fname);
438 return;
439 }
440
441 if(nftw(fname, fs_copydir, 1, FTW_PHYS) != 0) {
442 fprintf(stderr, "Error: unable to copy template dir\n");
443 exit(1);
444 }
445 fs_logger_print(); // save the current log
446
447 free(fname);
448}
449
450
451
452static char *check_dir_or_file(const char *name) { 346static char *check_dir_or_file(const char *name) {
453 assert(name); 347 assert(name);
454 struct stat s;
455 348
456 // basic checks 349 // basic checks
457 invalid_filename(name); 350 invalid_filename(name);
458
459 if (arg_debug) 351 if (arg_debug)
460 printf("Private home: checking %s\n", name); 352 printf("Private home: checking %s\n", name);
461 353
462 // expand home directory 354 // expand home directory
463 char *fname = expand_home(name, cfg.homedir); 355 char *fname = expand_home(name, cfg.homedir);
464 if (!fname) { 356 assert(fname);
465 fprintf(stderr, "Error: file %s not found.\n", name);
466 exit(1);
467 }
468 357
469 // If it doesn't start with '/', it must be relative to homedir 358 // If it doesn't start with '/', it must be relative to homedir
470 if (fname[0] != '/') { 359 if (fname[0] != '/') {
@@ -475,87 +364,77 @@ static char *check_dir_or_file(const char *name) {
475 fname = tmp; 364 fname = tmp;
476 } 365 }
477 366
478 // check the file is in user home directory 367 // we allow only files in user home directory or symbolic links to files or directories owned by the user
479 char *rname = realpath(fname, NULL); 368 struct stat s;
480 if (!rname) { 369 if (lstat(fname, &s) == 0 && S_ISLNK(s.st_mode)) {
481 fprintf(stderr, "Error: invalid file %s\n", name); 370 if (stat(fname, &s) == 0) {
482 exit(1); 371 if (s.st_uid != getuid()) {
483 } 372 fprintf(stderr, "Error: symbolic link %s to file or directory not owned by the user\n", fname);
484 if (strncmp(rname, cfg.homedir, strlen(cfg.homedir)) != 0) { 373 exit(1);
485 fprintf(stderr, "Error: file %s is not in user home directory\n", name); 374 }
486 exit(1); 375 return fname;
487 } 376 }
488 377 else {
489 // a full home directory is not allowed 378 fprintf(stderr, "Error: invalid file %s\n", name);
490 if (strcmp(rname, cfg.homedir) == 0) {
491 fprintf(stderr, "Error: invalid directory %s\n", rname);
492 exit(1);
493 }
494
495 // only top files and directories in user home are allowed
496 char *ptr = rname + strlen(cfg.homedir);
497 if (*ptr == '\0') {
498 fprintf(stderr, "Error: invalid file %s\n", name);
499 exit(1);
500 }
501 ptr++;
502 ptr = strchr(ptr, '/');
503 if (ptr) {
504 if (*ptr != '\0') {
505 fprintf(stderr, "Error: only top files and directories in user home are allowed\n");
506 exit(1); 379 exit(1);
507 } 380 }
508 } 381 }
509 382 else {
510 if (stat(fname, &s) == -1) { 383 // check the file is in user home directory, a full home directory is not allowed
511 fprintf(stderr, "Error: file %s not found.\n", fname); 384 char *rname = realpath(fname, NULL);
512 exit(1); 385 if (!rname ||
513 } 386 strncmp(rname, cfg.homedir, strlen(cfg.homedir)) != 0 ||
514 387 strcmp(rname, cfg.homedir) == 0) {
515 // check uid 388 fprintf(stderr, "Error: invalid file %s\n", name);
516 uid_t uid = getuid(); 389 exit(1);
517 gid_t gid = getgid(); 390 }
518 if (s.st_uid != uid || s.st_gid != gid) { 391
519 fprintf(stderr, "Error: only files or directories created by the current user are allowed.\n"); 392 // only top files and directories in user home are allowed
520 exit(1); 393 char *ptr = rname + strlen(cfg.homedir);
521 } 394 assert(*ptr != '\0');
522 395 ptr = strchr(++ptr, '/');
523 // dir or regular file 396 if (ptr) {
524 if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode)) { 397 if (*ptr != '\0') {
398 fprintf(stderr, "Error: only top files and directories in user home are allowed\n");
399 exit(1);
400 }
401 }
525 free(fname); 402 free(fname);
526 return rname; // regular exit from the function 403 return rname;
527 } 404 }
528
529 fprintf(stderr, "Error: invalid file type, %s.\n", fname);
530 exit(1);
531} 405}
532 406
407static void duplicate(char *name) {
408 char *fname = check_dir_or_file(name);
533 409
534// check directory list specified by user (--private-home option) - exit if it fails 410 if (arg_debug)
535void fs_check_home_list(void) { 411 printf("Private home: duplicating %s\n", fname);
536 if (strstr(cfg.home_private_keep, "..")) { 412 assert(strncmp(fname, cfg.homedir, strlen(cfg.homedir)) == 0);
537 fprintf(stderr, "Error: invalid private-home list\n");
538 exit(1);
539 }
540
541 char *dlist = strdup(cfg.home_private_keep);
542 if (!dlist)
543 errExit("strdup");
544
545 char *ptr = strtok(dlist, ",");
546 char *tmp = check_dir_or_file(ptr);
547 free(tmp);
548 413
549 while ((ptr = strtok(NULL, ",")) != NULL) { 414 struct stat s;
550 tmp = check_dir_or_file(ptr); 415 if (lstat(fname, &s) == -1) {
551 free(tmp); 416 free(fname);
417 return;
418 }
419 else if (S_ISDIR(s.st_mode)) {
420 // create the directory in RUN_HOME_DIR
421 char *name;
422 char *ptr = strrchr(fname, '/');
423 ptr++;
424 if (asprintf(&name, "%s/%s", RUN_HOME_DIR, ptr) == -1)
425 errExit("asprintf");
426 mkdir_attr(name, 0755, getuid(), getgid());
427 sbox_run(SBOX_USER| SBOX_CAPS_NONE | SBOX_SECCOMP, 3, PATH_FCOPY, fname, name);
428 free(name);
552 } 429 }
430 else
431 sbox_run(SBOX_USER| SBOX_CAPS_NONE | SBOX_SECCOMP, 3, PATH_FCOPY, fname, RUN_HOME_DIR);
432 fs_logger2("clone", fname);
433 fs_logger_print(); // save the current log
553 434
554 free(dlist); 435 free(fname);
555} 436}
556 437
557
558
559// private mode (--private-home=list): 438// private mode (--private-home=list):
560// mount homedir on top of /home/user, 439// mount homedir on top of /home/user,
561// tmpfs on top of /root in nonroot mode, 440// tmpfs on top of /root in nonroot mode,
@@ -571,68 +450,28 @@ void fs_private_home_list(void) {
571 int xflag = store_xauthority(); 450 int xflag = store_xauthority();
572 int aflag = store_asoundrc(); 451 int aflag = store_asoundrc();
573 452
574 uid_t u = firejail_uid; 453 uid_t uid = getuid();
575 gid_t g = firejail_gid; 454 gid_t gid = getgid();
576 struct stat s;
577 if (stat(homedir, &s) == -1) {
578 fprintf(stderr, "Error: cannot find user home directory\n");
579 exit(1);
580 }
581 455
582 // create /run/firejail/mnt/home directory 456 // create /run/firejail/mnt/home directory
583 int rv = mkdir(RUN_HOME_DIR, 0755); 457 mkdir_attr(RUN_HOME_DIR, 0755, uid, gid);
584 if (rv == -1)
585 errExit("mkdir");
586 if (set_perms(RUN_HOME_DIR, u, g, 0755))
587 errExit("set_perms");
588 ASSERT_PERMS(RUN_HOME_DIR, u, g, 0755);
589
590 fs_logger_print(); // save the current log 458 fs_logger_print(); // save the current log
591 459
460 if (arg_debug)
461 printf("Copying files in the new home:\n");
462
592 // copy the list of files in the new home directory 463 // copy the list of files in the new home directory
593 // using a new child process without root privileges 464 char *dlist = strdup(cfg.home_private_keep);
594 pid_t child = fork(); 465 if (!dlist)
595 if (child < 0) 466 errExit("strdup");
596 errExit("fork"); 467
597 if (child == 0) { 468 char *ptr = strtok(dlist, ",");
598 if (arg_debug) 469 duplicate(ptr);
599 printf("Copying files in the new home:\n"); 470 while ((ptr = strtok(NULL, ",")) != NULL)
600
601 // drop privileges
602 if (setgroups(0, NULL) < 0)
603 errExit("setgroups");
604 if (setgid(getgid()) < 0)
605 errExit("setgid/getgid");
606 if (setuid(getuid()) < 0)
607 errExit("setuid/getuid");
608
609 // copy the list of files in the new home directory
610 char *dlist = strdup(cfg.home_private_keep);
611 if (!dlist)
612 errExit("strdup");
613
614 char *ptr = strtok(dlist, ",");
615 duplicate(ptr); 471 duplicate(ptr);
616 while ((ptr = strtok(NULL, ",")) != NULL)
617 duplicate(ptr);
618
619 if (!arg_quiet) {
620 if (size_limit_reached)
621 fprintf(stderr, "Warning: private-home copy limit of %u MB reached, not all the files were copied\n",
622 PRIVATE_COPY_LIMIT / (1024 *1024));
623 else
624 printf("Private home: %u files, total size %u bytes\n", file_cnt, size_cnt);
625 }
626 472
627 fs_logger_print(); // save the current log 473 fs_logger_print(); // save the current log
628 free(dlist); 474 free(dlist);
629#ifdef HAVE_GCOV
630 __gcov_flush();
631#endif
632 _exit(0);
633 }
634 // wait for the child to finish
635 waitpid(child, NULL, 0);
636 475
637 if (arg_debug) 476 if (arg_debug)
638 printf("Mount-bind %s on top of %s\n", RUN_HOME_DIR, homedir); 477 printf("Mount-bind %s on top of %s\n", RUN_HOME_DIR, homedir);
@@ -640,7 +479,7 @@ void fs_private_home_list(void) {
640 if (mount(RUN_HOME_DIR, homedir, NULL, MS_BIND|MS_REC, NULL) < 0) 479 if (mount(RUN_HOME_DIR, homedir, NULL, MS_BIND|MS_REC, NULL) < 0)
641 errExit("mount bind"); 480 errExit("mount bind");
642 481
643 if (u != 0) { 482 if (uid != 0) {
644 // mask /root 483 // mask /root
645 if (arg_debug) 484 if (arg_debug)
646 printf("Mounting a new /root directory\n"); 485 printf("Mounting a new /root directory\n");
@@ -655,7 +494,7 @@ void fs_private_home_list(void) {
655 errExit("mounting home directory"); 494 errExit("mounting home directory");
656 } 495 }
657 496
658 skel(homedir, u, g); 497 skel(homedir, uid, gid);
659 if (xflag) 498 if (xflag)
660 copy_xauthority(); 499 copy_xauthority();
661 if (aflag) 500 if (aflag)
diff --git a/src/firejail/fs_hostname.c b/src/firejail/fs_hostname.c
index 04197eb8f..dcf06fc6f 100644
--- a/src/firejail/fs_hostname.c
+++ b/src/firejail/fs_hostname.c
@@ -33,15 +33,7 @@ void fs_hostname(const char *hostname) {
33 if (arg_debug) 33 if (arg_debug)
34 printf("Creating a new /etc/hostname file\n"); 34 printf("Creating a new /etc/hostname file\n");
35 35
36 FILE *fp = fopen(RUN_HOSTNAME_FILE, "w"); 36 create_empty_file_as_root(RUN_HOSTNAME_FILE, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH);
37 if (!fp) {
38 fprintf(stderr, "Error: cannot create %s\n", RUN_HOSTNAME_FILE);
39 exit(1);
40 }
41 fprintf(fp, "%s\n", hostname);
42 // mode and owner
43 SET_PERMS_STREAM(fp, 0, 0, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH);
44 fclose(fp);
45 37
46 // bind-mount the file on top of /etc/hostname 38 // bind-mount the file on top of /etc/hostname
47 if (mount(RUN_HOSTNAME_FILE, "/etc/hostname", NULL, MS_BIND|MS_REC, NULL) < 0) 39 if (mount(RUN_HOSTNAME_FILE, "/etc/hostname", NULL, MS_BIND|MS_REC, NULL) < 0)
@@ -56,15 +48,12 @@ void fs_hostname(const char *hostname) {
56 // copy /etc/host into our new file, and modify it on the fly 48 // copy /etc/host into our new file, and modify it on the fly
57 /* coverity[toctou] */ 49 /* coverity[toctou] */
58 FILE *fp1 = fopen("/etc/hosts", "r"); 50 FILE *fp1 = fopen("/etc/hosts", "r");
59 if (!fp1) { 51 if (!fp1)
60 fprintf(stderr, "Error: cannot open /etc/hosts\n"); 52 goto errexit;
61 exit(1); 53
62 }
63 FILE *fp2 = fopen(RUN_HOSTS_FILE, "w"); 54 FILE *fp2 = fopen(RUN_HOSTS_FILE, "w");
64 if (!fp2) { 55 if (!fp2)
65 fprintf(stderr, "Error: cannot create %s\n", RUN_HOSTS_FILE); 56 goto errexit;
66 exit(1);
67 }
68 57
69 char buf[4096]; 58 char buf[4096];
70 int done = 0; 59 int done = 0;
@@ -92,6 +81,11 @@ void fs_hostname(const char *hostname) {
92 errExit("mount bind /etc/hosts"); 81 errExit("mount bind /etc/hosts");
93 fs_logger("create /etc/hosts"); 82 fs_logger("create /etc/hosts");
94 } 83 }
84 return;
85
86errexit:
87 fprintf(stderr, "Error: cannot create hostname file\n");
88 exit(1);
95} 89}
96 90
97void fs_resolvconf(void) { 91void fs_resolvconf(void) {
diff --git a/src/firejail/main.c b/src/firejail/main.c
index ec0c31285..ff7b762cd 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -1601,7 +1601,6 @@ int main(int argc, char **argv) {
1601 1601
1602 // extract private home dirname 1602 // extract private home dirname
1603 cfg.home_private_keep = argv[i] + 15; 1603 cfg.home_private_keep = argv[i] + 15;
1604 fs_check_home_list();
1605 arg_private = 1; 1604 arg_private = 1;
1606 } 1605 }
1607 else { 1606 else {
@@ -1625,7 +1624,6 @@ int main(int argc, char **argv) {
1625 fprintf(stderr, "Error: invalid private-etc option\n"); 1624 fprintf(stderr, "Error: invalid private-etc option\n");
1626 exit(1); 1625 exit(1);
1627 } 1626 }
1628 fs_check_etc_list();
1629 arg_private_etc = 1; 1627 arg_private_etc = 1;
1630 } 1628 }
1631 else if (strncmp(argv[i], "--private-bin=", 14) == 0) { 1629 else if (strncmp(argv[i], "--private-bin=", 14) == 0) {
@@ -1636,7 +1634,6 @@ int main(int argc, char **argv) {
1636 exit(1); 1634 exit(1);
1637 } 1635 }
1638 arg_private_bin = 1; 1636 arg_private_bin = 1;
1639 fs_check_bin_list();
1640 } 1637 }
1641 else if (strcmp(argv[i], "--private-tmp") == 0) { 1638 else if (strcmp(argv[i], "--private-tmp") == 0) {
1642 arg_private_tmp = 1; 1639 arg_private_tmp = 1;
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index 0fd45d1ef..688fa9609 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -173,7 +173,6 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
173#ifdef HAVE_PRIVATE_HOME 173#ifdef HAVE_PRIVATE_HOME
174 if (checkcfg(CFG_PRIVATE_HOME)) { 174 if (checkcfg(CFG_PRIVATE_HOME)) {
175 cfg.home_private_keep = ptr + 13; 175 cfg.home_private_keep = ptr + 13;
176 fs_check_home_list();
177 arg_private = 1; 176 arg_private = 1;
178 } 177 }
179 else 178 else
@@ -737,7 +736,6 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
737 exit(1); 736 exit(1);
738 } 737 }
739 cfg.etc_private_keep = ptr + 12; 738 cfg.etc_private_keep = ptr + 12;
740 fs_check_etc_list();
741 arg_private_etc = 1; 739 arg_private_etc = 1;
742 740
743 return 0; 741 return 0;
@@ -747,7 +745,6 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
747 if (strncmp(ptr, "private-bin ", 12) == 0) { 745 if (strncmp(ptr, "private-bin ", 12) == 0) {
748 cfg.bin_private_keep = ptr + 12; 746 cfg.bin_private_keep = ptr + 12;
749 arg_private_bin = 1; 747 arg_private_bin = 1;
750 fs_check_bin_list();
751 return 0; 748 return 0;
752 } 749 }
753 750
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index 109daf552..c2e053b0c 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -696,7 +696,6 @@ int sandbox(void* sandbox_arg) {
696 if (asprintf(&tmp, "%s,xauth", cfg.bin_private_keep) == -1) 696 if (asprintf(&tmp, "%s,xauth", cfg.bin_private_keep) == -1)
697 errExit("asprintf"); 697 errExit("asprintf");
698 cfg.bin_private_keep = tmp; 698 cfg.bin_private_keep = tmp;
699 fs_check_bin_list();
700 EUID_ROOT(); 699 EUID_ROOT();
701 } 700 }
702 fs_private_bin_list(); 701 fs_private_bin_list();
diff --git a/src/firejail/util.c b/src/firejail/util.c
index d928c6b42..03f52fabb 100644
--- a/src/firejail/util.c
+++ b/src/firejail/util.c
@@ -206,6 +206,7 @@ int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, m
206 done += rv; 206 done += rv;
207 } 207 }
208 } 208 }
209 fflush(0);
209 210
210 if (fchown(dst, uid, gid) == -1) 211 if (fchown(dst, uid, gid) == -1)
211 errExit("fchown"); 212 errExit("fchown");
@@ -561,7 +562,10 @@ char *expand_home(const char *path, const char* homedir) {
561 return new_name; 562 return new_name;
562 } 563 }
563 564
564 return strdup(path); 565 char *rv = strdup(path);
566 if (!rv)
567 errExit("strdup");
568 return rv;
565} 569}
566 570
567 571
@@ -624,7 +628,7 @@ uid_t pid_get_uid(pid_t pid) {
624 628
625 629
626void invalid_filename(const char *fname) { 630void invalid_filename(const char *fname) {
627 EUID_ASSERT(); 631// EUID_ASSERT();
628 assert(fname); 632 assert(fname);
629 const char *ptr = fname; 633 const char *ptr = fname;
630 634
@@ -690,6 +694,7 @@ void flush_stdin(void) {
690 694
691void create_empty_dir_as_root(const char *dir, mode_t mode) { 695void create_empty_dir_as_root(const char *dir, mode_t mode) {
692 assert(dir); 696 assert(dir);
697 mode &= 07777;
693 struct stat s; 698 struct stat s;
694 699
695 if (stat(dir, &s)) { 700 if (stat(dir, &s)) {
@@ -705,6 +710,7 @@ void create_empty_dir_as_root(const char *dir, mode_t mode) {
705 710
706void create_empty_file_as_root(const char *fname, mode_t mode) { 711void create_empty_file_as_root(const char *fname, mode_t mode) {
707 assert(fname); 712 assert(fname);
713 mode &= 07777;
708 struct stat s; 714 struct stat s;
709 715
710 if (stat(fname, &s)) { 716 if (stat(fname, &s)) {
diff --git a/src/firemon/caps.c b/src/firemon/caps.c
index 81877ab87..3f8a139ae 100644
--- a/src/firemon/caps.c
+++ b/src/firemon/caps.c
@@ -24,7 +24,6 @@ static void print_caps(int pid) {
24 char *file; 24 char *file;
25 if (asprintf(&file, "/proc/%d/status", pid) == -1) { 25 if (asprintf(&file, "/proc/%d/status", pid) == -1) {
26 errExit("asprintf"); 26 errExit("asprintf");
27 exit(1);
28 } 27 }
29 28
30 FILE *fp = fopen(file, "r"); 29 FILE *fp = fopen(file, "r");
diff --git a/src/firemon/netstats.c b/src/firemon/netstats.c
index 3c020d630..534d783cb 100644
--- a/src/firemon/netstats.c
+++ b/src/firemon/netstats.c
@@ -216,6 +216,9 @@ void netstats(void) {
216 print_proc(i, itv, col); 216 print_proc(i, itv, col);
217 } 217 }
218 } 218 }
219#ifdef HAVE_GCOV
220 __gcov_flush();
221#endif
219 } 222 }
220} 223}
221 224
diff --git a/src/firemon/procevent.c b/src/firemon/procevent.c
index 1940f4a34..edae21951 100644
--- a/src/firemon/procevent.c
+++ b/src/firemon/procevent.c
@@ -43,10 +43,8 @@ static int pid_is_firejail(pid_t pid) {
43 43
44 // open /proc/self/comm 44 // open /proc/self/comm
45 char *file; 45 char *file;
46 if (asprintf(&file, "/proc/%u/comm", pid) == -1) { 46 if (asprintf(&file, "/proc/%u/comm", pid) == -1)
47 perror("asprintf"); 47 errExit("asprintf");
48 exit(1);
49 }
50 48
51 FILE *fp = fopen(file, "r"); 49 FILE *fp = fopen(file, "r");
52 if (!fp) { 50 if (!fp) {
diff --git a/src/firemon/seccomp.c b/src/firemon/seccomp.c
index abc698bb8..f11c624ea 100644
--- a/src/firemon/seccomp.c
+++ b/src/firemon/seccomp.c
@@ -22,10 +22,8 @@
22#define MAXBUF 4098 22#define MAXBUF 4098
23static void print_seccomp(int pid) { 23static void print_seccomp(int pid) {
24 char *file; 24 char *file;
25 if (asprintf(&file, "/proc/%d/status", pid) == -1) { 25 if (asprintf(&file, "/proc/%d/status", pid) == -1)
26 errExit("asprintf"); 26 errExit("asprintf");
27 exit(1);
28 }
29 27
30 FILE *fp = fopen(file, "r"); 28 FILE *fp = fopen(file, "r");
31 if (!fp) { 29 if (!fp) {
diff --git a/src/firemon/top.c b/src/firemon/top.c
index b804761dd..94271523c 100644
--- a/src/firemon/top.c
+++ b/src/firemon/top.c
@@ -292,6 +292,9 @@ void top(void) {
292 } 292 }
293 } 293 }
294 head_print(col, row); 294 head_print(col, row);
295#ifdef HAVE_GCOV
296 __gcov_flush();
297#endif
295 } 298 }
296} 299}
297 300
diff --git a/src/fnet/main.c b/src/fnet/main.c
index 4ae9eb6e3..4e7807d07 100644
--- a/src/fnet/main.c
+++ b/src/fnet/main.c
@@ -42,10 +42,10 @@ for (i = 0; i < argc; i++)
42printf("\n"); 42printf("\n");
43} 43}
44#endif 44#endif
45 if (argc < 2) 45 if (argc < 2) {
46 usage();
46 return 1; 47 return 1;
47 48 }
48
49 49
50 if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { 50 if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) {
51 usage(); 51 usage();
diff --git a/src/fseccomp/main.c b/src/fseccomp/main.c
index 39e72fdf9..2f85a786b 100644
--- a/src/fseccomp/main.c
+++ b/src/fseccomp/main.c
@@ -47,8 +47,10 @@ for (i = 0; i < argc; i++)
47printf("\n"); 47printf("\n");
48} 48}
49#endif 49#endif
50 if (argc < 2) 50 if (argc < 2) {
51 usage();
51 return 1; 52 return 1;
53 }
52 54
53 if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { 55 if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) {
54 usage(); 56 usage();
diff --git a/src/ftee/main.c b/src/ftee/main.c
index e6aa5f567..2b27baa5a 100644
--- a/src/ftee/main.c
+++ b/src/ftee/main.c
@@ -179,10 +179,6 @@ static int is_link(const char *fname) {
179 return 0; 179 return 0;
180} 180}
181 181
182
183
184
185
186static void usage(void) { 182static void usage(void) {
187 printf("Usage: ftee filename\n"); 183 printf("Usage: ftee filename\n");
188} 184}
@@ -201,33 +197,25 @@ int main(int argc, char **argv) {
201 197
202 198
203 // do not accept directories, links, and files with ".." 199 // do not accept directories, links, and files with ".."
204 if (strstr(fname, "..") || is_link(fname) || is_dir(fname)) { 200 if (strstr(fname, "..") || is_link(fname) || is_dir(fname))
205 fprintf(stderr, "Error: invalid output file. Links, directories and files with \"..\" are not allowed.\n"); 201 goto errexit;
206 exit(1);
207 }
208 202
209 struct stat s; 203 struct stat s;
210 if (stat(fname, &s) == 0) { 204 if (stat(fname, &s) == 0) {
211 // check permissions 205 // check permissions
212 if (s.st_uid != getuid() || s.st_gid != getgid()) { 206 if (s.st_uid != getuid() || s.st_gid != getgid())
213 fprintf(stderr, "Error: the output file needs to be owned by the current user.\n"); 207 goto errexit;
214 exit(1);
215 }
216 208
217 // check hard links 209 // check hard links
218 if (s.st_nlink != 1) { 210 if (s.st_nlink != 1)
219 fprintf(stderr, "Error: no hard links allowed.\n"); 211 goto errexit;
220 exit(1);
221 }
222 } 212 }
223 213
224 // check if we can append to this file 214 // check if we can append to this file
225 /* coverity[toctou] */ 215 /* coverity[toctou] */
226 FILE *fp = fopen(fname, "a"); 216 FILE *fp = fopen(fname, "a");
227 if (!fp) { 217 if (!fp)
228 fprintf(stderr, "Error: cannot open output file %s\n", fname); 218 goto errexit;
229 exit(1);
230 }
231 fclose(fp); 219 fclose(fp);
232 220
233 221
@@ -248,4 +236,8 @@ int main(int argc, char **argv) {
248 236
249 log_close(); 237 log_close();
250 return 0; 238 return 0;
239
240errexit:
241 fprintf(stderr, "Error ftee: invalid output file.\n");
242 return 1;
251} 243}