aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@protonmail.com>2020-08-22 06:40:05 -0500
committerLibravatar GitHub <noreply@github.com>2020-08-22 06:40:05 -0500
commitedce6a825467cc09f266010d0f624cdf4f054fa4 (patch)
tree1e1919529a764b593e68f2246573e1c9031ad953
parentrenamed /etc/apparmor.d/local/firejail-local to /etc/apparmor.d/local/firejai... (diff)
parentharden cat option (diff)
downloadfirejail-edce6a825467cc09f266010d0f624cdf4f054fa4.tar.gz
firejail-edce6a825467cc09f266010d0f624cdf4f054fa4.tar.zst
firejail-edce6a825467cc09f266010d0f624cdf4f054fa4.zip
Merge pull request #3594 from smitsohu/ls
cat option
-rw-r--r--src/firejail/firejail.h3
-rw-r--r--src/firejail/ls.c169
-rw-r--r--src/firejail/main.c31
-rw-r--r--src/firejail/sandbox.c40
-rw-r--r--src/firejail/usage.c3
-rw-r--r--src/man/firejail.txt20
6 files changed, 174 insertions, 92 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index c98f80d13..49d19e33d 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -728,10 +728,13 @@ void x11_xorg(void);
728// ls.c 728// ls.c
729enum { 729enum {
730 SANDBOX_FS_LS = 0, 730 SANDBOX_FS_LS = 0,
731 SANDBOX_FS_CAT,
731 SANDBOX_FS_GET, 732 SANDBOX_FS_GET,
732 SANDBOX_FS_PUT, 733 SANDBOX_FS_PUT,
733 SANDBOX_FS_MAX // this should always be the last entry 734 SANDBOX_FS_MAX // this should always be the last entry
734}; 735};
736void ls(const char *path);
737void cat(const char *path);
735void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) __attribute__((noreturn)); 738void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) __attribute__((noreturn));
736 739
737// checkcfg.c 740// checkcfg.c
diff --git a/src/firejail/ls.c b/src/firejail/ls.c
index aa33d838b..4d0a001b6 100644
--- a/src/firejail/ls.c
+++ b/src/firejail/ls.c
@@ -34,18 +34,12 @@
34static uid_t c_uid = 0; 34static uid_t c_uid = 0;
35static char *c_uid_name = NULL; 35static char *c_uid_name = NULL;
36 36
37static void print_file_or_dir(const char *path, const char *fname, int separator) { 37static void print_file_or_dir(const char *path, const char *fname) {
38 assert(fname); 38 assert(fname);
39 39
40 char *name; 40 char *name;
41 if (separator) { 41 if (asprintf(&name, "%s/%s", path, fname) == -1)
42 if (asprintf(&name, "%s/%s", path, fname) == -1) 42 errExit("asprintf");
43 errExit("asprintf");
44 }
45 else {
46 if (asprintf(&name, "%s%s", path, fname) == -1)
47 errExit("asprintf");
48 }
49 43
50 struct stat s; 44 struct stat s;
51 if (stat(name, &s) == -1) { 45 if (stat(name, &s) == -1) {
@@ -178,13 +172,81 @@ static void print_directory(const char *path) {
178 errExit("scandir"); 172 errExit("scandir");
179 else { 173 else {
180 for (i = 0; i < n; i++) { 174 for (i = 0; i < n; i++) {
181 print_file_or_dir(path, namelist[i]->d_name, 0); 175 print_file_or_dir(path, namelist[i]->d_name);
182 free(namelist[i]); 176 free(namelist[i]);
183 } 177 }
184 } 178 }
185 free(namelist); 179 free(namelist);
186} 180}
187 181
182void ls(const char *path) {
183 EUID_ASSERT();
184 assert(path);
185
186 char *rp = realpath(path, NULL);
187 if (!rp || access(rp, R_OK) == -1) {
188 fprintf(stderr, "Error: cannot access %s\n", path);
189 exit(1);
190 }
191 if (arg_debug)
192 printf("ls %s\n", rp);
193
194 // list directory contents
195 struct stat s;
196 if (stat(rp, &s) == -1) {
197 fprintf(stderr, "Error: cannot access %s\n", rp);
198 exit(1);
199 }
200 if (S_ISDIR(s.st_mode))
201 print_directory(rp);
202 else {
203 char *split = strrchr(rp, '/');
204 if (split) {
205 *split = '\0';
206 char *rp2 = split + 1;
207 if (arg_debug)
208 printf("path %s, file %s\n", rp, rp2);
209 print_file_or_dir(rp, rp2);
210 }
211 }
212 free(rp);
213}
214
215void cat(const char *path) {
216 EUID_ASSERT();
217 assert(path);
218
219 if (arg_debug)
220 printf("cat %s\n", path);
221 FILE *fp = fopen(path, "r");
222 if (!fp) {
223 fprintf(stderr, "Error: cannot read %s\n", path);
224 exit(1);
225 }
226 int fd = fileno(fp);
227 if (fd == -1)
228 errExit("fileno");
229 struct stat s;
230 if (fstat(fd, &s) == -1)
231 errExit("fstat");
232 if (!S_ISREG(s.st_mode)) {
233 fprintf(stderr, "Error: %s is not a regular file\n", path);
234 exit(1);
235 }
236 bool tty = isatty(STDOUT_FILENO);
237
238 int c;
239 while ((c = fgetc(fp)) != EOF) {
240 // file is untrusted
241 // replace control characters when printing to a terminal
242 if (tty && c != '\t' && c != '\n' && iscntrl((unsigned char) c))
243 c = '?';
244 fputc(c, stdout);
245 }
246 fflush(stdout);
247 fclose(fp);
248}
249
188char *expand_path(const char *path) { 250char *expand_path(const char *path) {
189 char *fname = NULL; 251 char *fname = NULL;
190 if (*path == '/') { 252 if (*path == '/') {
@@ -219,14 +281,14 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
219 check_join_permission(pid); 281 check_join_permission(pid);
220 282
221 // expand paths 283 // expand paths
222 char *fname1 = expand_path(path1);; 284 char *fname1 = expand_path(path1);
223 char *fname2 = NULL; 285 char *fname2 = NULL;
224 if (path2 != NULL) { 286 if (path2 != NULL) {
225 fname2 = expand_path(path2); 287 fname2 = expand_path(path2);
226 } 288 }
227 if (arg_debug) { 289 if (arg_debug) {
228 printf("file1 %s\n", fname1); 290 printf("file1 %s\n", fname1);
229 printf("file2 %s\n", fname2); 291 printf("file2 %s\n", fname2 ? fname2 : "(null)");
230 } 292 }
231 293
232 // sandbox root directory 294 // sandbox root directory
@@ -234,57 +296,36 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
234 if (asprintf(&rootdir, "/proc/%d/root", pid) == -1) 296 if (asprintf(&rootdir, "/proc/%d/root", pid) == -1)
235 errExit("asprintf"); 297 errExit("asprintf");
236 298
237 if (op == SANDBOX_FS_LS) { 299 if (op == SANDBOX_FS_LS || op == SANDBOX_FS_CAT) {
238 EUID_ROOT(); 300 pid_t child = fork();
239 // chroot 301 if (child < 0)
240 if (chroot(rootdir) < 0) 302 errExit("fork");
241 errExit("chroot"); 303 if (child == 0) {
242 if (chdir("/") < 0) 304 EUID_ROOT();
243 errExit("chdir"); 305 // chroot
244 306 if (chroot(rootdir) < 0)
245 // drop privileges 307 errExit("chroot");
246 drop_privs(0); 308 if (chdir("/") < 0)
247 309 errExit("chdir");
248 // check access
249 if (access(fname1, R_OK) == -1) {
250 fprintf(stderr, "Error: Cannot access %s\n", fname1);
251 exit(1);
252 }
253 /* coverity[toctou] */
254 char *rp = realpath(fname1, NULL);
255 if (!rp) {
256 fprintf(stderr, "Error: Cannot access %s\n", fname1);
257 exit(1);
258 }
259 if (arg_debug)
260 printf("realpath %s\n", rp);
261
262 310
263 // list directory contents 311 // drop privileges
264 struct stat s; 312 drop_privs(0);
265 if (stat(rp, &s) == -1) {
266 fprintf(stderr, "Error: Cannot access %s\n", rp);
267 exit(1);
268 }
269 if (S_ISDIR(s.st_mode)) {
270 char *dir;
271 if (asprintf(&dir, "%s/", rp) == -1)
272 errExit("asprintf");
273 313
274 print_directory(dir); 314 if (op == SANDBOX_FS_LS)
275 free(dir); 315 ls(fname1);
276 } 316 else
277 else { 317 cat(fname1);
278 char *split = strrchr(rp, '/'); 318#ifdef HAVE_GCOV
279 if (split) { 319 __gcov_flush();
280 *split = '\0'; 320#endif
281 char *rp2 = split + 1; 321 _exit(0);
282 if (arg_debug)
283 printf("path %s, file %s\n", rp, rp2);
284 print_file_or_dir(rp, rp2, 1);
285 }
286 } 322 }
287 free(rp); 323 // wait for the child to finish
324 int status = 0;
325 waitpid(child, &status, 0);
326 if (WIFEXITED(status) && WEXITSTATUS(status) == 0);
327 else
328 exit(1);
288 } 329 }
289 330
290 // get file from sandbox and store it in the current directory 331 // get file from sandbox and store it in the current directory
@@ -303,10 +344,12 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
303 // create a user-owned temporary file in /run/firejail directory 344 // create a user-owned temporary file in /run/firejail directory
304 char tmp_fname[] = "/run/firejail/tmpget-XXXXXX"; 345 char tmp_fname[] = "/run/firejail/tmpget-XXXXXX";
305 int fd = mkstemp(tmp_fname); 346 int fd = mkstemp(tmp_fname);
306 if (fd != -1) { 347 if (fd == -1) {
307 SET_PERMS_FD(fd, getuid(), getgid(), 0600); 348 fprintf(stderr, "Error: cannot create temporary file %s\n", tmp_fname);
308 close(fd); 349 exit(1);
309 } 350 }
351 SET_PERMS_FD(fd, getuid(), getgid(), 0600);
352 close(fd);
310 353
311 // copy the source file into the temporary file - we need to chroot 354 // copy the source file into the temporary file - we need to chroot
312 pid_t child = fork(); 355 pid_t child = fork();
diff --git a/src/firejail/main.c b/src/firejail/main.c
index b9cb43444..412c6148a 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -811,6 +811,8 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
811 } 811 }
812 812
813 // list directory contents 813 // list directory contents
814 if (!arg_debug)
815 arg_quiet = 1;
814 pid_t pid = require_pid(argv[i] + 5); 816 pid_t pid = require_pid(argv[i] + 5);
815 sandboxfs(SANDBOX_FS_LS, pid, path, NULL); 817 sandboxfs(SANDBOX_FS_LS, pid, path, NULL);
816 exit(0); 818 exit(0);
@@ -818,6 +820,35 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
818 else 820 else
819 exit_err_feature("file transfer"); 821 exit_err_feature("file transfer");
820 } 822 }
823 else if (strncmp(argv[i], "--cat=", 6) == 0) {
824 if (checkcfg(CFG_FILE_TRANSFER)) {
825 logargs(argc, argv);
826 if (arg_private_cwd) {
827 fprintf(stderr, "Error: --cat and --private-cwd options are mutually exclusive\n");
828 exit(1);
829 }
830
831 if ((i + 2) != argc) {
832 fprintf(stderr, "Error: invalid --cat option, path expected\n");
833 exit(1);
834 }
835 char *path = argv[i + 1];
836 invalid_filename(path, 0); // no globbing
837 if (strstr(path, "..")) {
838 fprintf(stderr, "Error: invalid file name %s\n", path);
839 exit(1);
840 }
841
842 // write file contents to stdout
843 if (!arg_debug)
844 arg_quiet = 1;
845 pid_t pid = require_pid(argv[i] + 6);
846 sandboxfs(SANDBOX_FS_CAT, pid, path, NULL);
847 exit(0);
848 }
849 else
850 exit_err_feature("file transfer");
851 }
821#endif 852#endif
822 else if (strncmp(argv[i], "--join=", 7) == 0) { 853 else if (strncmp(argv[i], "--join=", 7) == 0) {
823 if (checkcfg(CFG_JOIN) || getuid() == 0) { 854 if (checkcfg(CFG_JOIN) || getuid() == 0) {
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index e42d35be5..81d535762 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -140,6 +140,20 @@ void set_apparmor(void) {
140} 140}
141#endif 141#endif
142 142
143#ifdef HAVE_SECCOMP
144void seccomp_debug(void) {
145 if (arg_debug == 0)
146 return;
147
148 EUID_USER();
149 printf("Seccomp directory:\n");
150 ls(RUN_SECCOMP_DIR);
151 printf("Active seccomp files:\n");
152 cat(RUN_SECCOMP_LIST);
153 EUID_ROOT();
154}
155#endif
156
143static void save_nogroups(void) { 157static void save_nogroups(void) {
144 if (arg_nogroups == 0) 158 if (arg_nogroups == 0)
145 return; 159 return;
@@ -197,32 +211,6 @@ static FILE *create_ready_for_join_file(void) {
197 } 211 }
198} 212}
199 213
200#ifdef HAVE_SECCOMP
201static void seccomp_debug(void) {
202 if (arg_debug == 0)
203 return;
204
205 pid_t child = fork();
206 if (child < 0)
207 errExit("fork");
208 if (child == 0) {
209 // dropping privs before calling system(3)
210 drop_privs(1);
211 printf("Seccomp directory:\n");
212 int rv = system("ls -l " RUN_SECCOMP_DIR);
213 (void) rv;
214 printf("Active seccomp files:\n");
215 rv = system("cat " RUN_SECCOMP_LIST);
216 (void) rv;
217#ifdef HAVE_GCOV
218 __gcov_flush();
219#endif
220 _exit(0);
221 }
222 waitpid(child, NULL, 0);
223}
224#endif
225
226static void sandbox_if_up(Bridge *br) { 214static void sandbox_if_up(Bridge *br) {
227 assert(br); 215 assert(br);
228 if (!br->configured) 216 if (!br->configured)
diff --git a/src/firejail/usage.c b/src/firejail/usage.c
index 73c9a6a8b..2390706f2 100644
--- a/src/firejail/usage.c
+++ b/src/firejail/usage.c
@@ -47,6 +47,9 @@ static char *usage_str =
47 " --caps.drop=capability,capability - blacklist capabilities filter.\n" 47 " --caps.drop=capability,capability - blacklist capabilities filter.\n"
48 " --caps.keep=capability,capability - whitelist capabilities filter.\n" 48 " --caps.keep=capability,capability - whitelist capabilities filter.\n"
49 " --caps.print=name|pid - print the caps filter.\n" 49 " --caps.print=name|pid - print the caps filter.\n"
50#ifdef HAVE_FILE_TRANSFER
51 " --cat=name|pid filename - print content of file from sandbox container.\n"
52#endif
50 " --cgroup=tasks-file - place the sandbox in the specified control group.\n" 53 " --cgroup=tasks-file - place the sandbox in the specified control group.\n"
51#ifdef HAVE_CHROOT 54#ifdef HAVE_CHROOT
52 " --chroot=dirname - chroot into directory.\n" 55 " --chroot=dirname - chroot into directory.\n"
diff --git a/src/man/firejail.txt b/src/man/firejail.txt
index e216531ae..3b7ba4e3d 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -273,6 +273,10 @@ $ firejail \-\-list
273$ firejail \-\-caps.print=3272 273$ firejail \-\-caps.print=3272
274 274
275.TP 275.TP
276\fB\-\-cat=name|pid filename
277Print content of file from sandbox container, see FILE TRANSFER section for more details.
278
279.TP
276\fB\-\-cgroup=tasks-file 280\fB\-\-cgroup=tasks-file
277Place the sandbox in the specified control group. tasks-file is the full path of cgroup tasks file. 281Place the sandbox in the specified control group. tasks-file is the full path of cgroup tasks file.
278.br 282.br
@@ -344,7 +348,7 @@ $ firejail --dbus-system=filter --dbus-system.log --dbus-log=dbus.txt
344 348
345.TP 349.TP
346\fB\-\-dbus-system=filter|none 350\fB\-\-dbus-system=filter|none
347Set system DBus sandboxing policy. 351Set system DBus sandboxing policy.
348.br 352.br
349 353
350.br 354.br
@@ -3031,6 +3035,12 @@ These features allow the user to inspect the filesystem container of an existing
3031and transfer files between the container and the host filesystem. 3035and transfer files between the container and the host filesystem.
3032 3036
3033.TP 3037.TP
3038\fB\-\-cat=name|pid filename
3039Write content of a container file to standard out. The container is specified by name or PID.
3040If standard out is a terminal, all ASCII control characters except new line and horizontal tab
3041are replaced.
3042
3043.TP
3034\fB\-\-get=name|pid filename 3044\fB\-\-get=name|pid filename
3035Retrieve the container file and store it on the host in the current working directory. 3045Retrieve the container file and store it on the host in the current working directory.
3036The container is specified by name or PID. 3046The container is specified by name or PID.
@@ -3074,6 +3084,10 @@ $ firejail \-\-get=mybrowser ~/Downloads/xpra-clipboard.png
3074$ firejail \-\-put=mybrowser xpra-clipboard.png ~/Downloads/xpra-clipboard.png 3084$ firejail \-\-put=mybrowser xpra-clipboard.png ~/Downloads/xpra-clipboard.png
3075.br 3085.br
3076 3086
3087.br
3088$ firejail \-\-cat=mybrowser ~/.bashrc
3089.br
3090
3077.SH MONITORING 3091.SH MONITORING
3078Option \-\-list prints a list of all sandboxes. The format 3092Option \-\-list prints a list of all sandboxes. The format
3079for each process entry is as follows: 3093for each process entry is as follows:
@@ -3261,7 +3275,7 @@ Homepage: https://firejail.wordpress.com
3261\&\flfirejail-profile\fR\|(5), 3275\&\flfirejail-profile\fR\|(5),
3262\&\flfirejail-login\fR\|(5), 3276\&\flfirejail-login\fR\|(5),
3263\&\flfirejail-users\fR\|(5), 3277\&\flfirejail-users\fR\|(5),
3264.UR https://github.com/netblue30/firejail/wiki 3278.UR https://github.com/netblue30/firejail/wiki
3265.UE , 3279.UE ,
3266.UR https://github.com/netblue30/firejail 3280.UR https://github.com/netblue30/firejail
3267.UE 3281.UE