diff options
-rw-r--r-- | src/firejail/firejail.h | 6 | ||||
-rw-r--r-- | src/firejail/ls.c | 184 | ||||
-rw-r--r-- | src/firejail/main.c | 27 | ||||
-rwxr-xr-x | test/features/3.5.exp | 3 |
4 files changed, 166 insertions, 54 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 9c4dcc9a6..99705f0e6 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -532,8 +532,10 @@ int x11_display(void); | |||
532 | int x11_check_xpra(void); | 532 | int x11_check_xpra(void); |
533 | 533 | ||
534 | // ls.c | 534 | // ls.c |
535 | void ls_name(const char *name, const char *path); | 535 | #define SANDBOX_FS_LS 0 |
536 | void ls(pid_t pid, const char *path); | 536 | #define SANDBOX_FS_GET 1 |
537 | void sandboxfs_name(int op, const char *name, const char *path); | ||
538 | void sandboxfs(int op, pid_t pid, const char *path); | ||
537 | 539 | ||
538 | #endif | 540 | #endif |
539 | 541 | ||
diff --git a/src/firejail/ls.c b/src/firejail/ls.c index fe6348312..6a8d6acbd 100644 --- a/src/firejail/ls.c +++ b/src/firejail/ls.c | |||
@@ -184,7 +184,7 @@ static void print_directory(const char *path) { | |||
184 | free(namelist); | 184 | free(namelist); |
185 | } | 185 | } |
186 | 186 | ||
187 | void ls_name(const char *name, const char *path) { | 187 | void sandboxfs_name(int op, const char *name, const char *path) { |
188 | EUID_ASSERT(); | 188 | EUID_ASSERT(); |
189 | 189 | ||
190 | if (!name || strlen(name) == 0) { | 190 | if (!name || strlen(name) == 0) { |
@@ -197,10 +197,10 @@ void ls_name(const char *name, const char *path) { | |||
197 | exit(1); | 197 | exit(1); |
198 | } | 198 | } |
199 | 199 | ||
200 | ls(pid, path); | 200 | sandboxfs(op, pid, path); |
201 | } | 201 | } |
202 | 202 | ||
203 | void ls(pid_t pid, const char *path) { | 203 | void sandboxfs(int op, pid_t pid, const char *path) { |
204 | EUID_ASSERT(); | 204 | EUID_ASSERT(); |
205 | 205 | ||
206 | // if the pid is that of a firejail process, use the pid of the first child process | 206 | // if the pid is that of a firejail process, use the pid of the first child process |
@@ -225,16 +225,6 @@ void ls(pid_t pid, const char *path) { | |||
225 | } | 225 | } |
226 | } | 226 | } |
227 | 227 | ||
228 | EUID_ROOT(); | ||
229 | // chroot | ||
230 | char *rootdir; | ||
231 | if (asprintf(&rootdir, "/proc/%d/root", pid) == -1) | ||
232 | errExit("asprintf"); | ||
233 | if (chroot(rootdir) < 0) | ||
234 | errExit("chroot"); | ||
235 | if (chdir("/") < 0) | ||
236 | errExit("chdir"); | ||
237 | |||
238 | // full path or file in current directory? | 228 | // full path or file in current directory? |
239 | char *fname; | 229 | char *fname; |
240 | if (*path == '/') { | 230 | if (*path == '/') { |
@@ -251,55 +241,151 @@ void ls(pid_t pid, const char *path) { | |||
251 | exit(1); | 241 | exit(1); |
252 | } | 242 | } |
253 | 243 | ||
254 | // access chek is performed with the real UID | 244 | // sandbox root directory |
255 | if (access(fname, R_OK) == -1) { | 245 | char *rootdir; |
256 | fprintf(stderr, "Error: Cannot access file %s\n", fname); | 246 | if (asprintf(&rootdir, "/proc/%d/root", pid) == -1) |
257 | exit(1); | 247 | errExit("asprintf"); |
258 | } | ||
259 | 248 | ||
260 | // list directory contents | 249 | if (op == SANDBOX_FS_LS) { |
261 | struct stat s; | 250 | EUID_ROOT(); |
262 | if (stat(fname, &s) == -1) { | 251 | // chroot |
263 | fprintf(stderr, "Error: Cannot access file %s\n", fname); | 252 | if (chroot(rootdir) < 0) |
264 | exit(1); | 253 | errExit("chroot"); |
254 | if (chdir("/") < 0) | ||
255 | errExit("chdir"); | ||
256 | |||
257 | // access chek is performed with the real UID | ||
258 | if (access(fname, R_OK) == -1) { | ||
259 | fprintf(stderr, "Error: Cannot access file %s\n", fname); | ||
260 | exit(1); | ||
261 | } | ||
262 | |||
263 | // list directory contents | ||
264 | struct stat s; | ||
265 | if (stat(fname, &s) == -1) { | ||
266 | fprintf(stderr, "Error: Cannot access file %s\n", fname); | ||
267 | exit(1); | ||
268 | } | ||
269 | if (S_ISDIR(s.st_mode)) { | ||
270 | char *rp = realpath(fname, NULL); | ||
271 | if (!rp) { | ||
272 | fprintf(stderr, "Error: Cannot access file %s\n", fname); | ||
273 | exit(1); | ||
274 | } | ||
275 | if (arg_debug) | ||
276 | printf("realpath %s\n", rp); | ||
277 | |||
278 | char *dir; | ||
279 | if (asprintf(&dir, "%s/", rp) == -1) | ||
280 | errExit("asprintf"); | ||
281 | |||
282 | print_directory(dir); | ||
283 | free(rp); | ||
284 | free(dir); | ||
285 | } | ||
286 | else { | ||
287 | char *rp = realpath(fname, NULL); | ||
288 | if (!rp) { | ||
289 | fprintf(stderr, "Error: Cannot access file %s\n", fname); | ||
290 | exit(1); | ||
291 | } | ||
292 | if (arg_debug) | ||
293 | printf("realpath %s\n", rp); | ||
294 | char *split = strrchr(rp, '/'); | ||
295 | if (split) { | ||
296 | *split = '\0'; | ||
297 | char *rp2 = split + 1; | ||
298 | if (arg_debug) | ||
299 | printf("path %s, file %s\n", rp, rp2); | ||
300 | print_file_or_dir(rp, rp2, 1); | ||
301 | } | ||
302 | free(rp); | ||
303 | } | ||
265 | } | 304 | } |
266 | if (S_ISDIR(s.st_mode)) { | 305 | |
267 | char *rp = realpath(fname, NULL); | 306 | // get file from sandbox |
268 | if (!rp) { | 307 | else if (op == SANDBOX_FS_GET) { |
308 | // check source file (sandbox) | ||
309 | char *src_fname; | ||
310 | if (asprintf(&src_fname, "%s%s", rootdir, fname) == -1) | ||
311 | errExit("asprintf"); | ||
312 | EUID_ROOT(); | ||
313 | struct stat s; | ||
314 | if (stat(src_fname, &s) == -1) { | ||
269 | fprintf(stderr, "Error: Cannot access file %s\n", fname); | 315 | fprintf(stderr, "Error: Cannot access file %s\n", fname); |
270 | exit(1); | 316 | exit(1); |
271 | } | 317 | } |
272 | if (arg_debug) | 318 | |
273 | printf("realpath %s\n", rp); | 319 | |
320 | // try to open the source file - we need to chroot | ||
321 | pid_t child = fork(); | ||
322 | if (child < 0) | ||
323 | errExit("fork"); | ||
324 | if (child == 0) { | ||
325 | // chroot | ||
326 | if (chroot(rootdir) < 0) | ||
327 | errExit("chroot"); | ||
328 | if (chdir("/") < 0) | ||
329 | errExit("chdir"); | ||
330 | |||
331 | // drop privileges | ||
332 | drop_privs(0); | ||
333 | |||
334 | // try to read the file | ||
335 | if (access(fname, R_OK) == -1) { | ||
336 | fprintf(stderr, "Error: Cannot read file %s\n", fname); | ||
337 | exit(1); | ||
338 | } | ||
339 | exit(0); | ||
340 | } | ||
274 | 341 | ||
275 | char *dir; | 342 | // wait for the child to finish |
276 | if (asprintf(&dir, "%s/", rp) == -1) | 343 | int status = NULL; |
277 | errExit("asprintf"); | 344 | waitpid(child, &status, 0); |
345 | if (WIFEXITED(status) && WEXITSTATUS(status) == 0); | ||
346 | else | ||
347 | exit(1); | ||
348 | EUID_USER(); | ||
278 | 349 | ||
279 | print_directory(dir); | 350 | // check destination file (host) |
280 | free(rp); | 351 | char *dest_fname = strrchr(fname, '/'); |
281 | free(dir); | 352 | if (!dest_fname || *(++dest_fname) == '\0') { |
282 | } | 353 | fprintf(stderr, "Error: invalid file name %s\n", fname); |
283 | else { | ||
284 | char *rp = realpath(fname, NULL); | ||
285 | if (!rp) { | ||
286 | fprintf(stderr, "Error: Cannot access file %s\n", fname); | ||
287 | exit(1); | 354 | exit(1); |
288 | } | 355 | } |
289 | if (arg_debug) | 356 | |
290 | printf("realpath %s\n", rp); | 357 | if (access(dest_fname, F_OK) == -1) { |
291 | char *split = strrchr(rp, '/'); | 358 | // try to create the file |
292 | if (split) { | 359 | FILE *fp = fopen(dest_fname, "w"); |
293 | *split = '\0'; | 360 | if (!fp) { |
294 | char *rp2 = split + 1; | 361 | fprintf(stderr, "Error: cannot create %s file\n", dest_fname); |
295 | if (arg_debug) | 362 | exit(1); |
296 | printf("path %s, file %s\n", rp, rp2); | 363 | } |
297 | print_file_or_dir(rp, rp2, 1); | 364 | fclose(fp); |
298 | } | 365 | } |
299 | free(rp); | 366 | else { |
367 | if (access(dest_fname, W_OK) == -1) { | ||
368 | fprintf(stderr, "Error: cannot writee %s file\n", dest_fname); | ||
369 | exit(1); | ||
370 | } | ||
371 | } | ||
372 | // copy file | ||
373 | EUID_ROOT(); | ||
374 | copy_file(src_fname, dest_fname); | ||
375 | if (chown(dest_fname, getuid(), getgid()) == -1) | ||
376 | errExit("chown"); | ||
377 | if (chmod(dest_fname, 0644) == -1) | ||
378 | errExit("chmod"); | ||
379 | EUID_USER(); | ||
300 | } | 380 | } |
381 | |||
382 | // put file in sandbox | ||
383 | else if (op == SANDBOX_FS_LS) { | ||
384 | printf("todo!\n"); | ||
385 | } | ||
301 | 386 | ||
302 | free(fname); | 387 | free(fname); |
388 | free(rootdir); | ||
303 | 389 | ||
304 | exit(0); | 390 | exit(0); |
305 | } | 391 | } |
diff --git a/src/firejail/main.c b/src/firejail/main.c index eebb04fcc..2c6b5a5e1 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -426,6 +426,29 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { | |||
426 | exit(0); | 426 | exit(0); |
427 | } | 427 | } |
428 | #endif | 428 | #endif |
429 | else if (strncmp(argv[i], "--get=", 6) == 0) { | ||
430 | logargs(argc, argv); | ||
431 | |||
432 | // verify path | ||
433 | if ((i + 2) != argc) { | ||
434 | fprintf(stderr, "Error: invalid --get option, path expected\n"); | ||
435 | exit(1); | ||
436 | } | ||
437 | char *path = argv[i + 1]; | ||
438 | invalid_filename(path); | ||
439 | if (strstr(path, "..")) { | ||
440 | fprintf(stderr, "Error: invalid file name %s\n", path); | ||
441 | exit(1); | ||
442 | } | ||
443 | |||
444 | // get file | ||
445 | pid_t pid; | ||
446 | if (read_pid(argv[i] + 6, &pid) == 0) | ||
447 | sandboxfs(SANDBOX_FS_GET, pid, path); | ||
448 | else | ||
449 | sandboxfs_name(SANDBOX_FS_GET, argv[i] + 6, path); | ||
450 | exit(0); | ||
451 | } | ||
429 | else if (strncmp(argv[i], "--ls=", 5) == 0) { | 452 | else if (strncmp(argv[i], "--ls=", 5) == 0) { |
430 | logargs(argc, argv); | 453 | logargs(argc, argv); |
431 | 454 | ||
@@ -444,9 +467,9 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { | |||
444 | // list directory contents | 467 | // list directory contents |
445 | pid_t pid; | 468 | pid_t pid; |
446 | if (read_pid(argv[i] + 5, &pid) == 0) | 469 | if (read_pid(argv[i] + 5, &pid) == 0) |
447 | ls(pid, path); | 470 | sandboxfs(SANDBOX_FS_LS, pid, path); |
448 | else | 471 | else |
449 | ls_name(argv[i] + 5, path); | 472 | sandboxfs_name(SANDBOX_FS_LS, argv[i] + 5, path); |
450 | exit(0); | 473 | exit(0); |
451 | } | 474 | } |
452 | else if (strncmp(argv[i], "--join=", 7) == 0) { | 475 | else if (strncmp(argv[i], "--join=", 7) == 0) { |
diff --git a/test/features/3.5.exp b/test/features/3.5.exp index dfa8fae10..b1a16830d 100755 --- a/test/features/3.5.exp +++ b/test/features/3.5.exp | |||
@@ -44,7 +44,8 @@ if { $overlay == "overlay" } { | |||
44 | send -- "ls -l /dev | wc -l\r" | 44 | send -- "ls -l /dev | wc -l\r" |
45 | expect { | 45 | expect { |
46 | timeout {puts "TESTING ERROR 3.1\n";exit} | 46 | timeout {puts "TESTING ERROR 3.1\n";exit} |
47 | "11" | 47 | "12" { puts "Debian\n"} |
48 | "11" { puts "Centos\n"} | ||
48 | } | 49 | } |
49 | 50 | ||
50 | after 100 | 51 | after 100 |