diff options
Diffstat (limited to 'src/firejail/fs_home.c')
-rw-r--r-- | src/firejail/fs_home.c | 67 |
1 files changed, 35 insertions, 32 deletions
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index d8cd9ce4d..1612da5d3 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c | |||
@@ -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) |
@@ -351,11 +345,9 @@ void fs_check_private_dir(void) { | |||
351 | //*********************************************************************************** | 345 | //*********************************************************************************** |
352 | static char *check_dir_or_file(const char *name) { | 346 | static char *check_dir_or_file(const char *name) { |
353 | assert(name); | 347 | assert(name); |
354 | struct stat s; | ||
355 | 348 | ||
356 | // basic checks | 349 | // basic checks |
357 | invalid_filename(name); | 350 | invalid_filename(name); |
358 | |||
359 | if (arg_debug) | 351 | if (arg_debug) |
360 | printf("Private home: checking %s\n", name); | 352 | printf("Private home: checking %s\n", name); |
361 | 353 | ||
@@ -372,28 +364,44 @@ static char *check_dir_or_file(const char *name) { | |||
372 | fname = tmp; | 364 | fname = tmp; |
373 | } | 365 | } |
374 | 366 | ||
375 | // check the file is in user home directory, a full home directory is not allowed | 367 | // we allow only files in user home directory or symbolic links to files or directories owned by the user |
376 | char *rname = realpath(fname, NULL); | 368 | struct stat s; |
377 | if (!rname || | 369 | if (lstat(fname, &s) == 0 && S_ISLNK(s.st_mode)) { |
378 | strncmp(rname, cfg.homedir, strlen(cfg.homedir)) != 0 || | 370 | if (stat(fname, &s) == 0) { |
379 | strcmp(rname, cfg.homedir) == 0) { | 371 | if (s.st_uid != getuid()) { |
380 | fprintf(stderr, "Error: invalid file %s\n", name); | 372 | fprintf(stderr, "Error: symbolic link %s to file or directory not owned by the user\n", fname); |
381 | exit(1); | 373 | exit(1); |
374 | } | ||
375 | return fname; | ||
376 | } | ||
377 | else { | ||
378 | fprintf(stderr, "Error: invalid file %s\n", name); | ||
379 | exit(1); | ||
380 | } | ||
382 | } | 381 | } |
383 | 382 | else { | |
384 | // only top files and directories in user home are allowed | 383 | // check the file is in user home directory, a full home directory is not allowed |
385 | char *ptr = rname + strlen(cfg.homedir); | 384 | char *rname = realpath(fname, NULL); |
386 | assert(*ptr != '\0'); | 385 | if (!rname || |
387 | ptr = strchr(++ptr, '/'); | 386 | strncmp(rname, cfg.homedir, strlen(cfg.homedir)) != 0 || |
388 | if (ptr) { | 387 | strcmp(rname, cfg.homedir) == 0) { |
389 | if (*ptr != '\0') { | 388 | fprintf(stderr, "Error: invalid file %s\n", name); |
390 | fprintf(stderr, "Error: only top files and directories in user home are allowed\n"); | ||
391 | exit(1); | 389 | exit(1); |
392 | } | 390 | } |
391 | |||
392 | // only top files and directories in user home are allowed | ||
393 | char *ptr = rname + strlen(cfg.homedir); | ||
394 | assert(*ptr != '\0'); | ||
395 | ptr = strchr(++ptr, '/'); | ||
396 | if (ptr) { | ||
397 | if (*ptr != '\0') { | ||
398 | fprintf(stderr, "Error: only top files and directories in user home are allowed\n"); | ||
399 | exit(1); | ||
400 | } | ||
401 | } | ||
402 | free(fname); | ||
403 | return rname; | ||
393 | } | 404 | } |
394 | |||
395 | free(fname); | ||
396 | return rname; | ||
397 | } | 405 | } |
398 | 406 | ||
399 | static void duplicate(char *name) { | 407 | static void duplicate(char *name) { |
@@ -405,7 +413,7 @@ static void duplicate(char *name) { | |||
405 | assert(strncmp(fname, cfg.homedir, strlen(cfg.homedir)) == 0); | 413 | assert(strncmp(fname, cfg.homedir, strlen(cfg.homedir)) == 0); |
406 | 414 | ||
407 | struct stat s; | 415 | struct stat s; |
408 | if (stat(fname, &s) == -1) { | 416 | if (lstat(fname, &s) == -1) { |
409 | free(fname); | 417 | free(fname); |
410 | return; | 418 | return; |
411 | } | 419 | } |
@@ -445,11 +453,6 @@ void fs_private_home_list(void) { | |||
445 | 453 | ||
446 | uid_t uid = getuid(); | 454 | uid_t uid = getuid(); |
447 | gid_t gid = getgid(); | 455 | gid_t gid = getgid(); |
448 | struct stat s; | ||
449 | if (stat(homedir, &s) == -1) { | ||
450 | fprintf(stderr, "Error: cannot find user home directory\n"); | ||
451 | exit(1); | ||
452 | } | ||
453 | 456 | ||
454 | // create /run/firejail/mnt/home directory | 457 | // create /run/firejail/mnt/home directory |
455 | mkdir_attr(RUN_HOME_DIR, 0755, uid, gid); | 458 | mkdir_attr(RUN_HOME_DIR, 0755, uid, gid); |