diff options
Diffstat (limited to 'src/firejail/no_sandbox.c')
-rw-r--r-- | src/firejail/no_sandbox.c | 217 |
1 files changed, 181 insertions, 36 deletions
diff --git a/src/firejail/no_sandbox.c b/src/firejail/no_sandbox.c index a9242f035..aae490c34 100644 --- a/src/firejail/no_sandbox.c +++ b/src/firejail/no_sandbox.c | |||
@@ -23,6 +23,65 @@ | |||
23 | #include <unistd.h> | 23 | #include <unistd.h> |
24 | #include <grp.h> | 24 | #include <grp.h> |
25 | 25 | ||
26 | #define MAX_BUF 4096 | ||
27 | |||
28 | int is_container(const char *str) { | ||
29 | assert(str); | ||
30 | if (strcmp(str, "lxc") == 0 || | ||
31 | strcmp(str, "docker") == 0 || | ||
32 | strcmp(str, "lxc-libvirt") == 0 || | ||
33 | strcmp(str, "systemd-nspawn") == 0 || | ||
34 | strcmp(str, "rkt") == 0) | ||
35 | return 1; | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | // returns 1 if we are running under LXC | ||
40 | int check_namespace_virt(void) { | ||
41 | EUID_ASSERT(); | ||
42 | |||
43 | // check container environment variable | ||
44 | char *str = getenv("container"); | ||
45 | if (str && is_container(str)) | ||
46 | return 1; | ||
47 | |||
48 | // check PID 1 container environment variable | ||
49 | EUID_ROOT(); | ||
50 | FILE *fp = fopen("/proc/1/environ", "r"); | ||
51 | if (fp) { | ||
52 | int c = 0; | ||
53 | while (c != EOF) { | ||
54 | // read one line | ||
55 | char buf[MAX_BUF]; | ||
56 | int i = 0; | ||
57 | while ((c = fgetc(fp)) != EOF) { | ||
58 | if (c == 0) | ||
59 | break; | ||
60 | buf[i] = (char) c; | ||
61 | if (++i == (MAX_BUF - 1)) | ||
62 | break; | ||
63 | } | ||
64 | buf[i] = '\0'; | ||
65 | |||
66 | // check env var name | ||
67 | if (strncmp(buf, "container=", 10) == 0) { | ||
68 | // found it | ||
69 | if (is_container(buf + 10)) { | ||
70 | fclose(fp); | ||
71 | EUID_USER(); | ||
72 | return 1; | ||
73 | } | ||
74 | } | ||
75 | // printf("i %d c %d, buf #%s#\n", i, c, buf); | ||
76 | } | ||
77 | |||
78 | fclose(fp); | ||
79 | } | ||
80 | |||
81 | EUID_USER(); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
26 | // check process space for kernel processes | 85 | // check process space for kernel processes |
27 | // return 1 if found, 0 if not found | 86 | // return 1 if found, 0 if not found |
28 | int check_kernel_procs(void) { | 87 | int check_kernel_procs(void) { |
@@ -103,44 +162,130 @@ int check_kernel_procs(void) { | |||
103 | void run_no_sandbox(int argc, char **argv) { | 162 | void run_no_sandbox(int argc, char **argv) { |
104 | EUID_ASSERT(); | 163 | EUID_ASSERT(); |
105 | 164 | ||
106 | // build command | 165 | // process limited subset of options |
107 | char *command = NULL; | 166 | int i; |
108 | int allocated = 0; | 167 | for (i = 0; i < argc; i++) { |
109 | if (argc == 1) | 168 | if (strcmp(argv[i], "--csh") == 0) { |
110 | command = "/bin/bash"; | 169 | if (arg_shell_none) { |
111 | else { | 170 | fprintf(stderr, "Error: --shell=none was already specified.\n"); |
112 | // calculate length | 171 | exit(1); |
113 | int len = 0; | 172 | } |
114 | int i; | 173 | if (cfg.shell) { |
115 | for (i = 1; i < argc; i++) { | 174 | fprintf(stderr, "Error: only one default user shell can be specified\n"); |
116 | if (*argv[i] == '-') | 175 | exit(1); |
117 | continue; | 176 | } |
177 | cfg.shell = "/bin/csh"; | ||
178 | } | ||
179 | else if (strcmp(argv[i], "--zsh") == 0) { | ||
180 | if (arg_shell_none) { | ||
181 | fprintf(stderr, "Error: --shell=none was already specified.\n"); | ||
182 | exit(1); | ||
183 | } | ||
184 | if (cfg.shell) { | ||
185 | fprintf(stderr, "Error: only one default user shell can be specified\n"); | ||
186 | exit(1); | ||
187 | } | ||
188 | cfg.shell = "/bin/zsh"; | ||
189 | } | ||
190 | else if (strcmp(argv[i], "--shell=none") == 0) { | ||
191 | arg_shell_none = 1; | ||
192 | if (cfg.shell) { | ||
193 | fprintf(stderr, "Error: a shell was already specified\n"); | ||
194 | exit(1); | ||
195 | } | ||
196 | } | ||
197 | else if (strncmp(argv[i], "--shell=", 8) == 0) { | ||
198 | if (arg_shell_none) { | ||
199 | fprintf(stderr, "Error: --shell=none was already specified.\n"); | ||
200 | exit(1); | ||
201 | } | ||
202 | invalid_filename(argv[i] + 8); | ||
203 | |||
204 | if (cfg.shell) { | ||
205 | fprintf(stderr, "Error: only one user shell can be specified\n"); | ||
206 | exit(1); | ||
207 | } | ||
208 | cfg.shell = argv[i] + 8; | ||
209 | |||
210 | if (is_dir(cfg.shell) || strstr(cfg.shell, "..")) { | ||
211 | fprintf(stderr, "Error: invalid shell\n"); | ||
212 | exit(1); | ||
213 | } | ||
214 | |||
215 | // access call checks as real UID/GID, not as effective UID/GID | ||
216 | if(cfg.chrootdir) { | ||
217 | char *shellpath; | ||
218 | if (asprintf(&shellpath, "%s%s", cfg.chrootdir, cfg.shell) == -1) | ||
219 | errExit("asprintf"); | ||
220 | if (access(shellpath, R_OK)) { | ||
221 | fprintf(stderr, "Error: cannot access shell file in chroot\n"); | ||
222 | exit(1); | ||
223 | } | ||
224 | free(shellpath); | ||
225 | } else if (access(cfg.shell, R_OK)) { | ||
226 | fprintf(stderr, "Error: cannot access shell file\n"); | ||
227 | exit(1); | ||
228 | } | ||
229 | } | ||
230 | } | ||
231 | |||
232 | // use $SHELL to get shell used in sandbox | ||
233 | if (!arg_shell_none && !cfg.shell) { | ||
234 | char *shell = getenv("SHELL"); | ||
235 | if (access(shell, R_OK) == 0) | ||
236 | cfg.shell = shell; | ||
237 | } | ||
238 | // guess shell otherwise | ||
239 | if (!arg_shell_none && !cfg.shell) { | ||
240 | cfg.shell = guess_shell(); | ||
241 | if (arg_debug) | ||
242 | printf("Autoselecting %s as shell\n", cfg.shell); | ||
243 | } | ||
244 | if (!arg_shell_none && !cfg.shell) { | ||
245 | fprintf(stderr, "Error: unable to guess your shell, please set explicitly by using --shell option.\n"); | ||
246 | exit(1); | ||
247 | } | ||
248 | |||
249 | int prog_index = 0; | ||
250 | // find first non option arg: | ||
251 | // - first argument not starting wiht --, | ||
252 | // - whatever follows after -c (example: firejail -c ls) | ||
253 | for (i = 1; i < argc; i++) { | ||
254 | if (strcmp(argv[i], "-c") == 0) { | ||
255 | prog_index = i + 1; | ||
256 | if (prog_index == argc) { | ||
257 | fprintf(stderr, "Error: option -c requires an argument\n"); | ||
258 | exit(1); | ||
259 | } | ||
118 | break; | 260 | break; |
119 | } | 261 | } |
120 | int start_index = i; | 262 | // check first argument not starting with -- |
121 | for (i = start_index; i < argc; i++) | 263 | if (strncmp(argv[i],"--",2) != 0) { |
122 | len += strlen(argv[i]) + 1; | 264 | prog_index = i; |
123 | 265 | break; | |
124 | // allocate | ||
125 | command = malloc(len + 1); | ||
126 | if (!command) | ||
127 | errExit("malloc"); | ||
128 | memset(command, 0, len + 1); | ||
129 | allocated = 1; | ||
130 | |||
131 | // copy | ||
132 | for (i = start_index; i < argc; i++) { | ||
133 | strcat(command, argv[i]); | ||
134 | strcat(command, " "); | ||
135 | } | 266 | } |
136 | } | 267 | } |
137 | 268 | ||
138 | // start the program in /bin/sh | 269 | if (!arg_shell_none) { |
139 | fprintf(stderr, "Warning: an existing sandbox was detected. " | 270 | if (prog_index == 0) { |
140 | "%s will run without any additional sandboxing features in a /bin/sh shell\n", command); | 271 | cfg.command_line = cfg.shell; |
141 | int rv = system(command); | 272 | cfg.window_title = cfg.shell; |
142 | (void) rv; | 273 | } else { |
143 | if (allocated) | 274 | build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index); |
144 | free(command); | 275 | } |
145 | exit(1); | 276 | } |
277 | |||
278 | cfg.original_argv = argv; | ||
279 | cfg.original_program_index = prog_index; | ||
280 | |||
281 | char *command; | ||
282 | if (prog_index == 0) | ||
283 | command = cfg.shell; | ||
284 | else | ||
285 | command = argv[prog_index]; | ||
286 | if (!arg_quiet) | ||
287 | fprintf(stderr, "Warning: an existing sandbox was detected. " | ||
288 | "%s will run without any additional sandboxing features\n", command); | ||
289 | |||
290 | start_application(); | ||
146 | } | 291 | } |