aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar smitsohu <smitsohu@gmail.com>2020-08-03 19:20:32 +0200
committerLibravatar GitHub <noreply@github.com>2020-08-03 19:20:32 +0200
commitb41532ab6c8578fd6df254a41d1be54c9331aa3f (patch)
tree978e2796a3ca9ad6e594e9f0e2a7ae5d1c4e8db2 /src
parentRemove unused dummy source file (diff)
downloadfirejail-b41532ab6c8578fd6df254a41d1be54c9331aa3f.tar.gz
firejail-b41532ab6c8578fd6df254a41d1be54c9331aa3f.tar.zst
firejail-b41532ab6c8578fd6df254a41d1be54c9331aa3f.zip
don't run with closed standard streams
Ensure that all standard streams are open and we don't inadvertently print to files opened for a different reason; in general we can expect glibc to take care of this, but it doesn't cover the case where a sandbox is started by root. The added code also serves as a fallback. Unrelated: For what it's worth, shift umask call closer to main start, so it runs before lowering privileges and before anything can really go wrong.
Diffstat (limited to 'src')
-rw-r--r--src/firejail/main.c29
1 files changed, 25 insertions, 4 deletions
diff --git a/src/firejail/main.c b/src/firejail/main.c
index 958374c43..79e39b669 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -361,6 +361,24 @@ static void init_cfg(int argc, char **argv) {
361 cfg.seccomp_error_action = "EPERM"; 361 cfg.seccomp_error_action = "EPERM";
362} 362}
363 363
364static void fix_single_std_fd(int fd, const char *file, int flags) {
365 struct stat s;
366 if (fstat(fd, &s) == -1 && errno == EBADF) {
367 // something is wrong with fd, probably it is not opened
368 int nfd = open(file, flags);
369 if (nfd != fd || fstat(fd, &s) != 0)
370 _exit(1); // no further attempts to fix the situation
371 }
372}
373
374// glibc does this automatically if Firejail was started by a regular user
375// run this for root user and as a fallback
376static void fix_std_streams(void) {
377 fix_single_std_fd(0, "/dev/full", O_RDONLY|O_NOFOLLOW);
378 fix_single_std_fd(1, "/dev/null", O_WRONLY|O_NOFOLLOW);
379 fix_single_std_fd(2, "/dev/null", O_WRONLY|O_NOFOLLOW);
380}
381
364static void check_network(Bridge *br) { 382static void check_network(Bridge *br) {
365 assert(br); 383 assert(br);
366 if (br->macvlan == 0) // for bridge devices check network range or arp-scan and assign address 384 if (br->macvlan == 0) // for bridge devices check network range or arp-scan and assign address
@@ -1017,16 +1035,19 @@ int main(int argc, char **argv, char **envp) {
1017 int arg_caps_cmdline = 0; // caps requested on command line (used to break out of --chroot) 1035 int arg_caps_cmdline = 0; // caps requested on command line (used to break out of --chroot)
1018 char **ptr; 1036 char **ptr;
1019 1037
1038 // sanitize the umask
1039 orig_umask = umask(022);
1040
1041 // check standard streams before printing anything
1042 fix_std_streams();
1043
1020 // drop permissions by default and rise them when required 1044 // drop permissions by default and rise them when required
1021 EUID_INIT(); 1045 EUID_INIT();
1022 EUID_USER(); 1046 EUID_USER();
1023 1047
1024 // sanitize the umask
1025 orig_umask = umask(022);
1026
1027 // argument count should be larger than 0 1048 // argument count should be larger than 0
1028 if (argc == 0 || !argv || strlen(argv[0]) == 0) { 1049 if (argc == 0 || !argv || strlen(argv[0]) == 0) {
1029 fprintf(stderr, "Error: argv[0] is NULL\n"); 1050 fprintf(stderr, "Error: argv is invalid\n");
1030 exit(1); 1051 exit(1);
1031 } else if (argc >= MAX_ARGS) { 1052 } else if (argc >= MAX_ARGS) {
1032 fprintf(stderr, "Error: too many arguments\n"); 1053 fprintf(stderr, "Error: too many arguments\n");