aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/paths.c
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2017-02-14 15:00:09 -0500
committerLibravatar netblue30 <netblue30@yahoo.com>2017-02-14 15:00:09 -0500
commitb0cb1b40c3dd23e9584ab6b0686871ab02d298d0 (patch)
tree06ba5597231a26907ccaf944af2632d451d68275 /src/firejail/paths.c
parentmerge #1100 from zackw: removed libconnect (diff)
downloadfirejail-b0cb1b40c3dd23e9584ab6b0686871ab02d298d0.tar.gz
firejail-b0cb1b40c3dd23e9584ab6b0686871ab02d298d0.tar.zst
firejail-b0cb1b40c3dd23e9584ab6b0686871ab02d298d0.zip
merge #1100 from zackw: fix ugly memeory corruption in noblacklist processing
Diffstat (limited to 'src/firejail/paths.c')
-rw-r--r--src/firejail/paths.c191
1 files changed, 121 insertions, 70 deletions
diff --git a/src/firejail/paths.c b/src/firejail/paths.c
index 69c4b359b..454255717 100644
--- a/src/firejail/paths.c
+++ b/src/firejail/paths.c
@@ -18,83 +18,134 @@
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/ 19*/
20#include "firejail.h" 20#include "firejail.h"
21#include <sys/stat.h>
21 22
22static char **paths = NULL; 23static char **paths = 0;
23static int path_cnt = 0; 24static unsigned int path_cnt = 0;
24static char initialized = 0; 25static unsigned int longest_path_elt = 0;
25 26
26static void add_path(const char *path) { 27static void init_paths(void) {
27 assert(paths); 28 char *path = getenv("PATH");
28 assert(path_cnt); 29 char *p;
29 30 if (!path) {
30 // filter out duplicates 31 path = "/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin";
31 int i; 32 setenv("PATH", path, 1);
32 int empty = 0;
33 for (i = 0; i < path_cnt; i++) {
34 if (paths[i] && strcmp(path, paths[i]) == 0) {
35 return;
36 }
37 if (!paths[i]) {
38 empty = i;
39 break;
40 }
41 } 33 }
42 34 path = strdup(path);
43 paths[empty] = strdup(path); 35 if (!path)
44 if (!paths[empty])
45 errExit("strdup"); 36 errExit("strdup");
37
38 // size the paths array
39 for (p = path; *p; p++)
40 if (*p == ':')
41 path_cnt++;
42 path_cnt += 2; // one because we were counting fenceposts, one for the NULL at the end
43
44 paths = calloc(path_cnt, sizeof(char *));
45 if (!paths)
46 errExit("calloc");
47
48 // fill in 'paths' with pointers to elements of 'path'
49 char *elt;
50 unsigned int i = 0, j;
51 unsigned int len;
52 while ((elt = strsep(&path, ":")) != 0) {
53 // skip any entry that is not absolute
54 if (elt[0] != '/')
55 goto skip;
56
57 // strip trailing slashes (this also prevents '/' from being a path entry).
58 len = strlen(elt);
59 while (len > 0 && elt[len-1] == '/')
60 elt[--len] = '\0';
61 if (len == 0)
62 goto skip;
63
64 // filter out duplicate entries
65 for (j = 0; j < i; j++)
66 if (strcmp(elt, paths[j]) == 0)
67 goto skip;
68
69 paths[i++] = elt;
70 if (len > longest_path_elt)
71 longest_path_elt = len;
72
73 skip:;
74 }
75
76 assert(paths[i] == 0);
77 // path_cnt may be too big now, if entries were skipped above
78 path_cnt = i+1;
46} 79}
47 80
81
48char **build_paths(void) { 82char **build_paths(void) {
49 if (initialized) { 83 if (!paths)
50 assert(paths); 84 init_paths();
51 return paths; 85 assert(paths);
52 } 86 return paths;
53 initialized = 1; 87}
54 88
55 int cnt = 5; // 4 default paths + 1 NULL to end the array 89// Note: the NULL element at the end of 'paths' is included in this count.
56 char *path1 = getenv("PATH"); 90unsigned int count_paths(void) {
57 if (path1) { 91 if (!path_cnt)
58 char *path2 = strdup(path1); 92 init_paths();
59 if (!path2) 93 assert(path_cnt);
60 errExit("strdup"); 94 return path_cnt;
61 95}
62 // use path2 to count the entries 96
63 char *ptr = strtok(path2, ":"); 97// Return 1 if PROGRAM exists in $PATH and is runnable by the
64 while (ptr) { 98// invoking user (not root).
65 cnt++; 99// In other words, tests "will execvp(PROGRAM, ...) succeed?"
66 ptr = strtok(NULL, ":"); 100int program_in_path(const char *program) {
67 } 101 assert(program && *program);
68 free(path2); 102 assert(strchr(program, '/') == 0);
69 path_cnt = cnt; 103 assert(strcmp(program, ".") != 0);
70 104 assert(strcmp(program, "..") != 0);
71 // allocate paths array 105
72 paths = malloc(sizeof(char *) * cnt); 106 if (!paths)
73 if (!paths) 107 init_paths();
74 errExit("malloc"); 108 assert(paths);
75 memset(paths, 0, sizeof(char *) * cnt); 109
76 110 size_t proglen = strlen(program);
77 // add default paths 111 char *scratch = malloc(longest_path_elt + proglen + 2);
78 add_path("/usr/local/bin"); 112 if (!scratch)
79 add_path("/usr/bin"); 113 errExit("malloc");
80 add_path("/bin"); 114
81 add_path("/usr/local/sbin"); 115 int found = 0;
82 add_path("/usr/sbin"); 116 size_t dlen;
83 add_path("/sbin"); 117 char **p;
84 118 for (p = paths; *p; p++) {
85 path2 = strdup(path1); 119 char *dir = *p;
86 if (!path2) 120 dlen = strlen(dir);
87 errExit("strdup"); 121
88 122 // init_paths should ensure that this is true; as long
89 // use path2 to count the entries 123 // as it is true, 'scratch' has enough space for "$p/$program".
90 ptr = strtok(path2, ":"); 124 assert(dlen <= longest_path_elt);
91 while (ptr) { 125
92 cnt++; 126 memcpy(scratch, dir, dlen);
93 add_path(ptr); 127 scratch[dlen++] = '/';
94 ptr = strtok(NULL, ":"); 128
129 // copy proglen+1 bytes to copy the nul terminator at
130 // the end of 'program'.
131 memcpy(scratch + dlen, program, proglen+1);
132
133 if (access(scratch, X_OK) == 0) {
134 // must also verify that this is a regular file
135 // ('x' permission means something different for directories).
136 // exec follows symlinks, so use stat, not lstat.
137 struct stat st;
138 if (stat(scratch, &st)) {
139 perror(scratch);
140 exit(1);
141 }
142 if (S_ISREG(st.st_mode)) {
143 found = 1;
144 break;
145 }
95 } 146 }
96 free(path2);
97 } 147 }
98 148
99 return paths; 149 free(scratch);
150 return found;
100} 151}