diff options
author | smitsohu <smitsohu@gmail.com> | 2021-10-22 22:00:16 +0200 |
---|---|---|
committer | smitsohu <smitsohu@gmail.com> | 2021-10-22 23:09:35 +0200 |
commit | 7f0b5ddd8881c5276138b061109ab48eb5165201 (patch) | |
tree | a9de3ae0d5e9cd853a725dc2b8306de9895865d9 | |
parent | README update (diff) | |
download | firejail-7f0b5ddd8881c5276138b061109ab48eb5165201.tar.gz firejail-7f0b5ddd8881c5276138b061109ab48eb5165201.tar.zst firejail-7f0b5ddd8881c5276138b061109ab48eb5165201.zip |
private-bin: fix #4626, refactor symlink detection
-rw-r--r-- | src/firejail/firejail.h | 2 | ||||
-rw-r--r-- | src/firejail/fs_bin.c | 35 | ||||
-rw-r--r-- | src/firejail/fs_lib.c | 43 | ||||
-rw-r--r-- | src/firejail/run_symlink.c | 1 |
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); | |||
709 | void fs_private_bin_list(void); | 709 | void fs_private_bin_list(void); |
710 | 710 | ||
711 | // fs_lib.c | 711 | // fs_lib.c |
712 | int is_firejail_link(const char *fname); | ||
713 | char *find_in_path(const char *program); | ||
712 | void fs_private_lib(void); | 714 | void 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[] = { | |||
43 | static char *check_dir_or_file(const char *name) { | 43 | static 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 | ||
65 | int 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 | |||
64 | char *find_in_path(const char *program) { | 85 | char *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 | ||
25 | extern char *find_in_path(const char *program); | ||
26 | 25 | ||
27 | void run_symlink(int argc, char **argv, int run_as_is) { | 26 | void run_symlink(int argc, char **argv, int run_as_is) { |
28 | EUID_ASSERT(); | 27 | EUID_ASSERT(); |