diff options
author | netblue30 <netblue30@yahoo.com> | 2017-02-14 15:00:09 -0500 |
---|---|---|
committer | netblue30 <netblue30@yahoo.com> | 2017-02-14 15:00:09 -0500 |
commit | b0cb1b40c3dd23e9584ab6b0686871ab02d298d0 (patch) | |
tree | 06ba5597231a26907ccaf944af2632d451d68275 /src/firejail/paths.c | |
parent | merge #1100 from zackw: removed libconnect (diff) | |
download | firejail-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.c | 191 |
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 | ||
22 | static char **paths = NULL; | 23 | static char **paths = 0; |
23 | static int path_cnt = 0; | 24 | static unsigned int path_cnt = 0; |
24 | static char initialized = 0; | 25 | static unsigned int longest_path_elt = 0; |
25 | 26 | ||
26 | static void add_path(const char *path) { | 27 | static 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 | |||
48 | char **build_paths(void) { | 82 | char **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"); | 90 | unsigned 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, ":"); | 100 | int 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 | } |