aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/firejail/cmdline.c151
-rw-r--r--src/firejail/fs_mkdir.c39
-rw-r--r--src/firejail/join.c24
-rw-r--r--src/firejail/main.c104
-rw-r--r--src/libtrace/libtrace.c29
-rw-r--r--src/libtracelog/libtracelog.c4
-rw-r--r--src/man/firejail-profile.txt8
7 files changed, 219 insertions, 140 deletions
diff --git a/src/firejail/cmdline.c b/src/firejail/cmdline.c
new file mode 100644
index 000000000..517124d9e
--- /dev/null
+++ b/src/firejail/cmdline.c
@@ -0,0 +1,151 @@
1/*
2 * Copyright (C) 2014-2016 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
21#include "firejail.h"
22#include <string.h>
23#include <stdbool.h>
24#include <stdio.h>
25#include <linux/limits.h>
26#include <assert.h>
27#include <errno.h>
28
29int cmdline_length(int argc, char **argv, int index) {
30 int i,j;
31 int len = 0;
32 int argcnt = argc - index;
33 bool in_quotes = false;
34
35 for (i = 0; i < argcnt; i++) {
36 in_quotes = false;
37 for (j = 0; j < strlen(argv[i + index]); j++) {
38 if (argv[i + index][j] == '\'') {
39 if (in_quotes)
40 len++;
41 if (j > 0 && argv[i + index][j-1] == '\'')
42 len++;
43 else
44 len += 3;
45 in_quotes = false;
46 } else {
47 if (!in_quotes)
48 len++;
49 len++;
50 in_quotes = true;
51 }
52 }
53 if (in_quotes) {
54 len++;
55 }
56 if (strlen(argv[i + index]) == 0) {
57 len += 2;
58 }
59 len++;
60 }
61
62 return len;
63}
64
65void quote_cmdline(char *command_line, char *window_title, int len, int argc, char **argv, int index) {
66 int i,j;
67 int argcnt = argc - index;
68 bool in_quotes = false;
69 char *ptr1 = command_line;
70 char *ptr2 = window_title;
71
72 for (i = 0; i < argcnt; i++) {
73
74 // enclose args by single quotes,
75 // and since single quote can't be represented in single quoted text
76 // each occurence of it should be enclosed by double quotes
77 in_quotes = false;
78 for (j = 0; j < strlen(argv[i + index]); j++) {
79 // single quote
80 if (argv[i + index][j] == '\'') {
81 if (in_quotes) {
82 // close quotes
83 ptr1[0] = '\'';
84 ptr1++;
85 }
86 // previous char was single quote too
87 if (j > 0 && argv[i + index][j-1] == '\'') {
88 ptr1--;
89 sprintf(ptr1, "\'\"");
90 }
91 // this first in series
92 else
93 {
94 sprintf(ptr1, "\"\'\"");
95 }
96 ptr1 += strlen(ptr1);
97 in_quotes = false;
98 }
99 // anything other
100 else
101 {
102 if (!in_quotes) {
103 // open quotes
104 ptr1[0] = '\'';
105 ptr1++;
106 }
107 ptr1[0] = argv[i + index][j];
108 ptr1++;
109 in_quotes = true;
110 }
111 }
112 // close quotes
113 if (in_quotes) {
114 ptr1[0] = '\'';
115 ptr1++;
116 }
117 // handle empty argument case
118 if (strlen(argv[i + index]) == 0) {
119 sprintf(ptr1, "\'\'");
120 ptr1 += strlen(ptr1);
121 }
122 // add space
123 sprintf(ptr1, " ");
124 ptr1 += strlen(ptr1);
125
126 sprintf(ptr2, "%s ", argv[i + index]);
127 ptr2 += strlen(ptr2);
128 }
129
130 assert(len == strlen(command_line));
131}
132
133void build_cmdline(char **command_line, char **window_title, int argc, char **argv, int index) {
134 int len = cmdline_length(argc, argv, index);
135 if (len > ARG_MAX) {
136 errno = E2BIG;
137 errExit("cmdline_length");
138 }
139
140 *command_line = malloc(len + 1);
141 if (!*command_line)
142 errExit("malloc");
143 *window_title = malloc(len + 1);
144 if (!*window_title)
145 errExit("malloc");
146
147 quote_cmdline(*command_line, *window_title, len, argc, argv, index);
148
149 assert(*command_line);
150 assert(*window_title);
151}
diff --git a/src/firejail/fs_mkdir.c b/src/firejail/fs_mkdir.c
index 50bcc613b..5bc2df2cc 100644
--- a/src/firejail/fs_mkdir.c
+++ b/src/firejail/fs_mkdir.c
@@ -22,8 +22,38 @@
22#include <sys/stat.h> 22#include <sys/stat.h>
23#include <unistd.h> 23#include <unistd.h>
24#include <grp.h> 24#include <grp.h>
25 #include <sys/wait.h> 25#include <sys/wait.h>
26 26#include <string.h>
27
28static void mkdir_recursive(char *path) {
29 char *subdir = NULL;
30 struct stat s;
31
32 if (chdir("/")) {
33 fprintf(stderr, "Error: can't chdir to /");
34 return;
35 }
36
37 subdir = strtok(path, "/");
38 while(subdir) {
39 if (stat(subdir, &s) == -1) {
40 if (mkdir(subdir, 0700) == -1) {
41 fprintf(stderr, "Warning: cannot create %s directory\n", subdir);
42 return;
43 }
44 } else if (!S_ISDIR(s.st_mode)) {
45 fprintf(stderr, "Warning: '%s' exists, but is no directory\n", subdir);
46 return;
47 }
48 if (chdir(subdir)) {
49 fprintf(stderr, "Error: can't chdir to %s", subdir);
50 return;
51 }
52
53 subdir = strtok(NULL, "/");
54 }
55}
56
27void fs_mkdir(const char *name) { 57void fs_mkdir(const char *name) {
28 EUID_ASSERT(); 58 EUID_ASSERT();
29 59
@@ -50,8 +80,7 @@ void fs_mkdir(const char *name) {
50 drop_privs(0); 80 drop_privs(0);
51 81
52 // create directory 82 // create directory
53 if (mkdir(expanded, 0700) == -1) 83 mkdir_recursive(expanded);
54 fprintf(stderr, "Warning: cannot create %s directory\n", expanded);
55 exit(0); 84 exit(0);
56 } 85 }
57 // wait for the child to finish 86 // wait for the child to finish
@@ -101,4 +130,4 @@ void fs_mkfile(const char *name) {
101 130
102doexit: 131doexit:
103 free(expanded); 132 free(expanded);
104} \ No newline at end of file 133}
diff --git a/src/firejail/join.c b/src/firejail/join.c
index c14108986..0b5b6a34a 100644
--- a/src/firejail/join.c
+++ b/src/firejail/join.c
@@ -49,29 +49,9 @@ static void extract_command(int argc, char **argv, int index) {
49 exit(1); 49 exit(1);
50 } 50 }
51 51
52
53 int len = 0;
54 int i;
55 // calculate command length
56 for (i = index; i < argc; i++) {
57 len += strlen(argv[i]) + 3;
58 }
59 assert(len > 0);
60
61 // build command 52 // build command
62 cfg.command_line = malloc(len + 1); 53 build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, index);
63 *cfg.command_line = '\0'; 54
64 for (i = index; i < argc; i++) {
65 if (strchr(argv[i], '&')) {
66 strcat(cfg.command_line, "\'");
67 strcat(cfg.command_line, argv[i]);
68 strcat(cfg.command_line, "\' ");
69 }
70 else {
71 strcat(cfg.command_line, argv[i]);
72 strcat(cfg.command_line, " ");
73 }
74 }
75 if (arg_debug) 55 if (arg_debug)
76 printf("Extracted command #%s#\n", cfg.command_line); 56 printf("Extracted command #%s#\n", cfg.command_line);
77} 57}
diff --git a/src/firejail/main.c b/src/firejail/main.c
index cbc3d57cf..e86d78ff1 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -2004,109 +2004,7 @@ int main(int argc, char **argv) {
2004 cfg.window_title = "appimage"; 2004 cfg.window_title = "appimage";
2005 } 2005 }
2006 else { 2006 else {
2007 // calculate the length of the command 2007 build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index);
2008 int i;
2009 int len = 0;
2010 int argcnt = argc - prog_index;
2011 int j;
2012 bool in_quotes = false;
2013
2014 for (i = 0; i < argcnt; i++) {
2015 in_quotes = false;
2016 for (j = 0; j < strlen(argv[i + prog_index]); j++) {
2017 if (argv[i + prog_index][j] == '\'') {
2018 if (in_quotes)
2019 len++;
2020 if (j > 0 && argv[i + prog_index][j-1] == '\'')
2021 len++;
2022 else
2023 len += 3;
2024 in_quotes = false;
2025 } else {
2026 if (!in_quotes)
2027 len++;
2028 len++;
2029 in_quotes = true;
2030 }
2031 }
2032 if (in_quotes) {
2033 len++;
2034 }
2035 if (strlen(argv[i + prog_index]) == 0) {
2036 len += 2;
2037 }
2038 len++;
2039 }
2040
2041 // build the string
2042 cfg.command_line = malloc(len + 1); // + '\0'
2043 if (!cfg.command_line)
2044 errExit("malloc");
2045 cfg.window_title = malloc(len + 1); // + '\0'
2046 if (!cfg.window_title)
2047 errExit("malloc");
2048
2049 char *ptr1 = cfg.command_line;
2050 char *ptr2 = cfg.window_title;
2051 for (i = 0; i < argcnt; i++) {
2052
2053 // enclose args by single quotes,
2054 // and since single quote can't be represented in single quoted text
2055 // each occurence of it should be enclosed by double quotes
2056 in_quotes = false;
2057 for (j = 0; j < strlen(argv[i + prog_index]); j++) {
2058 // single quote
2059 if (argv[i + prog_index][j] == '\'') {
2060 if (in_quotes) {
2061 // close quotes
2062 ptr1[0] = '\'';
2063 ptr1++;
2064 }
2065 // previous char was single quote too
2066 if (j > 0 && argv[i + prog_index][j-1] == '\'') {
2067 ptr1--;
2068 sprintf(ptr1, "\'\"");
2069 }
2070 // this first in series
2071 else
2072 {
2073 sprintf(ptr1, "\"\'\"");
2074 }
2075 ptr1 += strlen(ptr1);
2076 in_quotes = false;
2077 }
2078 // anything other
2079 else
2080 {
2081 if (!in_quotes) {
2082 // open quotes
2083 ptr1[0] = '\'';
2084 ptr1++;
2085 }
2086 ptr1[0] = argv[i + prog_index][j];
2087 ptr1++;
2088 in_quotes = true;
2089 }
2090 }
2091 // close quotes
2092 if (in_quotes) {
2093 ptr1[0] = '\'';
2094 ptr1++;
2095 }
2096 // handle empty argument case
2097 if (strlen(argv[i + prog_index]) == 0) {
2098 sprintf(ptr1, "\'\'");
2099 ptr1 += strlen(ptr1);
2100 }
2101 // add space
2102 sprintf(ptr1, " ");
2103 ptr1 += strlen(ptr1);
2104
2105 sprintf(ptr2, "%s ", argv[i + prog_index]);
2106 ptr2 += strlen(ptr2);
2107 }
2108
2109 assert(len == strlen(cfg.command_line));
2110 } 2008 }
2111 2009
2112 assert(cfg.command_name); 2010 assert(cfg.command_name);
diff --git a/src/libtrace/libtrace.c b/src/libtrace/libtrace.c
index a3d1571f7..dde3df2ea 100644
--- a/src/libtrace/libtrace.c
+++ b/src/libtrace/libtrace.c
@@ -423,11 +423,36 @@ int stat(const char *pathname, struct stat *buf) {
423typedef int (*orig_stat64_t)(const char *pathname, struct stat64 *buf); 423typedef int (*orig_stat64_t)(const char *pathname, struct stat64 *buf);
424static orig_stat64_t orig_stat64 = NULL; 424static orig_stat64_t orig_stat64 = NULL;
425int stat64(const char *pathname, struct stat64 *buf) { 425int stat64(const char *pathname, struct stat64 *buf) {
426 if (!orig_stat) 426 if (!orig_stat64)
427 orig_stat64 = (orig_stat64_t)dlsym(RTLD_NEXT, "stat64"); 427 orig_stat64 = (orig_stat64_t)dlsym(RTLD_NEXT, "stat64");
428 428
429 int rv = orig_stat64(pathname, buf); 429 int rv = orig_stat64(pathname, buf);
430 printf("%u:%s:stat %s:%d\n", pid(), name(), pathname, rv); 430 printf("%u:%s:stat64 %s:%d\n", pid(), name(), pathname, rv);
431 return rv;
432}
433#endif /* __GLIBC__ */
434
435// lstat
436typedef int (*orig_lstat_t)(const char *pathname, struct stat *buf);
437static orig_lstat_t orig_lstat = NULL;
438int lstat(const char *pathname, struct stat *buf) {
439 if (!orig_lstat)
440 orig_lstat = (orig_lstat_t)dlsym(RTLD_NEXT, "lstat");
441
442 int rv = orig_lstat(pathname, buf);
443 printf("%u:%s:lstat %s:%d\n", pid(), name(), pathname, rv);
444 return rv;
445}
446
447#ifdef __GLIBC__
448typedef int (*orig_lstat64_t)(const char *pathname, struct stat64 *buf);
449static orig_lstat64_t orig_lstat64 = NULL;
450int lstat64(const char *pathname, struct stat64 *buf) {
451 if (!orig_lstat64)
452 orig_lstat64 = (orig_lstat64_t)dlsym(RTLD_NEXT, "lstat64");
453
454 int rv = orig_lstat64(pathname, buf);
455 printf("%u:%s:lstat64 %s:%d\n", pid(), name(), pathname, rv);
431 return rv; 456 return rv;
432} 457}
433#endif /* __GLIBC__ */ 458#endif /* __GLIBC__ */
diff --git a/src/libtracelog/libtracelog.c b/src/libtracelog/libtracelog.c
index 3e65587c4..dedba5513 100644
--- a/src/libtracelog/libtracelog.c
+++ b/src/libtracelog/libtracelog.c
@@ -562,7 +562,7 @@ int stat64(const char *pathname, struct stat64 *buf) {
562#ifdef DEBUG 562#ifdef DEBUG
563 printf("%s %s\n", __FUNCTION__, pathname); 563 printf("%s %s\n", __FUNCTION__, pathname);
564#endif 564#endif
565 if (!orig_stat) 565 if (!orig_stat64)
566 orig_stat64 = (orig_stat64_t)dlsym(RTLD_NEXT, "stat64"); 566 orig_stat64 = (orig_stat64_t)dlsym(RTLD_NEXT, "stat64");
567 if (!blacklist_loaded) 567 if (!blacklist_loaded)
568 load_blacklist(); 568 load_blacklist();
@@ -598,7 +598,7 @@ int lstat64(const char *pathname, struct stat64 *buf) {
598#ifdef DEBUG 598#ifdef DEBUG
599 printf("%s %s\n", __FUNCTION__, pathname); 599 printf("%s %s\n", __FUNCTION__, pathname);
600#endif 600#endif
601 if (!orig_lstat) 601 if (!orig_lstat64)
602 orig_lstat64 = (orig_lstat64_t)dlsym(RTLD_NEXT, "lstat64"); 602 orig_lstat64 = (orig_lstat64_t)dlsym(RTLD_NEXT, "lstat64");
603 if (!blacklist_loaded) 603 if (!blacklist_loaded)
604 load_blacklist(); 604 load_blacklist();
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt
index 504842a9e..7e33a6b45 100644
--- a/src/man/firejail-profile.txt
+++ b/src/man/firejail-profile.txt
@@ -136,7 +136,7 @@ The directory is created if it doesn't already exist.
136.br 136.br
137Use this command for whitelisted directories you need to preserve 137Use this command for whitelisted directories you need to preserve
138when the sandbox is closed. Without it, the application will create the directory, and the directory 138when the sandbox is closed. Without it, the application will create the directory, and the directory
139will be deleted when the sandbox is closed. Subdirectories also need to be created using mkdir. Example from 139will be deleted when the sandbox is closed. Subdirectories are recursively created. Example from
140firefox profile: 140firefox profile:
141.br 141.br
142 142
@@ -145,17 +145,13 @@ mkdir ~/.mozilla
145.br 145.br
146whitelist ~/.mozilla 146whitelist ~/.mozilla
147.br 147.br
148mkdir ~/.cache
149.br
150mkdir ~/.cache/mozilla
151.br
152mkdir ~/.cache/mozilla/firefox 148mkdir ~/.cache/mozilla/firefox
153.br 149.br
154whitelist ~/.cache/mozilla/firefox 150whitelist ~/.cache/mozilla/firefox
155.TP 151.TP
156\fBmkfile file 152\fBmkfile file
157Similar to mkdir, this command creates a file in user home before the sandbox is started. 153Similar to mkdir, this command creates a file in user home before the sandbox is started.
158The file is created if it doesn't already exist. 154The file is created if it doesn't already exist, but it's target directory has to exist.
159.TP 155.TP
160\fBnoexec file_or_directory 156\fBnoexec file_or_directory
161Remount the file or the directory noexec, nodev and nosuid. 157Remount the file or the directory noexec, nodev and nosuid.