aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--etc/firejail.config3
-rw-r--r--src/firejail/checkcfg.c12
-rw-r--r--src/firejail/firejail.h1
-rw-r--r--src/firejail/x11.c437
4 files changed, 296 insertions, 157 deletions
diff --git a/etc/firejail.config b/etc/firejail.config
index 22ce77324..82847ea37 100644
--- a/etc/firejail.config
+++ b/etc/firejail.config
@@ -111,6 +111,9 @@
111# Xpra server command extra parameters. None by default; this is an example. 111# Xpra server command extra parameters. None by default; this is an example.
112# xpra-extra-params --dpi 96 112# xpra-extra-params --dpi 96
113 113
114# Enable this option if you have a version of Xpra that supports --attach switch
115# for start command, default disabled.
116# xpra-attach no
114 117
115# Screen size for --x11=xvfb, default 800x600x24. The third dimension is 118# Screen size for --x11=xvfb, default 800x600x24. The third dimension is
116# color depth; use 24 unless you know exactly what you're doing. 119# color depth; use 24 unless you know exactly what you're doing.
diff --git a/src/firejail/checkcfg.c b/src/firejail/checkcfg.c
index 9703c9a5b..50a96fc7a 100644
--- a/src/firejail/checkcfg.c
+++ b/src/firejail/checkcfg.c
@@ -50,6 +50,7 @@ int checkcfg(int val) {
50 cfg_val[CFG_FOLLOW_SYMLINK_PRIVATE_BIN] = 0; 50 cfg_val[CFG_FOLLOW_SYMLINK_PRIVATE_BIN] = 0;
51 cfg_val[CFG_DISABLE_MNT] = 0; 51 cfg_val[CFG_DISABLE_MNT] = 0;
52 cfg_val[CFG_ARP_PROBES] = DEFAULT_ARP_PROBES; 52 cfg_val[CFG_ARP_PROBES] = DEFAULT_ARP_PROBES;
53 cfg_val[CFG_XPRA_ATTACH] = 0;
53 54
54 // open configuration file 55 // open configuration file
55 const char *fname = SYSCONFDIR "/firejail.config"; 56 const char *fname = SYSCONFDIR "/firejail.config";
@@ -354,9 +355,18 @@ int checkcfg(int val) {
354 goto errout; 355 goto errout;
355 cfg_val[CFG_ARP_PROBES] = arp_probes; 356 cfg_val[CFG_ARP_PROBES] = arp_probes;
356 } 357 }
358 // xpra-attach
359 else if (strncmp(ptr, "xpra-attach ", 12) == 0) {
360 if (strcmp(ptr + 12, "yes") == 0)
361 cfg_val[CFG_XPRA_ATTACH] = 1;
362 else if (strcmp(ptr + 12, "no") == 0)
363 cfg_val[CFG_XPRA_ATTACH] = 0;
364 else
365 goto errout;
366 }
357 else 367 else
358 goto errout; 368 goto errout;
359 369
360 free(ptr); 370 free(ptr);
361 } 371 }
362 372
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 1a26396a7..dc903962b 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -706,6 +706,7 @@ enum {
706 CFG_DISABLE_MNT, 706 CFG_DISABLE_MNT,
707 CFG_JOIN, 707 CFG_JOIN,
708 CFG_ARP_PROBES, 708 CFG_ARP_PROBES,
709 CFG_XPRA_ATTACH,
709 CFG_MAX // this should always be the last entry 710 CFG_MAX // this should always be the last entry
710}; 711};
711extern char *xephyr_screen; 712extern char *xephyr_screen;
diff --git a/src/firejail/x11.c b/src/firejail/x11.c
index 7b21c2209..74b8d5b5c 100644
--- a/src/firejail/x11.c
+++ b/src/firejail/x11.c
@@ -398,7 +398,6 @@ void x11_start_xvfb(int argc, char **argv) {
398} 398}
399 399
400 400
401
402static char *extract_setting(int argc, char **argv, const char *argument) { 401static char *extract_setting(int argc, char **argv, const char *argument) {
403 int i; 402 int i;
404 int len = strlen(argument); 403 int len = strlen(argument);
@@ -635,37 +634,258 @@ void x11_start_xephyr(int argc, char **argv) {
635} 634}
636 635
637 636
638void x11_start_xpra(int argc, char **argv) { 637void x11_start_xpra_old(int argc, char **argv, int display, char *display_str) {
639 EUID_ASSERT(); 638 EUID_ASSERT();
640 int i; 639 int i;
641 struct stat s; 640 struct stat s;
642 pid_t client = 0; 641 pid_t client = 0;
643 pid_t server = 0; 642 pid_t server = 0;
644 643
645 setenv("FIREJAIL_X11", "yes", 1); 644 // build the start command
645 char *server_argv[256] = { // rest initialyzed to NULL
646 "xpra", "start", display_str, "--no-daemon",
647 };
648 unsigned pos = 0;
649 while (server_argv[pos] != NULL) pos++;
646 650
647 // unfortunately, xpra does a number of weird things when started by root user!!! 651 assert(xpra_extra_params); // should be "" if empty
648 if (getuid() == 0) { 652
649 fprintf(stderr, "Error: X11 sandboxing is not available when running as root\n"); 653 // parse xephyr_extra_params
650 exit(1); 654 // very basic quoting support
655 char *temp = strdup(xpra_extra_params);
656 if (*xpra_extra_params != '\0') {
657 if (!temp)
658 errExit("strdup");
659 bool dquote = false;
660 bool squote = false;
661 for (i = 0; i < (int) strlen(xpra_extra_params); i++) {
662 if (temp[i] == '\"') {
663 dquote = !dquote;
664 // replace closing quote by \0
665 if (dquote) temp[i] = '\0';
666 }
667 if (temp[i] == '\'') {
668 squote = !squote;
669 // replace closing quote by \0
670 if (squote) temp[i] = '\0';
671 }
672 if (!dquote && !squote && temp[i] == ' ') temp[i] = '\0';
673 if (dquote && squote) {
674 fprintf(stderr, "Error: mixed quoting found while parsing xpra_extra_params\n");
675 exit(1);
676 }
677 }
678 if (dquote) {
679 fprintf(stderr, "Error: unclosed quote found while parsing xpra_extra_params\n");
680 exit(1);
681 }
682
683 server_argv[pos++] = temp;
684 for (i = 0; i < (int) strlen(xpra_extra_params)-1; i++) {
685 if (pos >= (sizeof(server_argv)/sizeof(*server_argv)) - 2) {
686 fprintf(stderr, "Error: arg count limit exceeded while parsing xpra_extra_params\n");
687 exit(1);
688 }
689 if (temp[i] == '\0' && (temp[i+1] == '\"' || temp[i+1] == '\'')) {
690 server_argv[pos++] = temp + i + 2;
691 }
692 else if (temp[i] == '\0' && temp[i+1] != '\0') {
693 server_argv[pos++] = temp + i + 1;
694 }
695 }
651 } 696 }
652 drop_privs(0);
653 697
654 // check xpra 698 server_argv[pos++] = NULL;
655 if (!program_in_path("xpra")) { 699
656 fprintf(stderr, "\nError: Xpra program was not found in /usr/bin directory, please install it:\n"); 700 // no overrun
657 fprintf(stderr, " Debian/Ubuntu/Mint: sudo apt-get install xpra\n"); 701 assert(pos < (sizeof(server_argv)/sizeof(*server_argv)));
658 exit(0); 702 assert(server_argv[pos-1] == NULL); // last element is null
703
704 if (arg_debug) {
705 size_t i = 0;
706 printf("\n*** Starting xpra server: ");
707 while (server_argv[i]!=NULL) {
708 printf(" \"%s\"", server_argv[i]);
709 i++;
710 }
711 printf(" ***\n\n");
659 } 712 }
660 713
661 int display = random_display_number(); 714 int fd_null = -1;
662 char *display_str; 715 if (arg_quiet) {
663 if (asprintf(&display_str, ":%d", display) == -1) 716 fd_null = open("/dev/null", O_RDWR);
717 if (fd_null == -1)
718 errExit("open");
719 }
720
721 // start
722 server = fork();
723 if (server < 0)
724 errExit("fork");
725 if (server == 0) {
726 if (arg_debug)
727 printf("Starting xpra...\n");
728
729 if (arg_quiet && fd_null != -1) {
730 dup2(fd_null,0);
731 dup2(fd_null,1);
732 dup2(fd_null,2);
733 }
734
735 // running without privileges - see drop_privs call above
736 assert(getenv("LD_PRELOAD") == NULL);
737 execvp(server_argv[0], server_argv);
738 perror("execvp");
739 _exit(1);
740 }
741
742 // add a small delay, on some systems it takes some time for the server to start
743 sleep(5);
744
745 // check X11 socket
746 char *fname;
747 if (asprintf(&fname, "/tmp/.X11-unix/X%d", display) == -1)
664 errExit("asprintf"); 748 errExit("asprintf");
749 int n = 0;
750 // wait for x11 server to start
751 while (++n < 10) {
752 sleep(1);
753 if (stat(fname, &s) == 0)
754 break;
755 }
756
757 if (n == 10) {
758 fprintf(stderr, "Error: failed to start xpra\n");
759 exit(1);
760 }
761 free(fname);
762
763 if (arg_debug) {
764 printf("X11 sockets: "); fflush(0);
765 int rv = system("ls /tmp/.X11-unix");
766 (void) rv;
767 }
768
769 // build attach command
770 char *attach_argv[] = { "xpra", "--title=\"firejail x11 sandbox\"", "attach", display_str, NULL };
771
772 // run attach command
773 client = fork();
774 if (client < 0)
775 errExit("fork");
776 if (client == 0) {
777 if (arg_quiet && fd_null != -1) {
778 dup2(fd_null,0);
779 dup2(fd_null,1);
780 dup2(fd_null,2);
781 }
782
783 if (!arg_quiet)
784 printf("\n*** Attaching to xpra display %d ***\n\n", display);
785
786 // running without privileges - see drop_privs call above
787 assert(getenv("LD_PRELOAD") == NULL);
788 execvp(attach_argv[0], attach_argv);
789 perror("execvp");
790 _exit(1);
791 }
792
793 assert(display_str);
794 setenv("DISPLAY", display_str, 1);
795
796 // build jail command
797 char *firejail_argv[argc+2];
798 pos = 0;
799 for (i = 0; i < argc; i++) {
800 if (strncmp(argv[i], "--x11", 5) == 0)
801 continue;
802 firejail_argv[pos] = argv[i];
803 pos++;
804 }
805 firejail_argv[pos] = NULL;
806
807 assert((int) pos < (argc+2));
808 assert(!firejail_argv[pos]);
809
810 // start jail
811 pid_t jail = fork();
812 if (jail < 0)
813 errExit("fork");
814 if (jail == 0) {
815 // running without privileges - see drop_privs call above
816 assert(getenv("LD_PRELOAD") == NULL);
817 if (firejail_argv[0]) // shut up llvm scan-build
818 execvp(firejail_argv[0], firejail_argv);
819 perror("execvp");
820 exit(1);
821 }
822
823 if (!arg_quiet)
824 printf("Xpra server pid %d, xpra client pid %d, jail %d\n", server, client, jail);
825
826 sleep(1); // adding a delay in order to let the server start
827
828 // wait for jail or server to end
829 while (1) {
830 pid_t pid = wait(NULL);
831
832 if (pid == jail) {
833 char *stop_argv[] = { "xpra", "stop", display_str, NULL };
834 pid_t stop = fork();
835 if (stop < 0)
836 errExit("fork");
837 if (stop == 0) {
838 if (arg_quiet && fd_null != -1) {
839 dup2(fd_null,0);
840 dup2(fd_null,1);
841 dup2(fd_null,2);
842 }
843 // running without privileges - see drop_privs call above
844 assert(getenv("LD_PRELOAD") == NULL);
845 execvp(stop_argv[0], stop_argv);
846 perror("execvp");
847 _exit(1);
848 }
849
850 // wait for xpra server to stop, 10 seconds limit
851 while (++n < 10) {
852 sleep(1);
853 pid = waitpid(server, NULL, WNOHANG);
854 if (pid == server)
855 break;
856 }
857
858 if (arg_debug) {
859 if (n == 10)
860 printf("failed to stop xpra server gratefully\n");
861 else
862 printf("xpra server successfully stopped in %d secs\n", n);
863 }
864
865 // kill xpra server and xpra client
866 kill(client, SIGTERM);
867 kill(server, SIGTERM);
868 exit(0);
869 }
870 else if (pid == server) {
871 // kill firejail process
872 kill(jail, SIGTERM);
873 // kill xpra client (should die with server, but...)
874 kill(client, SIGTERM);
875 exit(0);
876 }
877 }
878}
879
880
881void x11_start_xpra_new(int argc, char **argv, char *display_str) {
882 EUID_ASSERT();
883 int i;
884 pid_t server = 0;
665 885
666 // build the start command 886 // build the start command
667 char *server_argv[256] = { // rest initialyzed to NULL 887 char *server_argv[256] = { // rest initialyzed to NULL
668 "xpra", "start", display_str, "--daemon=no", "--attach=yes", "--exit-with-children=yes" 888 "xpra", "start", display_str, "--daemon=no", "--attach=yes", "--exit-with-children=yes"
669 }; 889 };
670 unsigned spos = 0; 890 unsigned spos = 0;
671 unsigned fpos = 0; 891 unsigned fpos = 0;
@@ -685,17 +905,16 @@ void x11_start_xpra(int argc, char **argv) {
685 char *start_child_prefix = "--start-child="; 905 char *start_child_prefix = "--start-child=";
686 char *start_child; 906 char *start_child;
687 start_child = malloc(total_length + strlen(start_child_prefix) + fpos + 2); 907 start_child = malloc(total_length + strlen(start_child_prefix) + fpos + 2);
688 if (start_child == NULL) 908 if (start_child == NULL) {
689 { 909 fprintf(stderr, "Error: unable to allocate start_child to assemble command\n");
690 fprintf(stderr, "Error: unable to allocate start_child to assemble command\n"); 910 exit(1);
691 exit(1); 911 }
692 } 912
693
694 strcpy(start_child,start_child_prefix); 913 strcpy(start_child,start_child_prefix);
695 for(i = 0; i < fpos; i++) { 914 for(i = 0; (unsigned) i < fpos; i++) {
696 strncat(start_child,firejail_argv[i],strlen(firejail_argv[i])); 915 strncat(start_child,firejail_argv[i],strlen(firejail_argv[i]));
697 if(i != fpos - 1) 916 if((unsigned) i != fpos - 1)
698 strncat(start_child," ",strlen(" ")); 917 strncat(start_child," ",strlen(" "));
699 } 918 }
700 919
701 server_argv[spos++] = start_child; 920 server_argv[spos++] = start_child;
@@ -756,8 +975,6 @@ void x11_start_xpra(int argc, char **argv) {
756 assert(spos < (sizeof(server_argv)/sizeof(*server_argv))); 975 assert(spos < (sizeof(server_argv)/sizeof(*server_argv)));
757 assert(server_argv[spos-1] == NULL); // last element is null 976 assert(server_argv[spos-1] == NULL); // last element is null
758 977
759
760
761 if (arg_debug) { 978 if (arg_debug) {
762 size_t i = 0; 979 size_t i = 0;
763 printf("\n*** Starting xpra server: "); 980 printf("\n*** Starting xpra server: ");
@@ -796,137 +1013,45 @@ void x11_start_xpra(int argc, char **argv) {
796 _exit(1); 1013 _exit(1);
797 } 1014 }
798 1015
799 /* // add a small delay, on some systems it takes some time for the server to start */
800 /* sleep(5); */
801
802 /* // check X11 socket */
803 /* char *fname; */
804 /* if (asprintf(&fname, "/tmp/.X11-unix/X%d", display) == -1) */
805 /* errExit("asprintf"); */
806 /* int n = 0; */
807 /* // wait for x11 server to start */
808 /* while (++n < 10) { */
809 /* sleep(1); */
810 /* if (stat(fname, &s) == 0) */
811 /* break; */
812 /* } */
813
814 /* if (n == 10) { */
815 /* fprintf(stderr, "Error: failed to start xpra\n"); */
816 /* exit(1); */
817 /* } */
818 /* free(fname); */
819
820 /* if (arg_debug) { */
821 /* printf("X11 sockets: "); fflush(0); */
822 /* int rv = system("ls /tmp/.X11-unix"); */
823 /* (void) rv; */
824 /* } */
825
826 /* // build attach command */
827 /* char *attach_argv[] = { "xpra", "--title=\"firejail x11 sandbox\"", "attach", display_str, NULL }; */
828
829 /* // run attach command */
830 /* client = fork(); */
831 /* if (client < 0) */
832 /* errExit("fork"); */
833 /* if (client == 0) { */
834 /* if (arg_quiet && fd_null != -1) { */
835 /* dup2(fd_null,0); */
836 /* dup2(fd_null,1); */
837 /* dup2(fd_null,2); */
838 /* } */
839
840 /* if (!arg_quiet) */
841 /* printf("\n*** Attaching to xpra display %d ***\n\n", display); */
842
843 /* // running without privileges - see drop_privs call above */
844 /* assert(getenv("LD_PRELOAD") == NULL); */
845 /* execvp(attach_argv[0], attach_argv); */
846 /* perror("execvp"); */
847 /* _exit(1); */
848 /* } */
849
850 /* assert(display_str); */
851 /* setenv("DISPLAY", display_str, 1); */
852
853 /* // start jail */
854 /* pid_t jail = fork(); */
855 /* if (jail < 0) */
856 /* errExit("fork"); */
857 /* if (jail == 0) { */
858 /* // running without privileges - see drop_privs call above */
859 /* assert(getenv("LD_PRELOAD") == NULL); */
860 /* if (firejail_argv[0]) // shut up llvm scan-build */
861 /* execvp(firejail_argv[0], firejail_argv); */
862 /* perror("execvp"); */
863 /* exit(1); */
864 /* } */
865
866 /* if (!arg_quiet) */
867 /* printf("Xpra server pid %d, xpra client pid %d, jail %d\n", server, client, jail); */
868
869 /* sleep(1); // adding a delay in order to let the server start */
870
871 // wait for server to end 1016 // wait for server to end
872 while (1) { 1017 while (1) {
873 pid_t pid = wait(NULL); 1018 pid_t pid = wait(NULL);
874 if (pid == server) { 1019 if (pid == server) {
875 free(start_child); 1020 free(start_child);
876 exit(0); 1021 exit(0);
877 } 1022 }
878 } 1023 }
1024}
1025
1026
1027void x11_start_xpra(int argc, char **argv) {
1028 EUID_ASSERT();
1029
1030 setenv("FIREJAIL_X11", "yes", 1);
1031
1032 // unfortunately, xpra does a number of weird things when started by root user!!!
1033 if (getuid() == 0) {
1034 fprintf(stderr, "Error: X11 sandboxing is not available when running as root\n");
1035 exit(1);
1036 }
1037 drop_privs(0);
1038
1039 // check xpra
1040 if (!program_in_path("xpra")) {
1041 fprintf(stderr, "\nError: Xpra program was not found in /usr/bin directory, please install it:\n");
1042 fprintf(stderr, " Debian/Ubuntu/Mint: sudo apt-get install xpra\n");
1043 exit(0);
1044 }
1045
1046 int display = random_display_number();
1047 char *display_str;
1048 if (asprintf(&display_str, ":%d", display) == -1)
1049 errExit("asprintf");
879 1050
880 // wait for jail or server to end 1051 if (checkcfg(CFG_XPRA_ATTACH))
881 /* while (1) { */ 1052 x11_start_xpra_new(argc, argv, display_str);
882 /* pid_t pid = wait(NULL); */ 1053 else
883 1054 x11_start_xpra_old(argc, argv, display, display_str);
884 /* if (pid == jail) { */
885 /* char *stop_argv[] = { "xpra", "stop", display_str, NULL }; */
886 /* pid_t stop = fork(); */
887 /* if (stop < 0) */
888 /* errExit("fork"); */
889 /* if (stop == 0) { */
890 /* if (arg_quiet && fd_null != -1) { */
891 /* dup2(fd_null,0); */
892 /* dup2(fd_null,1); */
893 /* dup2(fd_null,2); */
894 /* } */
895 /* // running without privileges - see drop_privs call above */
896 /* assert(getenv("LD_PRELOAD") == NULL); */
897 /* execvp(stop_argv[0], stop_argv); */
898 /* perror("execvp"); */
899 /* _exit(1); */
900 /* } */
901
902 /* // wait for xpra server to stop, 10 seconds limit */
903 /* while (++n < 10) { */
904 /* sleep(1); */
905 /* pid = waitpid(server, NULL, WNOHANG); */
906 /* if (pid == server) */
907 /* break; */
908 /* } */
909
910 /* if (arg_debug) { */
911 /* if (n == 10) */
912 /* printf("failed to stop xpra server gratefully\n"); */
913 /* else */
914 /* printf("xpra server successfully stopped in %d secs\n", n); */
915 /* } */
916
917 /* // kill xpra server and xpra client */
918 /* kill(client, SIGTERM); */
919 /* kill(server, SIGTERM); */
920 /* exit(0); */
921 /* } */
922 /* else if (pid == server) { */
923 /* // kill firejail process */
924 /* kill(jail, SIGTERM); */
925 /* // kill xpra client (should die with server, but...) */
926 /* kill(client, SIGTERM); */
927 /* exit(0); */
928 /* } */
929 /* } */
930} 1055}
931 1056
932 1057