diff options
author | valoq <valoq@mailbox.org> | 2016-11-19 22:12:51 +0100 |
---|---|---|
committer | valoq <valoq@mailbox.org> | 2016-11-19 22:12:51 +0100 |
commit | 530db20edeee191a3b60d56b3b87999a3d10979e (patch) | |
tree | 9053d21580917bdf0e6480b2b2875e90b08b1d8c /src | |
parent | readme updated (diff) | |
parent | qemu profile (diff) | |
download | firejail-530db20edeee191a3b60d56b3b87999a3d10979e.tar.gz firejail-530db20edeee191a3b60d56b3b87999a3d10979e.tar.zst firejail-530db20edeee191a3b60d56b3b87999a3d10979e.zip |
fixed readme
Diffstat (limited to 'src')
-rw-r--r-- | src/fcopy/Makefile.in | 45 | ||||
-rw-r--r-- | src/fcopy/main.c | 340 | ||||
-rw-r--r-- | src/firejail/appimage.c | 27 | ||||
-rw-r--r-- | src/firejail/firejail.h | 5 | ||||
-rw-r--r-- | src/firejail/fs_bin.c | 171 | ||||
-rw-r--r-- | src/firejail/fs_etc.c | 146 | ||||
-rw-r--r-- | src/firejail/fs_home.c | 315 | ||||
-rw-r--r-- | src/firejail/fs_hostname.c | 28 | ||||
-rw-r--r-- | src/firejail/main.c | 3 | ||||
-rw-r--r-- | src/firejail/profile.c | 3 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 1 | ||||
-rw-r--r-- | src/firejail/util.c | 10 | ||||
-rw-r--r-- | src/firemon/caps.c | 1 | ||||
-rw-r--r-- | src/firemon/netstats.c | 3 | ||||
-rw-r--r-- | src/firemon/procevent.c | 6 | ||||
-rw-r--r-- | src/firemon/seccomp.c | 4 | ||||
-rw-r--r-- | src/firemon/top.c | 3 | ||||
-rw-r--r-- | src/fnet/main.c | 6 | ||||
-rw-r--r-- | src/fseccomp/main.c | 4 | ||||
-rw-r--r-- | src/ftee/main.c | 32 |
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 @@ | |||
1 | all: fcopy | ||
2 | |||
3 | prefix=@prefix@ | ||
4 | exec_prefix=@exec_prefix@ | ||
5 | libdir=@libdir@ | ||
6 | sysconfdir=@sysconfdir@ | ||
7 | |||
8 | VERSION=@PACKAGE_VERSION@ | ||
9 | NAME=@PACKAGE_NAME@ | ||
10 | HAVE_SECCOMP_H=@HAVE_SECCOMP_H@ | ||
11 | HAVE_SECCOMP=@HAVE_SECCOMP@ | ||
12 | HAVE_CHROOT=@HAVE_CHROOT@ | ||
13 | HAVE_BIND=@HAVE_BIND@ | ||
14 | HAVE_FATAL_WARNINGS=@HAVE_FATAL_WARNINGS@ | ||
15 | HAVE_NETWORK=@HAVE_NETWORK@ | ||
16 | HAVE_USERNS=@HAVE_USERNS@ | ||
17 | HAVE_X11=@HAVE_X11@ | ||
18 | HAVE_FILE_TRANSFER=@HAVE_FILE_TRANSFER@ | ||
19 | HAVE_WHITELIST=@HAVE_WHITELIST@ | ||
20 | HAVE_GLOBALCFG=@HAVE_GLOBALCFG@ | ||
21 | HAVE_APPARMOR=@HAVE_APPARMOR@ | ||
22 | HAVE_OVERLAYFS=@HAVE_OVERLAYFS@ | ||
23 | HAVE_PRIVATE_HOME=@HAVE_PRIVATE_HOME@ | ||
24 | EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@ | ||
25 | HAVE_GCOV=@HAVE_GCOV@ | ||
26 | EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@ | ||
27 | |||
28 | H_FILE_LIST = $(sort $(wildcard *.[h])) | ||
29 | C_FILE_LIST = $(sort $(wildcard *.c)) | ||
30 | OBJS = $(C_FILE_LIST:.c=.o) | ||
31 | BINOBJS = $(foreach file, $(OBJS), $file) | ||
32 | CFLAGS += -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 | ||
33 | LDFLAGS += -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 | |||
38 | fcopy: $(OBJS) | ||
39 | $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(EXTRA_LDFLAGS) | ||
40 | |||
41 | clean:; rm -f *.o fcopy *.gcov *.gcda *.gcno | ||
42 | |||
43 | distclean: 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) | ||
27 | static int size_limit_reached = 0; | ||
28 | static unsigned file_cnt = 0; | ||
29 | static unsigned size_cnt = 0; | ||
30 | |||
31 | static char *outpath = NULL; | ||
32 | static char *inpath = NULL; | ||
33 | |||
34 | |||
35 | // modified version of the function from util.c | ||
36 | static 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 | |||
81 | errexit: | ||
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 | ||
91 | static 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 | |||
104 | void 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; | ||
118 | errout: | ||
119 | fprintf(stderr, "Warning fcopy: cannot create symbolic link %s\n", target); | ||
120 | } | ||
121 | |||
122 | static int first = 1; | ||
123 | static 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 | |||
191 | static 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 | |||
205 | errexit: | ||
206 | fprintf(stderr, "Error fcopy: invalid file %s\n", src); | ||
207 | exit(1); | ||
208 | } | ||
209 | |||
210 | static 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 | |||
227 | static 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 | |||
249 | static 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 | |||
272 | static 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 | |||
278 | int main(int argc, char **argv) { | ||
279 | #if 0 | ||
280 | { | ||
281 | //system("cat /proc/self/status"); | ||
282 | int i; | ||
283 | for (i = 0; i < argc; i++) | ||
284 | printf("*%s* ", argv[i]); | ||
285 | printf("\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 @@ | |||
31 | static char *devloop = NULL; // device file | 31 | static char *devloop = NULL; // device file |
32 | static char *mntdir = NULL; // mount point in /tmp directory | 32 | static char *mntdir = NULL; // mount point in /tmp directory |
33 | 33 | ||
34 | const char *appimage_getdir(void) { | 34 | void appimage_set(const char *appimage) { |
35 | return mntdir; | 35 | assert(appimage); |
36 | } | ||
37 | |||
38 | void 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); | |||
490 | void fs_check_private_dir(void); | 490 | void 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 |
492 | void fs_check_private_template(void); | 492 | void fs_check_private_template(void); |
493 | // check directory list specified by user (--private-home option) - exit if it fails | ||
494 | void fs_check_home_list(void); | ||
495 | void fs_private_home_list(void); | 493 | void fs_private_home_list(void); |
496 | 494 | ||
497 | 495 | ||
@@ -557,7 +555,6 @@ void network_del_run_file(pid_t pid); | |||
557 | void network_set_run_file(pid_t pid); | 555 | void network_set_run_file(pid_t pid); |
558 | 556 | ||
559 | // fs_etc.c | 557 | // fs_etc.c |
560 | void fs_check_etc_list(void); | ||
561 | void fs_private_etc_list(void); | 558 | void fs_private_etc_list(void); |
562 | 559 | ||
563 | // no_sandbox.c | 560 | // no_sandbox.c |
@@ -590,7 +587,6 @@ void pulseaudio_init(void); | |||
590 | void pulseaudio_disable(void); | 587 | void pulseaudio_disable(void); |
591 | 588 | ||
592 | // fs_bin.c | 589 | // fs_bin.c |
593 | void fs_check_bin_list(void); | ||
594 | void fs_private_bin_list(void); | 590 | void 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 |
40 | static char *check_dir_or_file(const char *name) { | 40 | static 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 | ||
97 | void fs_check_bin_list(void) { | 96 | static 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 | ||
158 | static 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 |
28 | static int check_dir_or_file(const char *name) { | 27 | static 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 | ||
60 | errexit: | 45 | errexit: |
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 | ||
65 | void fs_check_etc_list(void) { | 50 | static 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 | ||
96 | static 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 | ||
33 | static void skel(const char *homedir, uid_t u, gid_t g) { | 33 | static 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) | ||
353 | static int size_limit_reached = 0; | ||
354 | static unsigned file_cnt = 0; | ||
355 | static unsigned size_cnt = 0; | ||
356 | static char *check_dir_or_file(const char *name); | ||
357 | |||
358 | int 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 | ||
404 | struct stat s2; | ||
405 | if (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 | |||
428 | static 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 | |||
452 | static char *check_dir_or_file(const char *name) { | 346 | static 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 | ||
407 | static 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) |
535 | void 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 | |||
86 | errexit: | ||
87 | fprintf(stderr, "Error: cannot create hostname file\n"); | ||
88 | exit(1); | ||
95 | } | 89 | } |
96 | 90 | ||
97 | void fs_resolvconf(void) { | 91 | void 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 | ||
626 | void invalid_filename(const char *fname) { | 630 | void 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 | ||
691 | void create_empty_dir_as_root(const char *dir, mode_t mode) { | 695 | void 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 | ||
706 | void create_empty_file_as_root(const char *fname, mode_t mode) { | 711 | void 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 |
23 | static void print_seccomp(int pid) { | 23 | static 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++) | |||
42 | printf("\n"); | 42 | printf("\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++) | |||
47 | printf("\n"); | 47 | printf("\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 | |||
186 | static void usage(void) { | 182 | static 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 | |||
240 | errexit: | ||
241 | fprintf(stderr, "Error ftee: invalid output file.\n"); | ||
242 | return 1; | ||
251 | } | 243 | } |