aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar smitsohu <smitsohu@gmail.com>2021-10-22 22:00:16 +0200
committerLibravatar smitsohu <smitsohu@gmail.com>2021-10-22 23:09:35 +0200
commit7f0b5ddd8881c5276138b061109ab48eb5165201 (patch)
treea9de3ae0d5e9cd853a725dc2b8306de9895865d9
parentREADME update (diff)
downloadfirejail-7f0b5ddd8881c5276138b061109ab48eb5165201.tar.gz
firejail-7f0b5ddd8881c5276138b061109ab48eb5165201.tar.zst
firejail-7f0b5ddd8881c5276138b061109ab48eb5165201.zip
private-bin: fix #4626, refactor symlink detection
-rw-r--r--src/firejail/firejail.h2
-rw-r--r--src/firejail/fs_bin.c35
-rw-r--r--src/firejail/fs_lib.c43
-rw-r--r--src/firejail/run_symlink.c1
4 files changed, 38 insertions, 43 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index a6924b830..ec789cd63 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -709,6 +709,8 @@ void pulseaudio_disable(void);
709void fs_private_bin_list(void); 709void fs_private_bin_list(void);
710 710
711// fs_lib.c 711// fs_lib.c
712int is_firejail_link(const char *fname);
713char *find_in_path(const char *program);
712void fs_private_lib(void); 714void fs_private_lib(void);
713 715
714// protocol.c 716// protocol.c
diff --git a/src/firejail/fs_bin.c b/src/firejail/fs_bin.c
index 61398f12b..d485de05a 100644
--- a/src/firejail/fs_bin.c
+++ b/src/firejail/fs_bin.c
@@ -43,7 +43,6 @@ static char *paths[] = {
43static char *check_dir_or_file(const char *name) { 43static char *check_dir_or_file(const char *name) {
44 assert(name); 44 assert(name);
45 struct stat s; 45 struct stat s;
46 char *fname = NULL;
47 46
48 int i = 0; 47 int i = 0;
49 while (paths[i]) { 48 while (paths[i]) {
@@ -54,45 +53,28 @@ static char *check_dir_or_file(const char *name) {
54 } 53 }
55 54
56 // check file 55 // check file
56 char *fname;
57 if (asprintf(&fname, "%s/%s", paths[i], name) == -1) 57 if (asprintf(&fname, "%s/%s", paths[i], name) == -1)
58 errExit("asprintf"); 58 errExit("asprintf");
59 if (arg_debug) 59 if (arg_debug)
60 printf("Checking %s/%s\n", paths[i], name); 60 printf("Checking %s/%s\n", paths[i], name);
61 if (stat(fname, &s) == 0 && !S_ISDIR(s.st_mode)) { // do not allow directories 61 if (stat(fname, &s) == 0 &&
62 // check symlink to firejail executable in /usr/local/bin 62 !S_ISDIR(s.st_mode) && // do not allow directories
63 if (strcmp(paths[i], "/usr/local/bin") == 0 && is_link(fname)) { 63 !is_firejail_link(fname)) { // skip symlinks to firejail executable, as created by firecfg
64 /* coverity[toctou] */ 64 free(fname);
65 char *actual_path = realpath(fname, NULL); 65 break; // file found
66 if (actual_path) {
67 char *ptr = strstr(actual_path, "/firejail");
68 if (ptr && strlen(ptr) == strlen("/firejail")) {
69 if (arg_debug)
70 printf("firejail exec symlink detected\n");
71 free(actual_path);
72 free(fname);
73 fname = NULL;
74 i++;
75 continue;
76 }
77 free(actual_path);
78 }
79
80 }
81 break; // file found
82 } 66 }
83 67
84 free(fname); 68 free(fname);
85 fname = NULL;
86 i++; 69 i++;
87 } 70 }
88 71
89 if (!fname) { 72 if (!paths[i]) {
90 if (arg_debug) 73 if (arg_debug)
91 fwarning("file %s not found\n", name); 74 fwarning("file %s not found\n", name);
92 return NULL; 75 return NULL;
93 } 76 }
94 77
95 free(fname);
96 return paths[i]; 78 return paths[i];
97} 79}
98 80
@@ -256,6 +238,9 @@ static void globbing(char *fname) {
256 // testing for GLOB_NOCHECK - no pattern matched returns the original pattern 238 // testing for GLOB_NOCHECK - no pattern matched returns the original pattern
257 if (strcmp(globbuf.gl_pathv[j], pattern) == 0) 239 if (strcmp(globbuf.gl_pathv[j], pattern) == 0)
258 continue; 240 continue;
241 // skip symlinks to firejail executable, as created by firecfg
242 if (is_firejail_link(globbuf.gl_pathv[j]))
243 continue;
259 244
260 duplicate(globbuf.gl_pathv[j]); 245 duplicate(globbuf.gl_pathv[j]);
261 } 246 }
diff --git a/src/firejail/fs_lib.c b/src/firejail/fs_lib.c
index 848c186fa..249b41a12 100644
--- a/src/firejail/fs_lib.c
+++ b/src/firejail/fs_lib.c
@@ -61,17 +61,32 @@ static int valid_full_path(const char *full_path) {
61 return 0; 61 return 0;
62} 62}
63 63
64// return 1 if symlink to firejail executable
65int is_firejail_link(const char *fname) {
66 EUID_ASSERT();
67
68 if (!is_link(fname))
69 return 0;
70
71 // char *rp = realpath_as_user(fname, NULL);
72 char *rp = realpath(fname, NULL);
73 if (!rp)
74 return 0;
75
76 int rv = 0;
77 const char *base = gnu_basename(rp);
78 if (strcmp(base, "firejail") == 0)
79 rv = 1;
80
81 free(rp);
82 return rv;
83}
84
64char *find_in_path(const char *program) { 85char *find_in_path(const char *program) {
65 EUID_ASSERT(); 86 EUID_ASSERT();
66 if (arg_debug) 87 if (arg_debug)
67 printf("Searching $PATH for %s\n", program); 88 printf("Searching $PATH for %s\n", program);
68 89
69 char self[MAXBUF];
70 ssize_t len = readlink("/proc/self/exe", self, MAXBUF - 1);
71 if (len < 0)
72 errExit("readlink");
73 self[len] = '\0';
74
75 const char *path = env_get("PATH"); 90 const char *path = env_get("PATH");
76 if (!path) 91 if (!path)
77 return NULL; 92 return NULL;
@@ -88,18 +103,12 @@ char *find_in_path(const char *program) {
88 if (arg_debug) 103 if (arg_debug)
89 printf("trying #%s#\n", fname); 104 printf("trying #%s#\n", fname);
90 struct stat s; 105 struct stat s;
91 if (stat(fname, &s) == 0) { 106 if (stat(fname, &s) == 0 &&
92 // but skip links created by firecfg 107 !is_firejail_link(fname)) { // skip links created by firecfg
93 char *rp = realpath(fname, NULL); 108 free(dup);
94 if (!rp) 109 return fname;
95 errExit("realpath");
96 if (strcmp(self, rp) != 0) {
97 free(rp);
98 free(dup);
99 return fname;
100 }
101 free(rp);
102 } 110 }
111
103 free(fname); 112 free(fname);
104 tok = strtok(NULL, ":"); 113 tok = strtok(NULL, ":");
105 } 114 }
diff --git a/src/firejail/run_symlink.c b/src/firejail/run_symlink.c
index 77fac5438..6397418d1 100644
--- a/src/firejail/run_symlink.c
+++ b/src/firejail/run_symlink.c
@@ -22,7 +22,6 @@
22#include <sys/stat.h> 22#include <sys/stat.h>
23#include <unistd.h> 23#include <unistd.h>
24 24
25extern char *find_in_path(const char *program);
26 25
27void run_symlink(int argc, char **argv, int run_as_is) { 26void run_symlink(int argc, char **argv, int run_as_is) {
28 EUID_ASSERT(); 27 EUID_ASSERT();