aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar startx2017 <vradu.startx@yandex.com>2018-08-14 08:35:01 -0400
committerLibravatar startx2017 <vradu.startx@yandex.com>2018-08-14 08:35:01 -0400
commit23a962a1af3894b6834ad08c12b3c3fd99775247 (patch)
treef086ad1afa06d0b054aec684917086b60d1a78ed
parentmerge 0.9.56-rc1 (diff)
downloadfirejail-23a962a1af3894b6834ad08c12b3c3fd99775247.tar.gz
firejail-23a962a1af3894b6834ad08c12b3c3fd99775247.tar.zst
firejail-23a962a1af3894b6834ad08c12b3c3fd99775247.zip
0.9.56-rc1 merges
-rw-r--r--README5
-rw-r--r--RELNOTES12
-rw-r--r--src/firecfg/firecfg.config2
-rw-r--r--src/firecfg/main.c2
-rw-r--r--src/firejail/appimage.c2
-rw-r--r--src/firejail/firejail.h12
-rw-r--r--src/firejail/fs_home.c2
-rw-r--r--src/firejail/fs_whitelist.c509
-rw-r--r--src/firejail/join.c4
-rw-r--r--src/firejail/ls.c5
-rw-r--r--src/firejail/macros.c284
-rw-r--r--src/firejail/main.c25
-rw-r--r--src/firejail/profile.c46
-rw-r--r--src/firejail/run_symlink.c1
-rw-r--r--src/firejail/sandbox.c4
-rw-r--r--src/firejail/usage.c2
-rw-r--r--src/firejail/util.c129
-rw-r--r--src/firemon/arp.c2
-rw-r--r--src/firemon/route.c6
-rw-r--r--src/firemon/usage.c2
-rw-r--r--src/fnet/veth.c4
-rw-r--r--src/fnetfilter/main.c8
-rw-r--r--src/fsec-print/print.c2
-rw-r--r--src/include/libnetlink.h4
-rw-r--r--src/lib/libnetlink.c4
-rw-r--r--src/libtracelog/libtracelog.c15
26 files changed, 574 insertions, 519 deletions
diff --git a/README b/README
index 2b031d966..faaf37da3 100644
--- a/README
+++ b/README
@@ -243,6 +243,8 @@ Fred-Barclay (https://github.com/Fred-Barclay)
243 - added BibleTime profile 243 - added BibleTime profile
244 - added caja and galculator profiles 244 - added caja and galculator profiles
245 - added Catfish profile 245 - added Catfish profile
246Frederik Olesen (https://github.com/Freso)
247 - added many vim profiles
246g3ngr33n (https://github.com/g3ngr33n) 248g3ngr33n (https://github.com/g3ngr33n)
247 - fix musl compilation 249 - fix musl compilation
248G4JC (https://sourceforge.net/u/gaming4jc/profile/) 250G4JC (https://sourceforge.net/u/gaming4jc/profile/)
@@ -318,6 +320,7 @@ Jean Lucas (https://github.com/flacks)
318 - alias for riot-desktop 320 - alias for riot-desktop
319 - add gnome-mpv profile 321 - add gnome-mpv profile
320 - fix wire profile 322 - fix wire profile
323 - add Beaker profile
321Jericho (https://github.com/attritionorg) 324Jericho (https://github.com/attritionorg)
322 - spelling 325 - spelling
323Jesse Smith (https://github.com/slicer69) 326Jesse Smith (https://github.com/slicer69)
@@ -487,6 +490,8 @@ rogshdo (https://github.com/rogshdo)
487 - BitlBee profile 490 - BitlBee profile
488Ruan (https://github.com/ruany) 491Ruan (https://github.com/ruany)
489 - fixed hexchat profile 492 - fixed hexchat profile
493Salvo 'LtWorf' Tomaselli (https://github.com/ltworf)
494 - fixed ktorrent profile
490sarneaud (https://github.com/sarneaud) 495sarneaud (https://github.com/sarneaud)
491 - rewrite globbing code to fix various minor issues 496 - rewrite globbing code to fix various minor issues
492 - added noblacklist command for profile files 497 - added noblacklist command for profile files
diff --git a/RELNOTES b/RELNOTES
index 6af251850..974999bcb 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -1,4 +1,4 @@
1firejail (0.9.55) baseline; urgency=low 1firejail (0.9.56~rc1) baseline; urgency=low
2 * work in progress 2 * work in progress
3 * modif: removed CFG_CHROOT_DESKTOP configuration option 3 * modif: removed CFG_CHROOT_DESKTOP configuration option
4 * modif: removed compile time --enable-network=restricted 4 * modif: removed compile time --enable-network=restricted
@@ -12,10 +12,12 @@ firejail (0.9.55) baseline; urgency=low
12 * add --private-cache to support private ~/.cache 12 * add --private-cache to support private ~/.cache
13 * support full paths in private-lib 13 * support full paths in private-lib
14 * globbing support in private-lib 14 * globbing support in private-lib
15 * new profiles: ms-excel, ms-office, ms-onenote, ms-outlook, ms-powerpoint 15 * new profiles: ms-excel, ms-office, ms-onenote, ms-outlook, ms-powerpoint,
16 * new profiles: ms-skype, ms-word, riot-desktop, gnome-mpv, snox, gradio 16 * new profiles: ms-skype, ms-word, riot-desktop, gnome-mpv, snox, gradio,
17 * new profiles: standardnotes-desktop, shellcheck, patch, flameshot 17 * new profiles: standardnotes-desktop, shellcheck, patch, flameshot,
18 -- netblue30 <netblue30@yahoo.com> Fri, 25 May 2018 08:00:00 -0500 18 * new profiles: rview, rvim, vimcat, vimdiff, vimpager, vimtutor, xxd,
19 * new profiles: Beaker, electrum
20 -- netblue30 <netblue30@yahoo.com> Sat, 11 Aug 2018 08:00:00 -0500
19 21
20firejail (0.9.54) baseline; urgency=low 22firejail (0.9.54) baseline; urgency=low
21 * modif: --force removed 23 * modif: --force removed
diff --git a/src/firecfg/firecfg.config b/src/firecfg/firecfg.config
index 2585d204a..a33aaeb49 100644
--- a/src/firecfg/firecfg.config
+++ b/src/firecfg/firecfg.config
@@ -46,6 +46,7 @@ baloo_file
46baloo_filemetadata_temp_extractor 46baloo_filemetadata_temp_extractor
47baobab 47baobab
48basilisk 48basilisk
49beaker
49bibletime 50bibletime
50bitlbee 51bitlbee
51bleachbit 52bleachbit
@@ -108,6 +109,7 @@ dosbox
108dragon 109dragon
109dropbox 110dropbox
110ebook-viewer 111ebook-viewer
112electrum
111elinks 113elinks
112empathy 114empathy
113enchant 115enchant
diff --git a/src/firecfg/main.c b/src/firecfg/main.c
index b79053d3e..6fe220d35 100644
--- a/src/firecfg/main.c
+++ b/src/firecfg/main.c
@@ -53,7 +53,7 @@ static char *usage_str =
53 " [...]\n" 53 " [...]\n"
54 "\n" 54 "\n"
55 "License GPL version 2 or later\n" 55 "License GPL version 2 or later\n"
56 "Homepage: http://firejail.wordpress.com\n\n"; 56 "Homepage: https://firejail.wordpress.com\n\n";
57 57
58static void usage(void) { 58static void usage(void) {
59 printf("firecfg - version %s\n\n", VERSION); 59 printf("firecfg - version %s\n\n", VERSION);
diff --git a/src/firejail/appimage.c b/src/firejail/appimage.c
index 631276c0b..e8db91958 100644
--- a/src/firejail/appimage.c
+++ b/src/firejail/appimage.c
@@ -17,7 +17,7 @@
17 * with this program; if not, write to the Free Software Foundation, Inc., 17 * with this program; if not, write to the Free Software Foundation, Inc.,
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// http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=770fe30a46a12b6fb6b63fbe1737654d28e84844 20// https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=770fe30a46a12b6fb6b63fbe1737654d28e84844
21// sudo mount -o loop krita-3.0-x86_64.appimage mnt 21// sudo mount -o loop krita-3.0-x86_64.appimage mnt
22 22
23#include "firejail.h" 23#include "firejail.h"
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 0faf10340..f31d6a2bc 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -451,6 +451,7 @@ void fs_chroot(const char *rootdir);
451void fs_check_chroot_dir(const char *rootdir); 451void fs_check_chroot_dir(const char *rootdir);
452void fs_private_tmp(void); 452void fs_private_tmp(void);
453void fs_private_cache(void); 453void fs_private_cache(void);
454void fs_mnt(void);
454 455
455// profile.c 456// profile.c
456// find and read the profile specified by name from dir directory 457// find and read the profile specified by name from dir directory
@@ -463,7 +464,7 @@ void profile_read(const char *fname);
463int profile_check_line(char *ptr, int lineno, const char *fname); 464int profile_check_line(char *ptr, int lineno, const char *fname);
464// add a profile entry in cfg.profile list; use str to populate the list 465// add a profile entry in cfg.profile list; use str to populate the list
465void profile_add(char *str); 466void profile_add(char *str);
466void fs_mnt(void); 467void profile_add_ignore(const char *str);
467 468
468// list.c 469// list.c
469void list(void); 470void list(void);
@@ -490,6 +491,13 @@ int arp_check(const char *dev, uint32_t destaddr);
490// assign an IP address using arp scanning 491// assign an IP address using arp scanning
491uint32_t arp_assign(const char *dev, Bridge *br); 492uint32_t arp_assign(const char *dev, Bridge *br);
492 493
494// macros.c
495char *expand_home(const char *path, const char *homedir);
496char *resolve_macro(const char *name);
497void invalid_filename(const char *fname, int globbing);
498int is_macro(const char *name);
499
500
493// util.c 501// util.c
494void errLogExit(char* fmt, ...); 502void errLogExit(char* fmt, ...);
495void fwarning(char* fmt, ...); 503void fwarning(char* fmt, ...);
@@ -515,10 +523,8 @@ void check_private_dir(void);
515void update_map(char *mapping, char *map_file); 523void update_map(char *mapping, char *map_file);
516void wait_for_other(int fd); 524void wait_for_other(int fd);
517void notify_other(int fd); 525void notify_other(int fd);
518char *expand_home(const char *path, const char* homedir);
519const char *gnu_basename(const char *path); 526const char *gnu_basename(const char *path);
520uid_t pid_get_uid(pid_t pid); 527uid_t pid_get_uid(pid_t pid);
521void invalid_filename(const char *fname, int globbing);
522uid_t get_group_id(const char *group); 528uid_t get_group_id(const char *group);
523int remove_overlay_directory(void); 529int remove_overlay_directory(void);
524void flush_stdin(void); 530void flush_stdin(void);
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c
index f8e7e6e74..3a332f7ff 100644
--- a/src/firejail/fs_home.c
+++ b/src/firejail/fs_home.c
@@ -290,6 +290,8 @@ void fs_private(void) {
290 if (u == 0 && arg_allusers) // allow --allusers when starting the sandbox as root 290 if (u == 0 && arg_allusers) // allow --allusers when starting the sandbox as root
291 ; 291 ;
292 else { 292 else {
293 if (arg_allusers)
294 fwarning("--allusers disabled by --private or --whitelist\n");
293 if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) 295 if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
294 errExit("mounting home directory"); 296 errExit("mounting home directory");
295 fs_logger("tmpfs /home"); 297 fs_logger("tmpfs /home");
diff --git a/src/firejail/fs_whitelist.c b/src/firejail/fs_whitelist.c
index bf839b524..c3d34e259 100644
--- a/src/firejail/fs_whitelist.c
+++ b/src/firejail/fs_whitelist.c
@@ -29,207 +29,95 @@
29 29
30// mountinfo functionality test; 30// mountinfo functionality test;
31// 1. enable TEST_MOUNTINFO definition 31// 1. enable TEST_MOUNTINFO definition
32// 2. set a symlink in /tmp: ln -s /etc /tmp/etc 32// 2. run firejail --whitelist=/any/directory
33// 3. run firejail --debug --whitelist=/tmp/etc
34//#define TEST_MOUNTINFO 33//#define TEST_MOUNTINFO
35 34
36static char *dentry[] = {
37 "Downloads",
38 "Загрузки",
39 "Téléchargement",
40 NULL
41};
42
43static char *mentry[] = {
44 "Music",
45 "Музыка",
46 "Musique",
47 NULL
48};
49
50static char *ventry[] = {
51 "Videos",
52 "Видео",
53 "Vidéos",
54 NULL
55};
56
57static char *pentry[] = {
58 "Pictures",
59 "Изображения",
60 "Photos",
61 NULL
62};
63
64static char *deentry[] = {
65 "Desktop",
66 "Рабочий стол",
67 "Bureau",
68 NULL
69};
70
71static char *doentry[] = {
72 "Documents",
73 "Документы",
74 "Documents",
75 NULL
76};
77
78#define EMPTY_STRING ("") 35#define EMPTY_STRING ("")
79#define MAXBUF 4098 36#define MAXBUF 4098
80 37
81static char *resolve_xdg(int nowhitelist_flag, const char *var, size_t length, const char *prnt) { 38// returns mallocated memory
82 EUID_ASSERT(); 39char *parse_nowhitelist(int nowhitelist_flag, char *ptr1) {
83 char *fname; 40 char *rv;
84 struct stat s; 41 if (nowhitelist_flag) {
85 42 if (asprintf(&rv, "nowhitelist ~/%s", ptr1) == -1)
86 if (asprintf(&fname, "%s/.config/user-dirs.dirs", cfg.homedir) == -1) 43 errExit("asprintf");
87 errExit("asprintf");
88 FILE *fp = fopen(fname, "r");
89 if (!fp) {
90 free(fname);
91 return NULL;
92 }
93 free(fname);
94
95 char buf[MAXBUF];
96 while (fgets(buf, MAXBUF, fp)) {
97 char *ptr = buf;
98
99 // skip blanks
100 while (*ptr == ' ' || *ptr == '\t')
101 ptr++;
102 if (*ptr == '\0' || *ptr == '\n' || *ptr == '#')
103 continue;
104
105 if (strncmp(ptr, var, length) == 0) {
106 char *ptr1 = ptr + length;
107 char *ptr2 = strchr(ptr1, '"');
108 if (ptr2) {
109 fclose(fp);
110 *ptr2 = '\0';
111 if (arg_debug || arg_debug_whitelists)
112 printf("extracted %s from ~/.config/user-dirs.dirs\n", ptr1);
113 if (strlen(ptr1) != 0) {
114 if (arg_debug || arg_debug_whitelists)
115 printf("%s ",prnt);
116 printf("directory resolved as \"%s\"\n", ptr1);
117
118 if (asprintf(&fname, "%s/%s", cfg.homedir, ptr1) == -1)
119 errExit("asprintf");
120
121 if (stat(fname, &s) == -1) {
122 free(fname);
123 goto errout;
124 }
125
126 char *rv;
127 if (nowhitelist_flag) {
128 if (asprintf(&rv, "nowhitelist ~/%s", ptr + length) == -1)
129 errExit("asprintf");
130 }
131 else {
132 if (asprintf(&rv, "whitelist ~/%s", ptr + length) == -1)
133 errExit("asprintf");
134 }
135 return rv;
136 }
137 else
138 goto errout;
139 }
140 }
141 }
142
143 fclose(fp);
144 return NULL;
145
146 errout:
147 if (!arg_private) {
148 fprintf(stderr, "***\n");
149 fprintf(stderr, "*** Error: %s directory was not found in user home.\n",prnt);
150 fprintf(stderr, "*** \tAny files saved by the program, will be lost when the sandbox is closed.\n");
151 fprintf(stderr, "***\n");
152 } 44 }
153 return NULL; 45 else {
154} 46 if (asprintf(&rv, "whitelist ~/%s", ptr1) == -1)
155
156static char *resolve_hardcoded(int nowhitelist_flag, char *entries[], const char *prnt) {
157 EUID_ASSERT();
158 char *fname;
159 struct stat s;
160
161 int i = 0;
162 while (entries[i] != NULL) {
163 if (asprintf(&fname, "%s/%s", cfg.homedir, entries[i]) == -1)
164 errExit("asprintf"); 47 errExit("asprintf");
165
166 if (stat(fname, &s) == 0) {
167 if (arg_debug || arg_debug_whitelists) {
168 printf("%s ", prnt);
169 printf("directory resolved as \"%s\"\n", fname);
170 }
171
172 char *rv;
173 if (nowhitelist_flag) {
174 if (asprintf(&rv, "nowhitelist ~/%s", entries[i]) == -1)
175 errExit("asprintf");
176 }
177 else {
178 if (asprintf(&rv, "whitelist ~/%s", entries[i]) == -1)
179 errExit("asprintf");
180 }
181 free(fname);
182 return rv;
183 }
184 free(fname);
185 i++;
186 } 48 }
187 49 return rv;
188 return NULL;
189} 50}
190 51
191static int mkpath(const char* path, mode_t mode) { 52static int mkpath(const char* path, mode_t mode) {
192 assert(path && *path); 53 assert(path && *path);
193
194 mode |= 0111; 54 mode |= 0111;
195 55
196 // create directories with uid/gid as root or as current user if inside home directory 56 // create directories with uid/gid as root or as current user if inside home directory
197 uid_t uid = getuid(); 57 if (strncmp(path, cfg.homedir, strlen(cfg.homedir)) == 0) {
198 gid_t gid = getgid(); 58 EUID_USER();
199 if (strncmp(path, cfg.homedir, strlen(cfg.homedir)) != 0) {
200 uid = 0;
201 gid = 0;
202 } 59 }
203 60
204 // work on a copy of the path 61 // work on a copy of the path
205 char *file_path = strdup(path); 62 char *dup = strdup(path);
206 if (!file_path) 63 if (!dup)
207 errExit("strdup"); 64 errExit("strdup");
208 65
209 char* p; 66 // don't create the last path element
67 char *p = strrchr(dup, '/');
68 assert(p);
69 *p = '\0';
70
71 int parentfd = open("/", O_PATH|O_DIRECTORY|O_CLOEXEC);
72 if (parentfd == -1)
73 errExit("open");
74
75 // traverse the path, return -1 if a symlink is encountered
210 int done = 0; 76 int done = 0;
211 for (p=strchr(file_path+1, '/'); p; p=strchr(p+1, '/')) { 77 int fd = -1;
212 *p='\0'; 78 char *tok = strtok(dup, "/");
213 if (mkdir(file_path, mode)==-1) { 79 assert(tok); // path is no top level directory
80 while (tok) {
81 // skip all instances of "/./"
82 if (strcmp(tok, ".") == 0) {
83 tok = strtok(NULL, "/");
84 continue;
85 }
86 // create the directory if necessary
87 if (mkdirat(parentfd, tok, mode) == -1) {
214 if (errno != EEXIST) { 88 if (errno != EEXIST) {
215 *p='/'; 89 if (arg_debug || arg_debug_whitelists)
216 free(file_path); 90 perror("mkdir");
91 close(parentfd);
92 free(dup);
93 EUID_ROOT();
217 return -1; 94 return -1;
218 } 95 }
219 } 96 }
220 else { 97 else
221 if (set_perms(file_path, uid, gid, mode))
222 errExit("set_perms");
223 done = 1; 98 done = 1;
99 // open the directory
100 fd = openat(parentfd, tok, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
101 if (fd == -1) {
102 if (arg_debug || arg_debug_whitelists)
103 perror("open");
104 close(parentfd);
105 free(dup);
106 EUID_ROOT();
107 return -1;
224 } 108 }
225 109 // move on to next path segment
226 *p='/'; 110 close(parentfd);
111 parentfd = fd;
112 tok = strtok(NULL, "/");
227 } 113 }
114
228 if (done) 115 if (done)
229 fs_logger2("mkpath", path); 116 fs_logger2("mkpath", path);
230 117
231 free(file_path); 118 free(dup);
232 return 0; 119 EUID_ROOT();
120 return fd;
233} 121}
234 122
235static void whitelist_path(ProfileEntry *entry) { 123static void whitelist_path(ProfileEntry *entry) {
@@ -323,13 +211,17 @@ static void whitelist_path(ProfileEntry *entry) {
323 } 211 }
324 assert(wfile); 212 assert(wfile);
325 213
326 // check if the file exists, confirm again there is no symlink 214 if (arg_debug || arg_debug_whitelists)
215 printf("Whitelisting %s\n", path);
216
217 // confirm again the mount source exists and there is no symlink
327 struct stat wfilestat; 218 struct stat wfilestat;
328#ifndef TEST_MOUNTINFO
329 EUID_USER(); 219 EUID_USER();
330 int fd = safe_fd(wfile, O_PATH|O_NOFOLLOW|O_CLOEXEC); 220 int fd = safe_fd(wfile, O_PATH|O_NOFOLLOW|O_CLOEXEC);
331 EUID_ROOT(); 221 EUID_ROOT();
332 if (fd == -1) { 222 if (fd == -1) {
223 if (arg_debug || arg_debug_whitelists)
224 printf("Debug %d: skip whitelisting of %s\n", __LINE__, path);
333 free(wfile); 225 free(wfile);
334 return; 226 return;
335 } 227 }
@@ -337,57 +229,68 @@ static void whitelist_path(ProfileEntry *entry) {
337 errExit("fstat"); 229 errExit("fstat");
338 close(fd); 230 close(fd);
339 if (S_ISLNK(wfilestat.st_mode)) { 231 if (S_ISLNK(wfilestat.st_mode)) {
232 if (arg_debug || arg_debug_whitelists)
233 printf("Debug %d: skip whitelisting of %s\n", __LINE__, path);
340 free(wfile); 234 free(wfile);
341 return; 235 return;
342 } 236 }
237
238#ifdef TEST_MOUNTINFO
239 printf("TEST_MOUNTINFO\n");
240 path = "/etc/.";
343#endif 241#endif
344 242
345 if (arg_debug || arg_debug_whitelists) 243 // create path of the mount target if necessary
346 printf("Whitelisting %s\n", path); 244 int fd2 = mkpath(path, 0755);
245 if (fd2 == -1) {
246 // something went wrong during path creation or a symlink was found;
247 // if there is a symlink somewhere in the path of the mount target,
248 // assume the file is whitelisted already
249 if (arg_debug || arg_debug_whitelists)
250 printf("Debug %d: skip whitelisting of %s\n", __LINE__, path);
251 free(wfile);
252 return;
253 }
347 254
348 // create the path if necessary 255 // get file name of the mount target
349 struct stat s; 256 const char *file = gnu_basename(path);
350 if (stat(path, &s) == -1) { 257
351 mkpath(path, 0755); 258 // create the mount target if necessary and open it, a symlink is rejected
352 if (S_ISDIR(wfilestat.st_mode)) { 259 int fd3 = -1;
353 int rv = mkdir(path, 0755); 260 if (S_ISDIR(wfilestat.st_mode)) {
354 if (rv) { 261 // directory foo can exist already:
355 fprintf(stderr, "Error: cannot create directory %s\n", path); 262 // firejail --whitelist=/foo/bar --whitelist=/foo
356 exit(1); 263 if (mkdirat(fd2, file, 0755) == -1 && errno != EEXIST) {
357 } 264 if (arg_debug || arg_debug_whitelists) {
358 } 265 perror("mkdir");
359 else { 266 printf("Debug %d: skip whitelisting of %s\n", __LINE__, path);
360 int fd2 = open(path, O_RDONLY|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR|S_IWUSR);
361 if (fd2 == -1) {
362 fprintf(stderr, "Error: cannot create empty file %s\n", path);
363 exit(1);
364 } 267 }
365 close(fd2); 268 close(fd2);
269 free(wfile);
270 return;
366 } 271 }
272 fd3 = openat(fd2, file, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
367 } 273 }
368 else { 274 else {
369 if (!S_ISDIR(s.st_mode)) { 275 // create an empty file, fails with EEXIST if it is whitelisted already:
370 free(wfile); 276 // firejail --whitelist=/foo --whitelist=/foo/bar
371 return; // the file is already present 277 fd3 = openat(fd2, file, O_RDONLY|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR|S_IWUSR);
372 }
373 } 278 }
374 279
375 fs_logger2("whitelist", path);
376
377 // get a file descriptor for path; if path contains anything other than directories
378 // or a regular file, assume it is whitelisted already
379 int fd3 = safe_fd(path, O_PATH|O_NOFOLLOW|O_CLOEXEC);
380 if (fd3 == -1) { 280 if (fd3 == -1) {
281 if (arg_debug || arg_debug_whitelists) {
282 if (errno != EEXIST) {
283 perror("open");
284 printf("Debug %d: skip whitelisting of %s\n", __LINE__, path);
285 }
286 }
287 close(fd2);
381 free(wfile); 288 free(wfile);
382 return; 289 return;
383 } 290 }
384 if (fstat(fd3, &s) == -1) 291 close(fd2);
385 errExit("fstat"); 292
386 if (!(S_ISDIR(s.st_mode) || S_ISREG(s.st_mode))) { 293 fs_logger2("whitelist", path);
387 free(wfile);
388 close(fd3);
389 return;
390 }
391 294
392 // mount via the link in /proc/self/fd 295 // mount via the link in /proc/self/fd
393 char *proc; 296 char *proc;
@@ -411,6 +314,7 @@ static void whitelist_path(ProfileEntry *entry) {
411 int fd4 = safe_fd(path, O_PATH|O_NOFOLLOW|O_CLOEXEC); 314 int fd4 = safe_fd(path, O_PATH|O_NOFOLLOW|O_CLOEXEC);
412 if (fd4 == -1) 315 if (fd4 == -1)
413 errExit("safe_fd"); 316 errExit("safe_fd");
317 struct stat s;
414 if (fstat(fd4, &s) == -1) 318 if (fstat(fd4, &s) == -1)
415 errExit("fstat"); 319 errExit("fstat");
416 if (s.st_dev != wfilestat.st_dev || s.st_ino != wfilestat.st_ino) 320 if (s.st_dev != wfilestat.st_dev || s.st_ino != wfilestat.st_ino)
@@ -465,99 +369,21 @@ void fs_whitelist(void) {
465 } 369 }
466 char *dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; 370 char *dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
467 371
468 // resolve ${DOWNLOADS} 372 // resolve macros
469 if (strcmp(dataptr, "${DOWNLOADS}") == 0) { 373 if (is_macro(dataptr)) {
470 char *tmp = resolve_xdg(nowhitelist_flag, "XDG_DOWNLOAD_DIR=\"$HOME/", 24, "Downloads"); 374 char *tmp = resolve_macro(dataptr);
471 char *tmp2 = resolve_hardcoded(nowhitelist_flag, dentry, "Downloads"); 375 if (tmp != NULL)
472 if (tmp) { 376 tmp = parse_nowhitelist(nowhitelist_flag, tmp);
473 entry->data = tmp;
474 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
475 }
476 else if (tmp2) {
477 entry->data = tmp2;
478 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
479 }
480 else {
481 if (!nowhitelist_flag && !arg_quiet && !arg_private) {
482 fprintf(stderr, "***\n");
483 fprintf(stderr, "*** Warning: cannot whitelist Downloads directory\n");
484 fprintf(stderr, "*** \tAny file saved will be lost when the sandbox is closed.\n");
485 fprintf(stderr, "*** \tPlease create a proper Downloads directory for your application.\n");
486 fprintf(stderr, "***\n");
487 }
488 entry->data = EMPTY_STRING;
489 continue;
490 }
491 }
492 377
493 // resolve ${MUSIC}
494 if (strcmp(dataptr, "${MUSIC}") == 0) {
495 char *tmp = resolve_xdg(nowhitelist_flag, "XDG_MUSIC_DIR=\"$HOME/", 21, "Music");
496 char *tmp2 = resolve_hardcoded(nowhitelist_flag, mentry, "Music");
497 if (tmp) { 378 if (tmp) {
498 entry->data = tmp; 379 entry->data = tmp;
499 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; 380 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
500 } 381 }
501 else if (tmp2) {
502 entry->data = tmp2;
503 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
504 }
505 else {
506 if (!nowhitelist_flag && !arg_quiet && !arg_private) {
507 fprintf(stderr, "***\n");
508 fprintf(stderr, "*** Warning: cannot whitelist Music directory\n");
509 fprintf(stderr, "*** \tAny file saved will be lost when the sandbox is closed.\n");
510 fprintf(stderr, "*** \tPlease create a proper Music directory for your application.\n");
511 fprintf(stderr, "***\n");
512 }
513 entry->data = EMPTY_STRING;
514 continue;
515 }
516 }
517
518 // resolve ${VIDEOS}
519 if (strcmp(dataptr, "${VIDEOS}") == 0) {
520 char *tmp = resolve_xdg(nowhitelist_flag, "XDG_VIDEOS_DIR=\"$HOME/", 22, "Videos");
521 char *tmp2 = resolve_hardcoded(nowhitelist_flag, ventry, "Videos");
522 if (tmp) {
523 entry->data = tmp;
524 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
525 }
526 else if (tmp2) {
527 entry->data = tmp2;
528 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
529 }
530 else {
531 if (!nowhitelist_flag && !arg_quiet && !arg_private) {
532 fprintf(stderr, "***\n");
533 fprintf(stderr, "*** Warning: cannot whitelist Videos directory\n");
534 fprintf(stderr, "*** \tAny file saved will be lost when the sandbox is closed.\n");
535 fprintf(stderr, "*** \tPlease create a proper Videos directory for your application.\n");
536 fprintf(stderr, "***\n");
537 }
538 entry->data = EMPTY_STRING;
539 continue;
540 }
541 }
542
543 // resolve ${PICTURES}
544 if (strcmp(dataptr, "${PICTURES}") == 0) {
545 char *tmp = resolve_xdg(nowhitelist_flag, "XDG_PICTURES_DIR=\"$HOME/", 24, "Pictures");
546 char *tmp2 = resolve_hardcoded(nowhitelist_flag, pentry, "Pictures");
547 if (tmp) {
548 entry->data = tmp;
549 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
550 }
551 else if (tmp2) {
552 entry->data = tmp2;
553 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
554 }
555 else { 382 else {
556 if (!nowhitelist_flag && !arg_quiet && !arg_private) { 383 if (!nowhitelist_flag && !arg_quiet && !arg_private) {
557 fprintf(stderr, "***\n"); 384 fprintf(stderr, "***\n");
558 fprintf(stderr, "*** Warning: cannot whitelist Pictures directory\n"); 385 fprintf(stderr, "*** Warning: cannot whitelist %s directory\n", dataptr);
559 fprintf(stderr, "*** \tAny file saved will be lost when the sandbox is closed.\n"); 386 fprintf(stderr, "*** Any file saved in this directory will be lost when the sandbox is closed.\n");
560 fprintf(stderr, "*** \tPlease create a proper Pictures directory for your application.\n");
561 fprintf(stderr, "***\n"); 387 fprintf(stderr, "***\n");
562 } 388 }
563 entry->data = EMPTY_STRING; 389 entry->data = EMPTY_STRING;
@@ -565,59 +391,24 @@ void fs_whitelist(void) {
565 } 391 }
566 } 392 }
567 393
568 // resolve ${DESKTOP} 394 // replace ~/ or ${HOME} into /home/username
569 if (strcmp(dataptr, "${DESKTOP}") == 0) { 395 new_name = expand_home(dataptr, cfg.homedir);
570 char *tmp = resolve_xdg(nowhitelist_flag, "XDG_DESKTOP_DIR=\"$HOME/", 24, "Desktop"); 396 assert(new_name);
571 char *tmp2 = resolve_hardcoded(nowhitelist_flag, deentry, "Desktop");
572 if (tmp) {
573 entry->data = tmp;
574 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
575 }
576 else if (tmp2) {
577 entry->data = tmp2;
578 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10;
579 }
580 else {
581 if (!nowhitelist_flag && !arg_quiet && !arg_private) {
582 fprintf(stderr, "***\n");
583 fprintf(stderr, "*** Warning: cannot whitelist Desktop directory\n");
584 fprintf(stderr, "*** \tAny file saved will be lost when the sandbox is closed.\n");
585 fprintf(stderr, "*** \tPlease create a proper Desktop directory for your application.\n");
586 fprintf(stderr, "***\n");
587 }
588 entry->data = EMPTY_STRING;
589 continue;
590 }
591 }
592 397
593 // resolve ${DOCUMENTS} 398 // trim trailing slashes or dots
594 if (strcmp(dataptr, "${DOCUMENTS}") == 0) { 399 char *end = strchr(new_name, '\0');
595 char *tmp = resolve_xdg(nowhitelist_flag, "XDG_DOCUMENTS_DIR=\"$HOME/", 25, "Documents"); 400 assert(end);
596 char *tmp2 = resolve_hardcoded(nowhitelist_flag, doentry, "Documents"); 401 if ((end - new_name) > 1) {
597 if (tmp) { 402 end--;
598 entry->data = tmp; 403 while (*end == '/' ||
599 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; 404 (*end == '.' && *(end - 1) == '/')) {
600 } 405 *end = '\0';
601 else if (tmp2) { 406 end--;
602 entry->data = tmp2; 407 if (end == new_name)
603 dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; 408 break;
604 }
605 else {
606 if (!nowhitelist_flag && !arg_quiet && !arg_private) {
607 fprintf(stderr, "***\n");
608 fprintf(stderr, "*** Warning: cannot whitelist Documents directory\n");
609 fprintf(stderr, "*** \tAny file saved will be lost when the sandbox is closed.\n");
610 fprintf(stderr, "*** \tPlease create a proper Documents directory for your application.\n");
611 fprintf(stderr, "***\n");
612 }
613 entry->data = EMPTY_STRING;
614 continue;
615 } 409 }
616 } 410 }
617 411
618 // replace ~/ or ${HOME} into /home/username
619 new_name = expand_home(dataptr, cfg.homedir);
620 assert(new_name);
621 if (arg_debug || arg_debug_whitelists) 412 if (arg_debug || arg_debug_whitelists)
622 fprintf(stderr, "Debug %d: new_name #%s#, %s\n", __LINE__, new_name, (nowhitelist_flag)? "nowhitelist": "whitelist"); 413 fprintf(stderr, "Debug %d: new_name #%s#, %s\n", __LINE__, new_name, (nowhitelist_flag)? "nowhitelist": "whitelist");
623 414
@@ -628,7 +419,6 @@ void fs_whitelist(void) {
628 goto errexit; 419 goto errexit;
629 } 420 }
630 421
631
632 // extract the absolute path of the file 422 // extract the absolute path of the file
633 // realpath function will fail with ENOENT if the file is not found 423 // realpath function will fail with ENOENT if the file is not found
634 // special processing for /dev/fd, /dev/stdin, /dev/stdout and /dev/stderr 424 // special processing for /dev/fd, /dev/stdin, /dev/stdout and /dev/stderr
@@ -704,7 +494,6 @@ void fs_whitelist(void) {
704 continue; 494 continue;
705 } 495 }
706 496
707
708 // check for supported directories 497 // check for supported directories
709 if (strncmp(new_name, cfg.homedir, strlen(cfg.homedir)) == 0) { 498 if (strncmp(new_name, cfg.homedir, strlen(cfg.homedir)) == 0) {
710 // whitelisting home directory is disabled if --private option is present 499 // whitelisting home directory is disabled if --private option is present
@@ -724,7 +513,7 @@ void fs_whitelist(void) {
724 513
725 // both path and absolute path are under /home 514 // both path and absolute path are under /home
726 if (strncmp(fname, cfg.homedir, strlen(cfg.homedir)) == 0) { 515 if (strncmp(fname, cfg.homedir, strlen(cfg.homedir)) == 0) {
727 // avoid naming issues, also entire home dirs are not allowed 516 // entire home directory is not allowed
728 if (*(fname + strlen(cfg.homedir)) != '/') 517 if (*(fname + strlen(cfg.homedir)) != '/')
729 goto errexit; 518 goto errexit;
730 } 519 }
@@ -740,12 +529,10 @@ void fs_whitelist(void) {
740 entry->tmp_dir = 1; 529 entry->tmp_dir = 1;
741 tmp_dir = 1; 530 tmp_dir = 1;
742 531
743#ifndef TEST_MOUNTINFO
744 // both path and absolute path are under /tmp 532 // both path and absolute path are under /tmp
745 if (strncmp(fname, "/tmp/", 5) != 0) { 533 if (strncmp(fname, "/tmp/", 5) != 0) {
746 goto errexit; 534 goto errexit;
747 } 535 }
748#endif
749 } 536 }
750 else if (strncmp(new_name, "/media/", 7) == 0) { 537 else if (strncmp(new_name, "/media/", 7) == 0) {
751 entry->media_dir = 1; 538 entry->media_dir = 1;
@@ -871,7 +658,7 @@ void fs_whitelist(void) {
871 entry->link = new_name; 658 entry->link = new_name;
872 else { 659 else {
873 free(new_name); 660 free(new_name);
874 new_name = NULL; 661 entry->link = NULL;
875 } 662 }
876 663
877 // change file name in entry->data 664 // change file name in entry->data
@@ -901,7 +688,7 @@ void fs_whitelist(void) {
901 if (mount(cfg.homedir, RUN_WHITELIST_HOME_USER_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) 688 if (mount(cfg.homedir, RUN_WHITELIST_HOME_USER_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
902 errExit("mount bind"); 689 errExit("mount bind");
903 690
904 // mount a tmpfs and initialize /home/user 691 // mount a tmpfs and initialize /home/user, overrides --allusers
905 fs_private(); 692 fs_private();
906 } 693 }
907 else 694 else
@@ -1113,14 +900,29 @@ void fs_whitelist(void) {
1113 // if the link is already there, do not bother 900 // if the link is already there, do not bother
1114 if (lstat(entry->link, &s) != 0) { 901 if (lstat(entry->link, &s) != 0) {
1115 // create the path if necessary 902 // create the path if necessary
1116 mkpath(entry->link, 0755); 903 int fd = mkpath(entry->link, 0755);
1117 904 if (fd == -1) {
1118 int rv = symlink(entry->data + 10, entry->link); 905 if (arg_debug || arg_debug_whitelists)
1119 if (rv) 906 printf("Debug %d: cannot create symbolic link %s\n", __LINE__, entry->link);
1120 fprintf(stderr, "Warning cannot create symbolic link %s\n", entry->link); 907 free(entry->link);
908 entry = entry->next;
909 continue;
910 }
911 // get file name of symlink
912 const char *file = gnu_basename(entry->link);
913 // create the link
914 int rv = symlinkat(entry->data + 10, fd, file);
915 if (rv) {
916 if (arg_debug || arg_debug_whitelists) {
917 perror("symlink");
918 printf("Debug %d: cannot create symbolic link %s\n", __LINE__, entry->link);
919 }
920 }
1121 else if (arg_debug || arg_debug_whitelists) 921 else if (arg_debug || arg_debug_whitelists)
1122 printf("Created symbolic link %s -> %s\n", entry->link, entry->data + 10); 922 printf("Created symbolic link %s -> %s\n", entry->link, entry->data + 10);
923 close(fd);
1123 } 924 }
925 free(entry->link);
1124 } 926 }
1125 927
1126 entry = entry->next; 928 entry = entry->next;
@@ -1203,9 +1005,6 @@ void fs_whitelist(void) {
1203 fs_logger2("tmpfs", RUN_WHITELIST_MODULE_DIR); 1005 fs_logger2("tmpfs", RUN_WHITELIST_MODULE_DIR);
1204 } 1006 }
1205 1007
1206 if (new_name)
1207 free(new_name);
1208
1209 return; 1008 return;
1210 1009
1211errexit: 1010errexit:
diff --git a/src/firejail/join.c b/src/firejail/join.c
index e6da4c248..729c7f797 100644
--- a/src/firejail/join.c
+++ b/src/firejail/join.c
@@ -49,7 +49,7 @@ static void extract_x11_display(pid_t pid) {
49 if (!fp) 49 if (!fp)
50 return; 50 return;
51 51
52 if (1 != fscanf(fp, "%d", &display)) { 52 if (1 != fscanf(fp, "%u", &display)) {
53 fprintf(stderr, "Error: cannot read X11 display file\n"); 53 fprintf(stderr, "Error: cannot read X11 display file\n");
54 fclose(fp); 54 fclose(fp);
55 return; 55 return;
@@ -214,7 +214,7 @@ static void extract_umask(pid_t pid) {
214 free(fname); 214 free(fname);
215 if (!fp) 215 if (!fp)
216 return; 216 return;
217 if (fscanf(fp, "%4o", &orig_umask) < 1) { 217 if (fscanf(fp, "%3o", &orig_umask) < 1) {
218 fprintf(stderr, "Error: cannot read umask\n"); 218 fprintf(stderr, "Error: cannot read umask\n");
219 exit(1); 219 exit(1);
220 } 220 }
diff --git a/src/firejail/ls.c b/src/firejail/ls.c
index 79e4b679b..601cab4f8 100644
--- a/src/firejail/ls.c
+++ b/src/firejail/ls.c
@@ -198,6 +198,10 @@ char *expand_path(const char *path) {
198 } 198 }
199 else { 199 else {
200 // assume the file is in current working directory 200 // assume the file is in current working directory
201 if (!cfg.cwd) {
202 fprintf(stderr, "Error: current working directory has been deleted\n");
203 exit(1);
204 }
201 if (asprintf(&fname, "%s/%s", cfg.cwd, path) == -1) 205 if (asprintf(&fname, "%s/%s", cfg.cwd, path) == -1)
202 errExit("asprintf"); 206 errExit("asprintf");
203 } 207 }
@@ -206,6 +210,7 @@ char *expand_path(const char *path) {
206 210
207void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) { 211void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
208 EUID_ASSERT(); 212 EUID_ASSERT();
213 assert(path1);
209 214
210 // if the pid is that of a firejail process, use the pid of the first child process 215 // if the pid is that of a firejail process, use the pid of the first child process
211 EUID_ROOT(); 216 EUID_ROOT();
diff --git a/src/firejail/macros.c b/src/firejail/macros.c
new file mode 100644
index 000000000..283de57f2
--- /dev/null
+++ b/src/firejail/macros.c
@@ -0,0 +1,284 @@
1/*
2 * Copyright (C) 2014-2018 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20#include "firejail.h"
21#include <sys/stat.h>
22#define MAXBUF 4098
23
24typedef struct macro_t {
25 char *name; // macro name
26 char *xdg; // xdg line in ~/.config/user-dirs.dirs
27#define MAX_TRANSLATIONS 3 // several translations in case ~/.config/user-dirs.dirs not found
28 char *translation[MAX_TRANSLATIONS];
29} Macro;
30
31Macro macro[] = {
32 {
33 "${DOWNLOADS}",
34 "XDG_DOWNLOAD_DIR=\"$HOME/",
35 { "Downloads", "Загрузки", "Téléchargement" }
36 },
37
38 {
39 "${MUSIC}",
40 "XDG_MUSIC_DIR=\"$HOME/",
41 {"Music", "Музыка", "Musique"}
42 },
43
44 {
45 "${VIDEOS}",
46 "XDG_VIDEOS_DIR=\"$HOME/",
47 {"Videos", "Видео", "Vidéos"}
48 },
49
50 {
51 "${PICTURES}",
52 "XDG_PICTURES_DIR=\"$HOME/",
53 {"Pictures", "Изображения", "Photos"}
54 },
55
56 {
57 "${DESKTOP}",
58 "XDG_DESKTOP_DIR=\"$HOME/",
59 {"Desktop", "Рабочий стол", "Bureau"}
60 },
61
62 {
63 "${DOCUMENTS}",
64 "XDG_DOCUMENTS_DIR=\"$HOME/",
65 {"Documents", "Документы", "Documents"}
66 },
67
68 { 0 }
69};
70
71// return -1 if not found
72static int macro_id(const char *name) {
73 int i = 0;
74 while (macro[i].name != NULL) {
75 if (strcmp(name, macro[i].name) == 0)
76 return i;
77 i++;
78 }
79
80 return -1;
81}
82
83int is_macro(const char *name) {
84 assert(name);
85 int len = strlen(name);
86 if (len <= 4)
87 return 0;
88 if (*name == '$' && name[1] == '{' && name[len - 1] == '}')
89 return 1;
90 return 0;
91}
92
93// returns mallocated memory
94static char *resolve_xdg(const char *var) {
95 char *fname;
96 struct stat s;
97 size_t length = strlen(var);
98
99 if (asprintf(&fname, "%s/.config/user-dirs.dirs", cfg.homedir) == -1)
100 errExit("asprintf");
101 FILE *fp = fopen(fname, "r");
102 if (!fp) {
103 free(fname);
104 return NULL;
105 }
106 free(fname);
107
108 char buf[MAXBUF];
109 while (fgets(buf, MAXBUF, fp)) {
110 char *ptr = buf;
111
112 // skip blanks
113 while (*ptr == ' ' || *ptr == '\t')
114 ptr++;
115 if (*ptr == '\0' || *ptr == '\n' || *ptr == '#')
116 continue;
117
118 if (strncmp(ptr, var, length) == 0) {
119 char *ptr1 = ptr + length;
120 char *ptr2 = strchr(ptr1, '"');
121 if (ptr2) {
122 fclose(fp);
123 *ptr2 = '\0';
124 if (strlen(ptr1) != 0) {
125 if (asprintf(&fname, "%s/%s", cfg.homedir, ptr1) == -1)
126 errExit("asprintf");
127
128 if (stat(fname, &s) == -1) {
129 free(fname);
130 return NULL;
131 }
132 free(fname);
133
134 char *rv = strdup(ptr1);
135 if (!rv)
136 errExit(ptr1);
137 return rv;
138 }
139 else
140 return NULL;
141 }
142 }
143 }
144
145 fclose(fp);
146 return NULL;
147}
148
149// returns mallocated memory
150static char *resolve_hardcoded(char *entries[]) {
151 char *fname;
152 struct stat s;
153
154 int i = 0;
155 while (entries[i] != NULL) {
156 if (asprintf(&fname, "%s/%s", cfg.homedir, entries[i]) == -1)
157 errExit("asprintf");
158
159 if (stat(fname, &s) == 0) {
160 free(fname);
161 char *rv = strdup(entries[i]);
162 if (!rv)
163 errExit("strdup");
164 return rv;
165 }
166 free(fname);
167 i++;
168 }
169
170 return NULL;
171}
172
173// returns mallocated memory
174char *resolve_macro(const char *name) {
175 char *rv = NULL;
176 int id = macro_id(name);
177 if (id == -1)
178 return NULL;
179
180 rv = resolve_xdg(macro[id].xdg);
181 if (rv == NULL)
182 rv = resolve_hardcoded(macro[id].translation);
183 if (rv && arg_debug)
184 printf("Directory %s resolved as %s\n", name, rv);
185
186 return rv;
187}
188
189// This function takes a pathname supplied by the user and expands '~' and
190// '${HOME}' at the start, to refer to a path relative to the user's home
191// directory (supplied).
192// The return value is allocated using malloc and must be freed by the caller.
193// The function returns NULL if there are any errors.
194char *expand_home(const char *path, const char *homedir) {
195 assert(path);
196 assert(homedir);
197
198 int called_as_root = 0;
199
200 if(geteuid() == 0)
201 called_as_root = 1;
202
203 if(called_as_root) {
204 EUID_USER();
205 }
206
207 EUID_ASSERT();
208
209 // Replace home macro
210 char *new_name = NULL;
211 if (strncmp(path, "${HOME}", 7) == 0) {
212 if (asprintf(&new_name, "%s%s", homedir, path + 7) == -1)
213 errExit("asprintf");
214 if(called_as_root)
215 EUID_ROOT();
216 return new_name;
217 }
218 else if (*path == '~') {
219 if (asprintf(&new_name, "%s%s", homedir, path + 1) == -1)
220 errExit("asprintf");
221 if(called_as_root)
222 EUID_ROOT();
223 return new_name;
224 }
225 else if (strncmp(path, "${CFG}", 6) == 0) {
226 if (asprintf(&new_name, "%s%s", SYSCONFDIR, path + 6) == -1)
227 errExit("asprintf");
228 if(called_as_root)
229 EUID_ROOT();
230 return new_name;
231 }
232 else {
233 char *directory = resolve_macro(path);
234 if (directory) {
235 if (asprintf(&new_name, "%s/%s", cfg.homedir, directory) == -1)
236 errExit("asprintf");
237 if(called_as_root)
238 EUID_ROOT();
239 free(directory);
240 return new_name;
241 }
242 }
243
244 char *rv = strdup(path);
245 if (!rv)
246 errExit("strdup");
247
248 if(called_as_root)
249 EUID_ROOT();
250
251 return rv;
252}
253
254void invalid_filename(const char *fname, int globbing) {
255// EUID_ASSERT();
256 assert(fname);
257 const char *ptr = fname;
258
259 if (strncmp(ptr, "${HOME}", 7) == 0)
260 ptr = fname + 7;
261 else if (strncmp(ptr, "${PATH}", 7) == 0)
262 ptr = fname + 7;
263 else {
264 int id = macro_id(fname);
265 if (id != -1)
266 return;
267 }
268
269 int len = strlen(ptr);
270
271 if (globbing) {
272 // file globbing ('*?[]') is allowed
273 if (strcspn(ptr, "\\&!\"'<>%^(){};,") != (size_t)len) {
274 fprintf(stderr, "Error: \"%s\" is an invalid filename\n", ptr);
275 exit(1);
276 }
277 }
278 else {
279 if (strcspn(ptr, "\\&!?\"'<>%^(){};,*[]") != (size_t)len) {
280 fprintf(stderr, "Error: \"%s\" is an invalid filename\n", ptr);
281 exit(1);
282 }
283 }
284}
diff --git a/src/firejail/main.c b/src/firejail/main.c
index 891e73eda..d1f3c47c2 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -241,7 +241,10 @@ static void init_cfg(int argc, char **argv) {
241 fprintf(stderr, "Error: user %s doesn't have a user directory assigned\n", cfg.username); 241 fprintf(stderr, "Error: user %s doesn't have a user directory assigned\n", cfg.username);
242 exit(1); 242 exit(1);
243 } 243 }
244
244 cfg.cwd = getcwd(NULL, 0); 245 cfg.cwd = getcwd(NULL, 0);
246 if (!cfg.cwd && errno != ENOENT)
247 errExit("getcwd");
245 248
246 // check user database 249 // check user database
247 if (!firejail_user_check(cfg.username)) { 250 if (!firejail_user_check(cfg.username)) {
@@ -833,6 +836,7 @@ static void run_builder(int argc, char **argv) {
833 (void) argc; 836 (void) argc;
834 837
835 // drop privileges 838 // drop privileges
839 EUID_ROOT();
836 if (setgid(getgid()) < 0) 840 if (setgid(getgid()) < 0)
837 errExit("setgid/getgid"); 841 errExit("setgid/getgid");
838 if (setuid(getuid()) < 0) 842 if (setuid(getuid()) < 0)
@@ -1477,25 +1481,7 @@ int main(int argc, char **argv) {
1477 fprintf(stderr, "Error: please use --profile after --ignore\n"); 1481 fprintf(stderr, "Error: please use --profile after --ignore\n");
1478 exit(1); 1482 exit(1);
1479 } 1483 }
1480 1484 profile_add_ignore(argv[i] + 9);
1481 if (*(argv[i] + 9) == '\0') {
1482 fprintf(stderr, "Error: invalid ignore option\n");
1483 exit(1);
1484 }
1485
1486 // find an empty entry in profile_ignore array
1487 int j;
1488 for (j = 0; j < MAX_PROFILE_IGNORE; j++) {
1489 if (cfg.profile_ignore[j] == NULL)
1490 break;
1491 }
1492 if (j >= MAX_PROFILE_IGNORE) {
1493 fprintf(stderr, "Error: maximum %d --ignore options are permitted\n", MAX_PROFILE_IGNORE);
1494 exit(1);
1495 }
1496 // ... and configure it
1497 else
1498 cfg.profile_ignore[j] = argv[i] + 9;
1499 } 1485 }
1500#ifndef LTS 1486#ifndef LTS
1501#ifdef HAVE_CHROOT 1487#ifdef HAVE_CHROOT
@@ -1670,7 +1656,6 @@ int main(int argc, char **argv) {
1670 cfg.srv_private_keep = argv[i] + 14; 1656 cfg.srv_private_keep = argv[i] + 14;
1671 arg_private_srv = 1; 1657 arg_private_srv = 1;
1672 } 1658 }
1673
1674 else if (strncmp(argv[i], "--private-bin=", 14) == 0) { 1659 else if (strncmp(argv[i], "--private-bin=", 14) == 0) {
1675 // extract private bin list 1660 // extract private bin list
1676 if (*(argv[i] + 14) == '\0') { 1661 if (*(argv[i] + 14) == '\0') {
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index ab27c29a8..fb1beacd5 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -87,6 +87,31 @@ static int is_in_ignore_list(char *ptr) {
87 return 0; 87 return 0;
88} 88}
89 89
90void profile_add_ignore(const char *str) {
91 assert(str);
92 if (*str == '\0') {
93 fprintf(stderr, "Error: invalid ignore option\n");
94 exit(1);
95 }
96
97 // find an empty entry in profile_ignore array
98 int i;
99 for (i = 0; i < MAX_PROFILE_IGNORE; i++) {
100 if (cfg.profile_ignore[i] == NULL)
101 break;
102 }
103 if (i >= MAX_PROFILE_IGNORE) {
104 fprintf(stderr, "Error: maximum %d --ignore options are permitted\n", MAX_PROFILE_IGNORE);
105 exit(1);
106 }
107 // ... and configure it
108 else {
109 cfg.profile_ignore[i] = strdup(str);
110 if (!cfg.profile_ignore[i])
111 errExit("strdup");
112 }
113}
114
90 115
91// check profile line; if line == 0, this was generated from a command line option 116// check profile line; if line == 0, this was generated from a command line option
92// return 1 if the command is to be added to the linked list of profile commands 117// return 1 if the command is to be added to the linked list of profile commands
@@ -99,25 +124,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
99 return 0; 124 return 0;
100 125
101 if (strncmp(ptr, "ignore ", 7) == 0) { 126 if (strncmp(ptr, "ignore ", 7) == 0) {
102 char *str = strdup(ptr + 7); 127 profile_add_ignore(ptr + 7);
103 if (*str == '\0') {
104 fprintf(stderr, "Error: invalid ignore option\n");
105 exit(1);
106 }
107 // find an empty entry in profile_ignore array
108 int j;
109 for (j = 0; j < MAX_PROFILE_IGNORE; j++) {
110 if (cfg.profile_ignore[j] == NULL)
111 break;
112 }
113 if (j >= MAX_PROFILE_IGNORE) {
114 fprintf(stderr, "Error: maximum %d --ignore options are permitted\n", MAX_PROFILE_IGNORE);
115 exit(1);
116 }
117 // ... and configure it
118 else
119 cfg.profile_ignore[j] = str;
120
121 return 0; 128 return 0;
122 } 129 }
123 130
@@ -952,6 +959,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
952 return 0; 959 return 0;
953 } 960 }
954 961
962
955#ifdef HAVE_OVERLAYFS 963#ifdef HAVE_OVERLAYFS
956 if (strncmp(ptr, "overlay-named ", 14) == 0) { 964 if (strncmp(ptr, "overlay-named ", 14) == 0) {
957 if (checkcfg(CFG_OVERLAYFS)) { 965 if (checkcfg(CFG_OVERLAYFS)) {
diff --git a/src/firejail/run_symlink.c b/src/firejail/run_symlink.c
index 5714206d4..ec8e0f1e5 100644
--- a/src/firejail/run_symlink.c
+++ b/src/firejail/run_symlink.c
@@ -34,6 +34,7 @@ void run_symlink(int argc, char **argv, int run_as_is) {
34 return; 34 return;
35 35
36 // drop privileges 36 // drop privileges
37 EUID_ROOT();
37 if (setgid(getgid()) < 0) 38 if (setgid(getgid()) < 0)
38 errExit("setgid/getgid"); 39 errExit("setgid/getgid");
39 if (setuid(getuid()) < 0) 40 if (setuid(getuid()) < 0)
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index 2335e9ed2..deb37d700 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -250,7 +250,7 @@ static int monitor_application(pid_t app_pid) {
250 } 250 }
251 while(rv != monitored_pid); 251 while(rv != monitored_pid);
252 if (arg_debug) 252 if (arg_debug)
253 printf("Sandbox monitor: waitpid %u retval %d status %d\n", monitored_pid, rv, status); 253 printf("Sandbox monitor: waitpid %d retval %d status %d\n", monitored_pid, rv, status);
254 if (rv == -1) { // we can get here if we have processes joining the sandbox (ECHILD) 254 if (rv == -1) { // we can get here if we have processes joining the sandbox (ECHILD)
255 if (arg_debug) 255 if (arg_debug)
256 perror("waitpid"); 256 perror("waitpid");
@@ -294,7 +294,7 @@ static int monitor_application(pid_t app_pid) {
294 closedir(dir); 294 closedir(dir);
295 295
296 if (monitored_pid != 0 && arg_debug) 296 if (monitored_pid != 0 && arg_debug)
297 printf("Sandbox monitor: monitoring %u\n", monitored_pid); 297 printf("Sandbox monitor: monitoring %d\n", monitored_pid);
298 } 298 }
299 299
300 // return the latest exit status. 300 // return the latest exit status.
diff --git a/src/firejail/usage.c b/src/firejail/usage.c
index 804bfb179..78cd30926 100644
--- a/src/firejail/usage.c
+++ b/src/firejail/usage.c
@@ -255,7 +255,7 @@ static char *usage_str =
255 "\tlist all running sandboxes\n" 255 "\tlist all running sandboxes\n"
256 "\n" 256 "\n"
257 "License GPL version 2 or later\n" 257 "License GPL version 2 or later\n"
258 "Homepage: http://firejail.wordpress.com\n" 258 "Homepage: https://firejail.wordpress.com\n"
259 "\n"; 259 "\n";
260 260
261 261
diff --git a/src/firejail/util.c b/src/firejail/util.c
index fa32ffcc8..329ae141b 100644
--- a/src/firejail/util.c
+++ b/src/firejail/util.c
@@ -32,6 +32,9 @@
32#include <fcntl.h> 32#include <fcntl.h>
33 33
34#define MAX_GROUPS 1024 34#define MAX_GROUPS 1024
35#define MAXBUF 4098
36
37
35 38
36// send the error to /var/log/auth.log and exit after a small delay 39// send the error to /var/log/auth.log and exit after a small delay
37void errLogExit(char* fmt, ...) { 40void errLogExit(char* fmt, ...) {
@@ -723,38 +726,6 @@ void notify_other(int fd) {
723} 726}
724 727
725 728
726// This function takes a pathname supplied by the user and expands '~' and
727// '${HOME}' at the start, to refer to a path relative to the user's home
728// directory (supplied).
729// The return value is allocated using malloc and must be freed by the caller.
730// The function returns NULL if there are any errors.
731char *expand_home(const char *path, const char* homedir) {
732 assert(path);
733 assert(homedir);
734
735 // Replace home macro
736 char *new_name = NULL;
737 if (strncmp(path, "${HOME}", 7) == 0) {
738 if (asprintf(&new_name, "%s%s", homedir, path + 7) == -1)
739 errExit("asprintf");
740 return new_name;
741 }
742 else if (*path == '~') {
743 if (asprintf(&new_name, "%s%s", homedir, path + 1) == -1)
744 errExit("asprintf");
745 return new_name;
746 }
747 else if (strncmp(path, "${CFG}", 6) == 0) {
748 if (asprintf(&new_name, "%s%s", SYSCONFDIR, path + 6) == -1)
749 errExit("asprintf");
750 return new_name;
751 }
752
753 char *rv = strdup(path);
754 if (!rv)
755 errExit("strdup");
756 return rv;
757}
758 729
759 730
760// Equivalent to the GNU version of basename, which is incompatible with 731// Equivalent to the GNU version of basename, which is incompatible with
@@ -815,44 +786,6 @@ uid_t pid_get_uid(pid_t pid) {
815} 786}
816 787
817 788
818void invalid_filename(const char *fname, int globbing) {
819// EUID_ASSERT();
820 assert(fname);
821 const char *ptr = fname;
822
823 if (strncmp(ptr, "${HOME}", 7) == 0)
824 ptr = fname + 7;
825 else if (strncmp(ptr, "${PATH}", 7) == 0)
826 ptr = fname + 7;
827 else if (strcmp(fname, "${DOWNLOADS}") == 0)
828 return;
829 else if (strcmp(fname, "${MUSIC}") == 0)
830 return;
831 else if (strcmp(fname, "${VIDEOS}") == 0)
832 return;
833 else if (strcmp(fname, "${PICTURES}") == 0)
834 return;
835 else if (strcmp(fname, "${DESKTOP}") == 0)
836 return;
837 else if (strcmp(fname, "${DOCUMENTS}") == 0)
838 return;
839
840 int len = strlen(ptr);
841
842 if (globbing) {
843 // file globbing ('*?[]') is allowed
844 if (strcspn(ptr, "\\&!\"'<>%^(){};,") != (size_t)len) {
845 fprintf(stderr, "Error: \"%s\" is an invalid filename\n", ptr);
846 exit(1);
847 }
848 }
849 else {
850 if (strcspn(ptr, "\\&!?\"'<>%^(){};,*[]") != (size_t)len) {
851 fprintf(stderr, "Error: \"%s\" is an invalid filename\n", ptr);
852 exit(1);
853 }
854 }
855}
856 789
857 790
858uid_t get_group_id(const char *group) { 791uid_t get_group_id(const char *group) {
@@ -1059,54 +992,70 @@ void disable_file_path(const char *path, const char *file) {
1059// user controlled paths. Passed flags are ignored if path is a top level directory. 992// user controlled paths. Passed flags are ignored if path is a top level directory.
1060int safe_fd(const char *path, int flags) { 993int safe_fd(const char *path, int flags) {
1061 assert(path); 994 assert(path);
1062 int fd = -1; 995
996 // reject empty string, relative path
997 if (*path != '/')
998 goto errexit;
999 // reject ".."
1000 if (strstr(path, ".."))
1001 goto errexit;
1063 1002
1064 // work with a copy of path 1003 // work with a copy of path
1065 char *dup = strdup(path); 1004 char *dup = strdup(path);
1066 if (dup == NULL) 1005 if (dup == NULL)
1067 errExit("strdup"); 1006 errExit("strdup");
1068 // reject relative path and empty string
1069 if (*dup != '/') {
1070 fprintf(stderr, "Error: invalid pathname: %s\n", path);
1071 exit(1);
1072 }
1073 1007
1074 char *p = strrchr(dup, '/'); 1008 char *p = strrchr(dup, '/');
1075 if (p == NULL) 1009 assert(p);
1076 errExit("strrchr"); 1010 // reject trailing slash, root directory
1077 // reject trailing slash and root dir 1011 if (*(p + 1) == '\0')
1078 if (*(p + 1) == '\0') { 1012 goto errexit;
1079 fprintf(stderr, "Error: invalid pathname: %s\n", path); 1013 // reject trailing dot
1080 exit(1); 1014 if (*(p + 1) == '.' && *(p + 2) == '\0')
1081 } 1015 goto errexit;
1016 // if there is more than one path segment, keep the last one for later
1017 if (p != dup)
1018 *p = '\0';
1082 1019
1083 int parentfd = open("/", O_PATH|O_DIRECTORY|O_CLOEXEC); 1020 int parentfd = open("/", O_PATH|O_DIRECTORY|O_CLOEXEC);
1084 if (parentfd == -1) 1021 if (parentfd == -1)
1085 errExit("open"); 1022 errExit("open");
1086 1023
1087 // if there is more than one path segment, keep the last one for later 1024 // traverse the path and return -1 if a symlink is encountered
1088 if (p != dup) 1025 int entered = 0;
1089 *p = '\0'; 1026 int fd = -1;
1090
1091 // traverse the path, return -1 if a symlink is encountered
1092 char *tok = strtok(dup, "/"); 1027 char *tok = strtok(dup, "/");
1093 if (tok == NULL)
1094 errExit("strtok");
1095 while (tok) { 1028 while (tok) {
1029 // skip all "/./"
1030 if (strcmp(tok, ".") == 0) {
1031 tok = strtok(NULL, "/");
1032 continue;
1033 }
1034 entered = 1;
1035
1036 // open the directory
1096 fd = openat(parentfd, tok, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); 1037 fd = openat(parentfd, tok, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
1097 close(parentfd); 1038 close(parentfd);
1098 if (fd == -1) { 1039 if (fd == -1) {
1099 free(dup); 1040 free(dup);
1100 return -1; 1041 return -1;
1101 } 1042 }
1043
1102 parentfd = fd; 1044 parentfd = fd;
1103 tok = strtok(NULL, "/"); 1045 tok = strtok(NULL, "/");
1104 } 1046 }
1105 if (p != dup) { 1047 if (p != dup) {
1048 // consistent flags for top level directories (////foo, /.///foo)
1049 if (!entered)
1050 flags = O_PATH|O_DIRECTORY|O_CLOEXEC;
1106 // open last path segment 1051 // open last path segment
1107 fd = openat(parentfd, p + 1, flags|O_NOFOLLOW); 1052 fd = openat(parentfd, p + 1, flags|O_NOFOLLOW);
1108 close(parentfd); 1053 close(parentfd);
1109 } 1054 }
1110 free(dup); 1055 free(dup);
1111 return fd; // -1 if open failed 1056 return fd; // -1 if open failed
1057
1058errexit:
1059 fprintf(stderr, "Error: cannot open \"%s\", invalid filename\n", path);
1060 exit(1);
1112} 1061}
diff --git a/src/firemon/arp.c b/src/firemon/arp.c
index aac1aeba3..9f3e50e94 100644
--- a/src/firemon/arp.c
+++ b/src/firemon/arp.c
@@ -51,7 +51,7 @@ static void print_arp(const char *fname) {
51 char mac[64]; 51 char mac[64];
52 char mask[64]; 52 char mask[64];
53 char device[64]; 53 char device[64];
54 int rv = sscanf(start, "%s %s %s %s %s %s\n", ip, type, flags, mac, mask, device); 54 int rv = sscanf(start, "%63s %63s %63s %63s %63s %63s\n", ip, type, flags, mac, mask, device);
55 if (rv != 6) 55 if (rv != 6)
56 continue; 56 continue;
57 57
diff --git a/src/firemon/route.c b/src/firemon/route.c
index 7426637df..6db212831 100644
--- a/src/firemon/route.c
+++ b/src/firemon/route.c
@@ -144,7 +144,7 @@ static void print_route(const char *fname) {
144 char use[64]; 144 char use[64];
145 char metric[64]; 145 char metric[64];
146 char mask[64]; 146 char mask[64];
147 int rv = sscanf(start, "%s %s %s %s %s %s %s %s\n", ifname, destination, gateway, flags, refcnt, use, metric, mask); 147 int rv = sscanf(start, "%63s %63s %63s %63s %63s %63s %63s %63s\n", ifname, destination, gateway, flags, refcnt, use, metric, mask);
148 if (rv != 8) 148 if (rv != 8)
149 continue; 149 continue;
150 150
@@ -161,7 +161,7 @@ static void print_route(const char *fname) {
161 161
162// printf("#%s# #%s# #%s# #%s# #%s# #%s# #%s# #%s#\n", ifname, destination, gateway, flags, refcnt, use, metric, mask); 162// printf("#%s# #%s# #%s# #%s# #%s# #%s# #%s# #%s#\n", ifname, destination, gateway, flags, refcnt, use, metric, mask);
163 if (gw != 0) 163 if (gw != 0)
164 printf(" %u.%u.%u.%u/%u via %u.%u.%u.%u, dev %s, metric %s\n", 164 printf(" %d.%d.%d.%d/%u via %d.%d.%d.%d, dev %s, metric %s\n",
165 PRINT_IP(destip), mask2bits(destmask), 165 PRINT_IP(destip), mask2bits(destmask),
166 PRINT_IP(gw), 166 PRINT_IP(gw),
167 ifname, 167 ifname,
@@ -169,7 +169,7 @@ static void print_route(const char *fname) {
169 else { // this is an interface 169 else { // this is an interface
170 IfList *ifentry = list_find(destip, destmask); 170 IfList *ifentry = list_find(destip, destmask);
171 if (ifentry) { 171 if (ifentry) {
172 printf(" %u.%u.%u.%u/%u, dev %s, scope link src %d.%d.%d.%d\n", 172 printf(" %d.%d.%d.%d/%u, dev %s, scope link src %d.%d.%d.%d\n",
173 PRINT_IP(destip), mask2bits(destmask), 173 PRINT_IP(destip), mask2bits(destmask),
174 ifname, 174 ifname,
175 PRINT_IP(ifentry->ip)); 175 PRINT_IP(ifentry->ip));
diff --git a/src/firemon/usage.c b/src/firemon/usage.c
index a4d642d66..5714643cc 100644
--- a/src/firemon/usage.c
+++ b/src/firemon/usage.c
@@ -75,7 +75,7 @@ static char *help_str =
75 "\tUser - The owner of the sandbox.\n" 75 "\tUser - The owner of the sandbox.\n"
76 "\n" 76 "\n"
77 "License GPL version 2 or later\n" 77 "License GPL version 2 or later\n"
78 "Homepage: http://firejail.wordpress.com\n" 78 "Homepage: https://firejail.wordpress.com\n"
79 "\n"; 79 "\n";
80 80
81void usage(void) { 81void usage(void) {
diff --git a/src/fnet/veth.c b/src/fnet/veth.c
index 39a4f35d8..e4d3db21a 100644
--- a/src/fnet/veth.c
+++ b/src/fnet/veth.c
@@ -3,10 +3,10 @@
3 * Original source code: 3 * Original source code:
4 * 4 *
5 * Information: 5 * Information:
6 * http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2 6 * https://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2
7 * 7 *
8 * Download: 8 * Download:
9 * http://www.kernel.org/pub/linux/utils/net/iproute2/ 9 * https://www.kernel.org/pub/linux/utils/net/iproute2/
10 * 10 *
11 * Repository: 11 * Repository:
12 * git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git 12 * git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git
diff --git a/src/fnetfilter/main.c b/src/fnetfilter/main.c
index ba58ba3c9..34ebf5926 100644
--- a/src/fnetfilter/main.c
+++ b/src/fnetfilter/main.c
@@ -79,13 +79,17 @@ static void process_template(char *src, const char *dest) {
79 *arg_start = '\0'; 79 *arg_start = '\0';
80 arg_start++; 80 arg_start++;
81 if (*arg_start == '\0') { 81 if (*arg_start == '\0') {
82 fprintf(stderr, "Error fnetfilter: you need to provide at least on argument\n"); 82 fprintf(stderr, "Error fnetfilter: you need to provide at least one argument\n");
83 exit(1); 83 exit(1);
84 } 84 }
85 85
86 // extract the arguments from command line 86 // extract the arguments from command line
87 char *token = strtok(arg_start, ","); 87 char *token = strtok(arg_start, ",");
88 while (token) { 88 while (token) {
89 if (argcnt == MAXARGS) {
90 fprintf(stderr, "Error fnetfilter: only up to %u arguments are supported\n", (unsigned) MAXARGS);
91 exit(1);
92 }
89 // look for abnormal things 93 // look for abnormal things
90 int len = strlen(token); 94 int len = strlen(token);
91 if (strcspn(token, "\\&!?\"'<>%^(){};,*[]") != (size_t)len) { 95 if (strcspn(token, "\\&!?\"'<>%^(){};,*[]") != (size_t)len) {
@@ -125,7 +129,7 @@ for (i = 0; i < argcnt; i++)
125 else { 129 else {
126 // parsing 130 // parsing
127 int index = 0; 131 int index = 0;
128 int rv = sscanf(ptr, "$ARG%u", &index) ; 132 int rv = sscanf(ptr, "$ARG%d", &index) ;
129 if (rv != 1) { 133 if (rv != 1) {
130 fprintf(stderr, "Error fnetfilter: invalid template argument on line %d\n", line); 134 fprintf(stderr, "Error fnetfilter: invalid template argument on line %d\n", line);
131 exit(1); 135 exit(1);
diff --git a/src/fsec-print/print.c b/src/fsec-print/print.c
index faf59aa35..1042f0c3e 100644
--- a/src/fsec-print/print.c
+++ b/src/fsec-print/print.c
@@ -39,7 +39,7 @@
39 * for more details. 39 * for more details.
40 * 40 *
41 * You should have received a copy of the GNU Lesser General Public License 41 * You should have received a copy of the GNU Lesser General Public License
42 * along with this library; if not, see <http://www.gnu.org/licenses>. 42 * along with this library; if not, see <https://www.gnu.org/licenses>.
43 */ 43 */
44 44
45#include "fsec_print.h" 45#include "fsec_print.h"
diff --git a/src/include/libnetlink.h b/src/include/libnetlink.h
index 01fd2675d..0310ecad3 100644
--- a/src/include/libnetlink.h
+++ b/src/include/libnetlink.h
@@ -3,10 +3,10 @@
3 * Original source code: 3 * Original source code:
4 * 4 *
5 * Information: 5 * Information:
6 * http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2 6 * https://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2
7 * 7 *
8 * Download: 8 * Download:
9 * http://www.kernel.org/pub/linux/utils/net/iproute2/ 9 * https://www.kernel.org/pub/linux/utils/net/iproute2/
10 * 10 *
11 * Repository: 11 * Repository:
12 * git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git 12 * git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git
diff --git a/src/lib/libnetlink.c b/src/lib/libnetlink.c
index d2975bd57..5f6ecd95c 100644
--- a/src/lib/libnetlink.c
+++ b/src/lib/libnetlink.c
@@ -3,10 +3,10 @@
3 * Original source code: 3 * Original source code:
4 * 4 *
5 * Information: 5 * Information:
6 * http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2 6 * https://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2
7 * 7 *
8 * Download: 8 * Download:
9 * http://www.kernel.org/pub/linux/utils/net/iproute2/ 9 * https://www.kernel.org/pub/linux/utils/net/iproute2/
10 * 10 *
11 * Repository: 11 * Repository:
12 * git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git 12 * git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git
diff --git a/src/libtracelog/libtracelog.c b/src/libtracelog/libtracelog.c
index 5ce41aca0..0f8d5a00d 100644
--- a/src/libtracelog/libtracelog.c
+++ b/src/libtracelog/libtracelog.c
@@ -64,9 +64,6 @@ static inline uint32_t hash(const char *str) {
64} 64}
65 65
66static void storage_add(const char *str) { 66static void storage_add(const char *str) {
67#ifdef DEBUG
68 printf("add %s\n", str);
69#endif
70 if (!str) { 67 if (!str) {
71#ifdef DEBUG 68#ifdef DEBUG
72 printf("null pointer passed to storage_add\n"); 69 printf("null pointer passed to storage_add\n");
@@ -74,6 +71,10 @@ static void storage_add(const char *str) {
74 return; 71 return;
75 } 72 }
76 73
74#ifdef DEBUG
75 printf("add %s\n", str);
76#endif
77
77 ListElem *ptr = malloc(sizeof(ListElem)); 78 ListElem *ptr = malloc(sizeof(ListElem));
78 if (!ptr) { 79 if (!ptr) {
79 fprintf(stderr, "Error: cannot allocate memory\n"); 80 fprintf(stderr, "Error: cannot allocate memory\n");
@@ -96,15 +97,17 @@ static void storage_add(const char *str) {
96static char* cwd = NULL; 97static char* cwd = NULL;
97 98
98static char *storage_find(const char *str) { 99static char *storage_find(const char *str) {
99#ifdef DEBUG
100 printf("storage find %s\n", str);
101#endif
102 if (!str) { 100 if (!str) {
103#ifdef DEBUG 101#ifdef DEBUG
104 printf("null pointer passed to storage_find\n"); 102 printf("null pointer passed to storage_find\n");
105#endif 103#endif
106 return NULL; 104 return NULL;
107 } 105 }
106
107#ifdef DEBUG
108 printf("storage find %s\n", str);
109#endif
110
108 const char *tofind = str; 111 const char *tofind = str;
109 int allocated = 0; 112 int allocated = 0;
110 113