aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar startx2017 <vradu.startx@yandex.com>2018-09-06 07:41:11 -0400
committerLibravatar startx2017 <vradu.startx@yandex.com>2018-09-06 07:41:11 -0400
commit5e8d4cd110825f1d1608f99d6e1a8cf59e1be537 (patch)
tree8ed044526eb2dbd135b821c5ccac715d37a3bc0c
parentmainline merges (diff)
downloadfirejail-5e8d4cd110825f1d1608f99d6e1a8cf59e1be537.tar.gz
firejail-5e8d4cd110825f1d1608f99d6e1a8cf59e1be537.tar.zst
firejail-5e8d4cd110825f1d1608f99d6e1a8cf59e1be537.zip
final cleanup
-rw-r--r--src/firejail/fs.c650
-rw-r--r--src/firejail/fs_etc.c112
-rw-r--r--src/firejail/fs_home.c172
-rw-r--r--src/firejail/fs_trace.c9
-rw-r--r--src/firejail/join.c24
-rw-r--r--src/firejail/main.c583
-rw-r--r--src/firejail/profile.c319
-rw-r--r--src/firejail/sandbox.c145
8 files changed, 1 insertions, 2013 deletions
diff --git a/src/firejail/fs.c b/src/firejail/fs.c
index d92b6b1e0..a4f34b883 100644
--- a/src/firejail/fs.c
+++ b/src/firejail/fs.c
@@ -780,656 +780,6 @@ void fs_basic_fs(void) {
780} 780}
781 781
782 782
783#ifndef LTS
784#ifdef HAVE_OVERLAYFS
785char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) {
786 assert(subdirname);
787 struct stat s;
788 char *dirname;
789
790 if (asprintf(&dirname, "%s/.firejail", cfg.homedir) == -1)
791 errExit("asprintf");
792 // check if ~/.firejail already exists
793 if (lstat(dirname, &s) == 0) {
794 if (!S_ISDIR(s.st_mode)) {
795 if (S_ISLNK(s.st_mode))
796 fprintf(stderr, "Error: ~/.firejail is a symbolic link\n");
797 else
798 fprintf(stderr, "Error: ~/.firejail is not a directory\n");
799 exit(1);
800 }
801 if (s.st_uid != getuid()) {
802 fprintf(stderr, "Error: ~/.firejail directory is not owned by the current user\n");
803 exit(1);
804 }
805 }
806 else {
807 // create ~/.firejail directory
808 pid_t child = fork();
809 if (child < 0)
810 errExit("fork");
811 if (child == 0) {
812 // drop privileges
813 drop_privs(0);
814
815 // create directory
816 if (mkdir(dirname, 0700))
817 errExit("mkdir");
818 if (chmod(dirname, 0700) == -1)
819 errExit("chmod");
820 ASSERT_PERMS(dirname, getuid(), getgid(), 0700);
821#ifdef HAVE_GCOV
822 __gcov_flush();
823#endif
824 _exit(0);
825 }
826 // wait for the child to finish
827 waitpid(child, NULL, 0);
828 if (stat(dirname, &s) == -1) {
829 fprintf(stderr, "Error: cannot create ~/.firejail directory\n");
830 exit(1);
831 }
832 fs_logger2("create", dirname);
833 }
834 free(dirname);
835
836 // check overlay directory
837 if (asprintf(&dirname, "%s/.firejail/%s", cfg.homedir, subdirname) == -1)
838 errExit("asprintf");
839 if (lstat(dirname, &s) == 0) {
840 if (!S_ISDIR(s.st_mode)) {
841 if (S_ISLNK(s.st_mode))
842 fprintf(stderr, "Error: %s is a symbolic link\n", dirname);
843 else
844 fprintf(stderr, "Error: %s is not a directory\n", dirname);
845 exit(1);
846 }
847 if (s.st_uid != 0) {
848 fprintf(stderr, "Error: overlay directory %s is not owned by the root user\n", dirname);
849 exit(1);
850 }
851 if (allow_reuse == 0) {
852 fprintf(stderr, "Error: overlay directory exists, but reuse is not allowed\n");
853 exit(1);
854 }
855 }
856
857 return dirname;
858}
859
860
861
862// mount overlayfs on top of / directory
863// mounting an overlay and chrooting into it:
864//
865// Old Ubuntu kernel
866// # cd ~
867// # mkdir -p overlay/root
868// # mkdir -p overlay/diff
869// # mount -t overlayfs -o lowerdir=/,upperdir=/root/overlay/diff overlayfs /root/overlay/root
870// # chroot /root/overlay/root
871// to shutdown, first exit the chroot and then unmount the overlay
872// # exit
873// # umount /root/overlay/root
874//
875// Kernels 3.18+
876// # cd ~
877// # mkdir -p overlay/root
878// # mkdir -p overlay/diff
879// # mkdir -p overlay/work
880// # mount -t overlay -o lowerdir=/,upperdir=/root/overlay/diff,workdir=/root/overlay/work overlay /root/overlay/root
881// # cat /etc/mtab | grep overlay
882// /root/overlay /root/overlay/root overlay rw,relatime,lowerdir=/,upperdir=/root/overlay/diff,workdir=/root/overlay/work 0 0
883// # chroot /root/overlay/root
884// to shutdown, first exit the chroot and then unmount the overlay
885// # exit
886// # umount /root/overlay/root
887
888
889// to do: fix the code below; also, it might work without /dev, but consider keeping /dev/shm; add locking mechanism for overlay-clean
890#include <sys/utsname.h>
891void fs_overlayfs(void) {
892 struct stat s;
893
894 // check kernel version
895 struct utsname u;
896 int rv = uname(&u);
897 if (rv != 0)
898 errExit("uname");
899 int major;
900 int minor;
901 if (2 != sscanf(u.release, "%d.%d", &major, &minor)) {
902 fprintf(stderr, "Error: cannot extract Linux kernel version: %s\n", u.version);
903 exit(1);
904 }
905
906 if (arg_debug)
907 printf("Linux kernel version %d.%d\n", major, minor);
908 int oldkernel = 0;
909 if (major < 3) {
910 fprintf(stderr, "Error: minimum kernel version required 3.x\n");
911 exit(1);
912 }
913 if (major == 3 && minor < 18)
914 oldkernel = 1;
915
916 char *oroot = RUN_OVERLAY_ROOT;
917 mkdir_attr(oroot, 0755, 0, 0);
918
919 // set base for working and diff directories
920 char *basedir = RUN_MNT_DIR;
921 int basefd = -1;
922
923 if (arg_overlay_keep) {
924 basedir = cfg.overlay_dir;
925 assert(basedir);
926 // get a file descriptor for ~/.firejail, fails if there is any symlink
927 char *firejail;
928 if (asprintf(&firejail, "%s/.firejail", cfg.homedir) == -1)
929 errExit("asprintf");
930 int fd = safe_fd(firejail, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
931 if (fd == -1)
932 errExit("safe_fd");
933 free(firejail);
934 // create basedir if it doesn't exist
935 // the new directory will be owned by root
936 const char *dirname = gnu_basename(basedir);
937 if (mkdirat(fd, dirname, 0755) == -1 && errno != EEXIST) {
938 perror("mkdir");
939 fprintf(stderr, "Error: cannot create overlay directory %s\n", basedir);
940 exit(1);
941 }
942 // open basedir
943 basefd = openat(fd, dirname, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
944 close(fd);
945 }
946 else {
947 basefd = open(basedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
948 }
949 if (basefd == -1) {
950 perror("open");
951 fprintf(stderr, "Error: cannot open overlay directory %s\n", basedir);
952 exit(1);
953 }
954
955 // confirm once more base is owned by root
956 if (fstat(basefd, &s) == -1)
957 errExit("fstat");
958 if (s.st_uid != 0) {
959 fprintf(stderr, "Error: overlay directory %s is not owned by the root user\n", basedir);
960 exit(1);
961 }
962 // confirm permissions of base are 0755
963 if (((S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) & s.st_mode) != (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
964 fprintf(stderr, "Error: invalid permissions on overlay directory %s\n", basedir);
965 exit(1);
966 }
967
968 // create diff and work directories inside base
969 // no need to check arg_overlay_reuse
970 char *odiff;
971 if (asprintf(&odiff, "%s/odiff", basedir) == -1)
972 errExit("asprintf");
973 // the new directory will be owned by root
974 if (mkdirat(basefd, "odiff", 0755) == -1 && errno != EEXIST) {
975 perror("mkdir");
976 fprintf(stderr, "Error: cannot create overlay directory %s\n", odiff);
977 exit(1);
978 }
979 ASSERT_PERMS(odiff, 0, 0, 0755);
980
981 char *owork;
982 if (asprintf(&owork, "%s/owork", basedir) == -1)
983 errExit("asprintf");
984 // the new directory will be owned by root
985 if (mkdirat(basefd, "owork", 0755) == -1 && errno != EEXIST) {
986 perror("mkdir");
987 fprintf(stderr, "Error: cannot create overlay directory %s\n", owork);
988 exit(1);
989 }
990 ASSERT_PERMS(owork, 0, 0, 0755);
991
992 // mount overlayfs
993 if (arg_debug)
994 printf("Mounting OverlayFS\n");
995 char *option;
996 if (oldkernel) { // old Ubuntu/OpenSUSE kernels
997 if (arg_overlay_keep) {
998 fprintf(stderr, "Error: option --overlay= not available for kernels older than 3.18\n");
999 exit(1);
1000 }
1001 if (asprintf(&option, "lowerdir=/,upperdir=%s", odiff) == -1)
1002 errExit("asprintf");
1003 if (mount("overlayfs", oroot, "overlayfs", MS_MGC_VAL, option) < 0)
1004 errExit("mounting overlayfs");
1005 }
1006 else { // kernel 3.18 or newer
1007 if (asprintf(&option, "lowerdir=/,upperdir=%s,workdir=%s", odiff, owork) == -1)
1008 errExit("asprintf");
1009 if (mount("overlay", oroot, "overlay", MS_MGC_VAL, option) < 0)
1010 errExit("mounting overlayfs");
1011
1012 //***************************
1013 // issue #263 start code
1014 // My setup has a separate mount point for /home. When the overlay is mounted,
1015 // the overlay does not contain the original /home contents.
1016 // I added code to create a second overlay for /home if the overlay home dir is empty and this seems to work
1017 // @dshmgh, Jan 2016
1018 {
1019 char *overlayhome;
1020 struct stat s;
1021 char *hroot;
1022 char *hdiff;
1023 char *hwork;
1024
1025 // dons add debug
1026 if (arg_debug) printf ("DEBUG: chroot dirs are oroot %s odiff %s owork %s\n",oroot,odiff,owork);
1027
1028 // BEFORE NEXT, WE NEED TO TEST IF /home has any contents or do we need to mount it?
1029 // must create var for oroot/cfg.homedir
1030 if (asprintf(&overlayhome, "%s%s", oroot, cfg.homedir) == -1)
1031 errExit("asprintf");
1032 if (arg_debug) printf ("DEBUG: overlayhome var holds ##%s##\n", overlayhome);
1033
1034 // if no homedir in overlay -- create another overlay for /home
1035 if (stat(cfg.homedir, &s) == 0 && stat(overlayhome, &s) == -1) {
1036
1037 // no need to check arg_overlay_reuse
1038 if (asprintf(&hdiff, "%s/hdiff", basedir) == -1)
1039 errExit("asprintf");
1040 // the new directory will be owned by root
1041 if (mkdirat(basefd, "hdiff", 0755) == -1 && errno != EEXIST) {
1042 perror("mkdir");
1043 fprintf(stderr, "Error: cannot create overlay directory %s\n", hdiff);
1044 exit(1);
1045 }
1046 ASSERT_PERMS(hdiff, 0, 0, 0755);
1047
1048 // no need to check arg_overlay_reuse
1049 if (asprintf(&hwork, "%s/hwork", basedir) == -1)
1050 errExit("asprintf");
1051 // the new directory will be owned by root
1052 if (mkdirat(basefd, "hwork", 0755) == -1 && errno != EEXIST) {
1053 perror("mkdir");
1054 fprintf(stderr, "Error: cannot create overlay directory %s\n", hwork);
1055 exit(1);
1056 }
1057 ASSERT_PERMS(hwork, 0, 0, 0755);
1058
1059 // no homedir in overlay so now mount another overlay for /home
1060 if (asprintf(&hroot, "%s/home", oroot) == -1)
1061 errExit("asprintf");
1062 if (asprintf(&option, "lowerdir=/home,upperdir=%s,workdir=%s", hdiff, hwork) == -1)
1063 errExit("asprintf");
1064 if (mount("overlay", hroot, "overlay", MS_MGC_VAL, option) < 0)
1065 errExit("mounting overlayfs for mounted home directory");
1066
1067 printf("OverlayFS for /home configured in %s directory\n", basedir);
1068 free(hroot);
1069 free(hdiff);
1070 free(hwork);
1071
1072 } // stat(overlayhome)
1073 free(overlayhome);
1074 }
1075 // issue #263 end code
1076 //***************************
1077 }
1078 fmessage("OverlayFS configured in %s directory\n", basedir);
1079 close(basefd);
1080
1081 // /dev, /run and /tmp are not covered by the overlay
1082 // mount-bind dev directory
1083 if (arg_debug)
1084 printf("Mounting /dev\n");
1085 char *dev;
1086 if (asprintf(&dev, "%s/dev", oroot) == -1)
1087 errExit("asprintf");
1088 if (mount("/dev", dev, NULL, MS_BIND|MS_REC, NULL) < 0)
1089 errExit("mounting /dev");
1090 fs_logger("whitelist /dev");
1091
1092 // mount-bind run directory
1093 if (arg_debug)
1094 printf("Mounting /run\n");
1095 char *run;
1096 if (asprintf(&run, "%s/run", oroot) == -1)
1097 errExit("asprintf");
1098 if (mount("/run", run, NULL, MS_BIND|MS_REC, NULL) < 0)
1099 errExit("mounting /run");
1100 fs_logger("whitelist /run");
1101
1102 // mount-bind tmp directory
1103 if (arg_debug)
1104 printf("Mounting /tmp\n");
1105 char *tmp;
1106 if (asprintf(&tmp, "%s/tmp", oroot) == -1)
1107 errExit("asprintf");
1108 if (mount("/tmp", tmp, NULL, MS_BIND|MS_REC, NULL) < 0)
1109 errExit("mounting /tmp");
1110 fs_logger("whitelist /tmp");
1111
1112 // chroot in the new filesystem
1113#ifdef HAVE_GCOV
1114 __gcov_flush();
1115#endif
1116 if (chroot(oroot) == -1)
1117 errExit("chroot");
1118
1119 // update /var directory in order to support multiple sandboxes running on the same root directory
1120// if (!arg_private_dev)
1121// fs_dev_shm();
1122 fs_var_lock();
1123 if (!arg_keep_var_tmp)
1124 fs_var_tmp();
1125 if (!arg_writable_var_log)
1126 fs_var_log();
1127 fs_var_lib();
1128 fs_var_cache();
1129 fs_var_utmp();
1130 fs_machineid();
1131
1132 // don't leak user information
1133 restrict_users();
1134
1135 // when starting as root, firejail config is not disabled;
1136 if (getuid() != 0)
1137 disable_config();
1138
1139 // cleanup and exit
1140 free(option);
1141 free(odiff);
1142 free(owork);
1143 free(dev);
1144 free(run);
1145 free(tmp);
1146}
1147#endif
1148
1149
1150#ifdef HAVE_CHROOT
1151// exit if error
1152void fs_check_chroot_dir(const char *rootdir) {
1153 EUID_ASSERT();
1154 assert(rootdir);
1155 struct stat s;
1156 int fd = -1;
1157 int parentfd = -1;
1158
1159 char *overlay;
1160 if (asprintf(&overlay, "%s/.firejail", cfg.homedir) == -1)
1161 errExit("asprintf");
1162 if (strncmp(rootdir, overlay, strlen(overlay)) == 0) {
1163 fprintf(stderr, "Error: invalid chroot directory: no directories in ~/.firejail are allowed\n");
1164 exit(1);
1165 }
1166 free(overlay);
1167
1168 // fails if there is any symlink or if rootdir is not a directory
1169 parentfd = safe_fd(rootdir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
1170 if (parentfd == -1) {
1171 fprintf(stderr, "Error: invalid chroot directory %s\n", rootdir);
1172 exit(1);
1173 }
1174 // rootdir has to be owned by root and is not allowed to be generally writable,
1175 // this also excludes /tmp, /var/tmp and such
1176 if (fstat(parentfd, &s) == -1)
1177 errExit("fstat");
1178 if (s.st_uid != 0) {
1179 fprintf(stderr, "Error: chroot directory should be owned by root\n");
1180 exit(1);
1181 }
1182 if (((S_IWGRP|S_IWOTH) & s.st_mode) != 0) {
1183 fprintf(stderr, "Error: only root user should be given write permission on chroot directory\n");
1184 exit(1);
1185 }
1186
1187 // check /dev
1188 fd = openat(parentfd, "dev", O_PATH|O_CLOEXEC);
1189 if (fd == -1) {
1190 fprintf(stderr, "Error: cannot open /dev in chroot directory\n");
1191 exit(1);
1192 }
1193 if (fstat(fd, &s) == -1)
1194 errExit("fstat");
1195 if (!S_ISDIR(s.st_mode) || s.st_uid != 0) {
1196 fprintf(stderr, "Error: chroot /dev should be a directory owned by root\n");
1197 exit(1);
1198 }
1199 close(fd);
1200
1201 // check /var/tmp
1202 fd = openat(parentfd, "var/tmp", O_PATH|O_CLOEXEC);
1203 if (fd == -1) {
1204 fprintf(stderr, "Error: cannot open /var/tmp in chroot directory\n");
1205 exit(1);
1206 }
1207 if (fstat(fd, &s) == -1)
1208 errExit("fstat");
1209 if (!S_ISDIR(s.st_mode) || s.st_uid != 0) {
1210 fprintf(stderr, "Error: chroot /var/tmp should be a directory owned by root\n");
1211 exit(1);
1212 }
1213 close(fd);
1214
1215 // check /proc
1216 fd = openat(parentfd, "proc", O_PATH|O_CLOEXEC);
1217 if (fd == -1) {
1218 fprintf(stderr, "Error: cannot open /proc in chroot directory\n");
1219 exit(1);
1220 }
1221 if (fstat(fd, &s) == -1)
1222 errExit("fstat");
1223 if (!S_ISDIR(s.st_mode) || s.st_uid != 0) {
1224 fprintf(stderr, "Error: chroot /proc should be a directory owned by root\n");
1225 exit(1);
1226 }
1227 close(fd);
1228
1229 // check /tmp
1230 fd = openat(parentfd, "tmp", O_PATH|O_CLOEXEC);
1231 if (fd == -1) {
1232 fprintf(stderr, "Error: cannot open /tmp in chroot directory\n");
1233 exit(1);
1234 }
1235 if (fstat(fd, &s) == -1)
1236 errExit("fstat");
1237 if (!S_ISDIR(s.st_mode) || s.st_uid != 0) {
1238 fprintf(stderr, "Error: chroot /tmp should be a directory owned by root\n");
1239 exit(1);
1240 }
1241 close(fd);
1242
1243 // check /etc
1244 fd = openat(parentfd, "etc", O_PATH|O_CLOEXEC);
1245 if (fd == -1) {
1246 fprintf(stderr, "Error: cannot open /etc in chroot directory\n");
1247 exit(1);
1248 }
1249 if (fstat(fd, &s) == -1)
1250 errExit("fstat");
1251 if (!S_ISDIR(s.st_mode) || s.st_uid != 0) {
1252 fprintf(stderr, "Error: chroot /etc should be a directory owned by root\n");
1253 exit(1);
1254 }
1255 if (((S_IWGRP|S_IWOTH) & s.st_mode) != 0) {
1256 fprintf(stderr, "Error: only root user should be given write permission on chroot /etc\n");
1257 exit(1);
1258 }
1259 close(fd);
1260
1261 // there should be no checking on <chrootdir>/etc/resolv.conf
1262 // the file is replaced with the real /etc/resolv.conf anyway
1263#if 0
1264 if (asprintf(&name, "%s/etc/resolv.conf", rootdir) == -1)
1265 errExit("asprintf");
1266 if (stat(name, &s) == 0) {
1267 if (s.st_uid != 0) {
1268 fprintf(stderr, "Error: chroot /etc/resolv.conf should be owned by root\n");
1269 exit(1);
1270 }
1271 }
1272 else {
1273 fprintf(stderr, "Error: chroot /etc/resolv.conf not found\n");
1274 exit(1);
1275 }
1276 // on Arch /etc/resolv.conf could be a symlink to /run/systemd/resolve/resolv.conf
1277 // on Ubuntu 17.04 /etc/resolv.conf could be a symlink to /run/resolveconf/resolv.conf
1278 if (is_link(name)) {
1279 // check the link points in chroot
1280 char *rname = realpath(name, NULL);
1281 if (!rname || strncmp(rname, rootdir, strlen(rootdir)) != 0) {
1282 fprintf(stderr, "Error: chroot /etc/resolv.conf is pointing outside chroot\n");
1283 exit(1);
1284 }
1285 }
1286 free(name);
1287#endif
1288
1289 // check x11 socket directory
1290 if (getenv("FIREJAIL_X11")) {
1291 fd = openat(parentfd, "tmp/.X11-unix", O_PATH|O_CLOEXEC);
1292 if (fd == -1) {
1293 fprintf(stderr, "Error: cannot open /tmp/.X11-unix in chroot directory\n");
1294 exit(1);
1295 }
1296 if (fstat(fd, &s) == -1)
1297 errExit("fstat");
1298 if (!S_ISDIR(s.st_mode) || s.st_uid != 0) {
1299 fprintf(stderr, "Error: chroot /tmp/.X11-unix should be a directory owned by root\n");
1300 exit(1);
1301 }
1302 close(fd);
1303 }
1304
1305 close(parentfd);
1306}
1307
1308// chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf
1309void fs_chroot(const char *rootdir) {
1310 assert(rootdir);
1311
1312 // mount-bind a /dev in rootdir
1313 char *newdev;
1314 if (asprintf(&newdev, "%s/dev", rootdir) == -1)
1315 errExit("asprintf");
1316 if (arg_debug)
1317 printf("Mounting /dev on %s\n", newdev);
1318 if (mount("/dev", newdev, NULL, MS_BIND|MS_REC, NULL) < 0)
1319 errExit("mounting /dev");
1320 free(newdev);
1321
1322 // x11
1323 if (getenv("FIREJAIL_X11")) {
1324 char *newx11;
1325 if (asprintf(&newx11, "%s/tmp/.X11-unix", rootdir) == -1)
1326 errExit("asprintf");
1327 if (arg_debug)
1328 printf("Mounting /tmp/.X11-unix on %s\n", newx11);
1329 if (mount("/tmp/.X11-unix", newx11, NULL, MS_BIND|MS_REC, NULL) < 0)
1330 errExit("mounting /tmp/.X11-unix");
1331 free(newx11);
1332 }
1333
1334 // some older distros don't have a /run directory
1335 // create one by default
1336 char *rundir;
1337 if (asprintf(&rundir, "%s/run", rootdir) == -1)
1338 errExit("asprintf");
1339 struct stat s;
1340 if (lstat(rundir, &s) == 0) {
1341 if (S_ISLNK(s.st_mode)) {
1342 fprintf(stderr, "Error: chroot /run is a symbolic link\n");
1343 exit(1);
1344 }
1345 if (!S_ISDIR(s.st_mode) || s.st_uid != 0) {
1346 fprintf(stderr, "Error: chroot /run should be a directory owned by root\n");
1347 exit(1);
1348 }
1349 if (((S_IWGRP|S_IWOTH) & s.st_mode) != 0) {
1350 fprintf(stderr, "Error: only root user should be given write permission on chroot /run\n");
1351 exit(1);
1352 }
1353 }
1354 else {
1355 // several sandboxes could race to create /run
1356 if (mkdir(rundir, 0755) == -1 && errno != EEXIST)
1357 errExit("mkdir");
1358 ASSERT_PERMS(rundir, 0, 0, 0755);
1359 }
1360 free(rundir);
1361
1362 // create /run/firejail directory in chroot
1363 if (asprintf(&rundir, "%s/run/firejail", rootdir) == -1)
1364 errExit("asprintf");
1365 if (mkdir(rundir, 0755) == -1 && errno != EEXIST)
1366 errExit("mkdir");
1367 ASSERT_PERMS(rundir, 0, 0, 0755);
1368 free(rundir);
1369
1370 // create /run/firejail/mnt directory in chroot and mount the current one
1371 if (asprintf(&rundir, "%s%s", rootdir, RUN_MNT_DIR) == -1)
1372 errExit("asprintf");
1373 if (mkdir(rundir, 0755) == -1 && errno != EEXIST)
1374 errExit("mkdir");
1375 ASSERT_PERMS(rundir, 0, 0, 0755);
1376 if (mount(RUN_MNT_DIR, rundir, NULL, MS_BIND|MS_REC, NULL) < 0)
1377 errExit("mount bind");
1378 free(rundir);
1379
1380 // copy /etc/resolv.conf in chroot directory
1381 char *fname;
1382 if (asprintf(&fname, "%s/etc/resolv.conf", rootdir) == -1)
1383 errExit("asprintf");
1384 if (arg_debug)
1385 printf("Updating /etc/resolv.conf in %s\n", fname);
1386 unlink(fname);
1387 if (copy_file("/etc/resolv.conf", fname, 0, 0, 0644) == -1) // root needed
1388 fwarning("/etc/resolv.conf not initialized\n");
1389 free(fname);
1390
1391 // chroot into the new directory
1392#ifdef HAVE_GCOV
1393 __gcov_flush();
1394#endif
1395 // mount the chroot dir on top of /run/firejail/mnt/oroot in order to reuse the apparmor rules for overlay
1396 // and chroot into this new directory
1397 if (arg_debug)
1398 printf("Chrooting into %s\n", rootdir);
1399 char *oroot = RUN_OVERLAY_ROOT;
1400 if (mkdir(oroot, 0755) == -1)
1401 errExit("mkdir");
1402 if (mount(rootdir, oroot, NULL, MS_BIND|MS_REC, NULL) < 0)
1403 errExit("mounting rootdir oroot");
1404 if (chroot(oroot) < 0)
1405 errExit("chroot");
1406
1407 // create all other /run/firejail files and directories
1408 preproc_build_firejail_dir();
1409
1410 // update /var directory in order to support multiple sandboxes running on the same root directory
1411// if (!arg_private_dev)
1412// fs_dev_shm();
1413 fs_var_lock();
1414 if (!arg_keep_var_tmp)
1415 fs_var_tmp();
1416 if (!arg_writable_var_log)
1417 fs_var_log();
1418
1419 fs_var_lib();
1420 fs_var_cache();
1421 fs_var_utmp();
1422 fs_machineid();
1423
1424 // don't leak user information
1425 restrict_users();
1426
1427 // when starting as root, firejail config is not disabled;
1428 if (getuid() != 0)
1429 disable_config();
1430}
1431#endif
1432#endif // LTS
1433 783
1434// this function is called from sandbox.c before blacklist/whitelist functions 784// this function is called from sandbox.c before blacklist/whitelist functions
1435void fs_private_tmp(void) { 785void fs_private_tmp(void) {
diff --git a/src/firejail/fs_etc.c b/src/firejail/fs_etc.c
index 8e8739436..fc6ac525e 100644
--- a/src/firejail/fs_etc.c
+++ b/src/firejail/fs_etc.c
@@ -74,115 +74,3 @@ void fs_machineid(void) {
74 } 74 }
75} 75}
76 76
77#ifndef LTS
78// return 0 if file not found, 1 if found
79static int check_dir_or_file(const char *fname) {
80 assert(fname);
81
82 struct stat s;
83 if (stat(fname, &s) == -1) {
84 if (arg_debug)
85 fwarning("file %s not found.\n", fname);
86 return 0;
87 }
88
89 // read access
90 if (access(fname, R_OK) == -1)
91 goto errexit;
92
93 // dir or regular file
94 if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode) || !is_link(fname))
95 return 1; // normal exit
96
97errexit:
98 fprintf(stderr, "Error: invalid file type, %s.\n", fname);
99 exit(1);
100}
101
102static void duplicate(const char *fname, const char *private_dir, const char *private_run_dir) {
103 assert(fname);
104
105 if (*fname == '~' || strchr(fname, '/') || strcmp(fname, "..") == 0) {
106 fprintf(stderr, "Error: \"%s\" is an invalid filename\n", fname);
107 exit(1);
108 }
109 invalid_filename(fname, 0); // no globbing
110
111 char *src;
112 if (asprintf(&src, "%s/%s", private_dir, fname) == -1)
113 errExit("asprintf");
114 if (check_dir_or_file(src) == 0) {
115 fwarning("skipping %s for private %s\n", fname, private_dir);
116 free(src);
117 return;
118 }
119
120 if (arg_debug)
121 printf("copying %s to private %s\n", src, private_dir);
122
123 struct stat s;
124 if (stat(src, &s) == 0 && S_ISDIR(s.st_mode)) {
125 // create the directory in RUN_ETC_DIR
126 char *dirname;
127 if (asprintf(&dirname, "%s/%s", private_run_dir, fname) == -1)
128 errExit("asprintf");
129 create_empty_dir_as_root(dirname, s.st_mode);
130 sbox_run(SBOX_ROOT| SBOX_SECCOMP, 3, PATH_FCOPY, src, dirname);
131 free(dirname);
132 }
133 else
134 sbox_run(SBOX_ROOT| SBOX_SECCOMP, 3, PATH_FCOPY, src, private_run_dir);
135
136 fs_logger2("clone", src);
137 free(src);
138}
139
140
141void fs_private_dir_list(const char *private_dir, const char *private_run_dir, const char *private_list) {
142 assert(private_dir);
143 assert(private_run_dir);
144 assert(private_list);
145
146 timetrace_start();
147
148 // create /run/firejail/mnt/etc directory
149 mkdir_attr(private_run_dir, 0755, 0, 0);
150 fs_logger2("tmpfs", private_dir);
151
152 fs_logger_print(); // save the current log
153
154
155 // copy the list of files in the new etc directory
156 // using a new child process with root privileges
157 if (*private_list != '\0') {
158 if (arg_debug)
159 printf("Copying files in the new %s directory:\n", private_dir);
160
161 // copy the list of files in the new home directory
162 char *dlist = strdup(private_list);
163 if (!dlist)
164 errExit("strdup");
165
166
167 char *ptr = strtok(dlist, ",");
168 if (!ptr) {
169 fprintf(stderr, "Error: invalid private %s argument\n", private_dir);
170 exit(1);
171 }
172 duplicate(ptr, private_dir, private_run_dir);
173
174 while ((ptr = strtok(NULL, ",")) != NULL)
175 duplicate(ptr, private_dir, private_run_dir);
176 free(dlist);
177 fs_logger_print();
178 }
179
180 if (arg_debug)
181 printf("Mount-bind %s on top of %s\n", private_run_dir, private_dir);
182 if (mount(private_run_dir, private_dir, NULL, MS_BIND|MS_REC, NULL) < 0)
183 errExit("mount bind");
184 fs_logger2("mount", private_dir);
185
186 fmessage("Private %s installed in %0.2f ms\n", private_dir, timetrace_end());
187}
188#endif
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c
index 866b750b0..1ac03e4dc 100644
--- a/src/firejail/fs_home.c
+++ b/src/firejail/fs_home.c
@@ -366,175 +366,3 @@ void fs_check_private_dir(void) {
366 } 366 }
367} 367}
368 368
369//***********************************************************************************
370// --private-home
371//***********************************************************************************
372#ifndef LTS
373static char *check_dir_or_file(const char *name) {
374 assert(name);
375
376 // basic checks
377 invalid_filename(name, 0); // no globbing
378 if (arg_debug)
379 printf("Private home: checking %s\n", name);
380
381 // expand home directory
382 char *fname = expand_home(name, cfg.homedir);
383 assert(fname);
384
385 // If it doesn't start with '/', it must be relative to homedir
386 if (fname[0] != '/') {
387 char* tmp;
388 if (asprintf(&tmp, "%s/%s", cfg.homedir, fname) == -1)
389 errExit("asprintf");
390 free(fname);
391 fname = tmp;
392 }
393
394 // we allow only files in user home directory or symbolic links to files or directories owned by the user
395 struct stat s;
396 if (lstat(fname, &s) == 0 && S_ISLNK(s.st_mode)) {
397 if (stat(fname, &s) == 0) {
398 if (s.st_uid != getuid()) {
399 fprintf(stderr, "Error: symbolic link %s to file or directory not owned by the user\n", fname);
400 exit(1);
401 }
402 return fname;
403 }
404 else // dangling link
405 goto errexit;
406 }
407 else {
408 // check the file is in user home directory, a full home directory is not allowed
409 char *rname = realpath(fname, NULL);
410 if (!rname ||
411 strncmp(rname, cfg.homedir, strlen(cfg.homedir)) != 0 ||
412 strcmp(rname, cfg.homedir) == 0)
413 goto errexit;
414
415 // only top files and directories in user home are allowed
416 char *ptr = rname + strlen(cfg.homedir);
417 if (*ptr != '/')
418 goto errexit;
419 ptr = strchr(++ptr, '/');
420 if (ptr) {
421 fprintf(stderr, "Error: only top files and directories in user home are allowed\n");
422 exit(1);
423 }
424 free(fname);
425 return rname;
426 }
427
428errexit:
429 fprintf(stderr, "Error: invalid file %s\n", name);
430 exit(1);
431}
432
433static void duplicate(char *name) {
434 char *fname = check_dir_or_file(name);
435
436 if (arg_debug)
437 printf("Private home: duplicating %s\n", fname);
438 assert(strncmp(fname, cfg.homedir, strlen(cfg.homedir)) == 0);
439
440 struct stat s;
441 if (lstat(fname, &s) == -1) {
442 free(fname);
443 return;
444 }
445 else if (S_ISDIR(s.st_mode)) {
446 // create the directory in RUN_HOME_DIR
447 char *name;
448 char *ptr = strrchr(fname, '/');
449 ptr++;
450 if (asprintf(&name, "%s/%s", RUN_HOME_DIR, ptr) == -1)
451 errExit("asprintf");
452 mkdir_attr(name, 0755, getuid(), getgid());
453 sbox_run(SBOX_USER| SBOX_CAPS_NONE | SBOX_SECCOMP, 3, PATH_FCOPY, fname, name);
454 free(name);
455 }
456 else
457 sbox_run(SBOX_USER| SBOX_CAPS_NONE | SBOX_SECCOMP, 3, PATH_FCOPY, fname, RUN_HOME_DIR);
458 fs_logger2("clone", fname);
459 fs_logger_print(); // save the current log
460
461 free(fname);
462}
463
464// private mode (--private-home=list):
465// mount homedir on top of /home/user,
466// tmpfs on top of /root in nonroot mode,
467// tmpfs on top of /tmp in root mode,
468// set skel files,
469// restore .Xauthority
470void fs_private_home_list(void) {
471 timetrace_start();
472
473 char *homedir = cfg.homedir;
474 char *private_list = cfg.home_private_keep;
475 assert(homedir);
476 assert(private_list);
477
478 int xflag = store_xauthority();
479 int aflag = store_asoundrc();
480
481 uid_t uid = getuid();
482 gid_t gid = getgid();
483
484 // create /run/firejail/mnt/home directory
485 mkdir_attr(RUN_HOME_DIR, 0755, uid, gid);
486 fs_logger_print(); // save the current log
487
488 if (arg_debug)
489 printf("Copying files in the new home:\n");
490
491 // copy the list of files in the new home directory
492 char *dlist = strdup(cfg.home_private_keep);
493 if (!dlist)
494 errExit("strdup");
495
496 char *ptr = strtok(dlist, ",");
497 if (!ptr) {
498 fprintf(stderr, "Error: invalid private-home argument\n");
499 exit(1);
500 }
501 duplicate(ptr);
502 while ((ptr = strtok(NULL, ",")) != NULL)
503 duplicate(ptr);
504
505 fs_logger_print(); // save the current log
506 free(dlist);
507
508 if (arg_debug)
509 printf("Mount-bind %s on top of %s\n", RUN_HOME_DIR, homedir);
510
511 if (mount(RUN_HOME_DIR, homedir, NULL, MS_BIND|MS_REC, NULL) < 0)
512 errExit("mount bind");
513 fs_logger2("tmpfs", homedir);
514
515 if (uid != 0) {
516 // mask /root
517 if (arg_debug)
518 printf("Mounting a new /root directory\n");
519 if (mount("tmpfs", "/root", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=700,gid=0") < 0)
520 errExit("mounting home directory");
521 }
522 else {
523 // mask /home
524 if (arg_debug)
525 printf("Mounting a new /home directory\n");
526 if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
527 errExit("mounting home directory");
528 }
529
530 skel(homedir, uid, gid);
531 if (xflag)
532 copy_xauthority();
533 if (aflag)
534 copy_asoundrc();
535
536 if (!arg_quiet)
537 fprintf(stderr, "Home directory installed in %0.2f ms\n", timetrace_end());
538
539}
540#endif //LTS \ No newline at end of file
diff --git a/src/firejail/fs_trace.c b/src/firejail/fs_trace.c
index e1320433c..2668c8429 100644
--- a/src/firejail/fs_trace.c
+++ b/src/firejail/fs_trace.c
@@ -53,15 +53,6 @@ void fs_trace(void) {
53 errExit("fopen"); 53 errExit("fopen");
54 const char *prefix = LIBDIR "/firejail"; 54 const char *prefix = LIBDIR "/firejail";
55 55
56#ifndef LTS
57 if (arg_trace) {
58 fprintf(fp, "%s/libtrace.so\n", prefix);
59 }
60 else if (arg_tracelog) {
61 fprintf(fp, "%s/libtracelog.so\n", prefix);
62 fmessage("Blacklist violations are logged to syslog\n");
63 }
64#endif
65 if (arg_seccomp_postexec) { 56 if (arg_seccomp_postexec) {
66 fprintf(fp, "%s/libpostexecseccomp.so\n", prefix); 57 fprintf(fp, "%s/libpostexecseccomp.so\n", prefix);
67 fmessage("Post-exec seccomp protector enabled\n"); 58 fmessage("Post-exec seccomp protector enabled\n");
diff --git a/src/firejail/join.c b/src/firejail/join.c
index bf421d5d1..852796c20 100644
--- a/src/firejail/join.c
+++ b/src/firejail/join.c
@@ -121,21 +121,6 @@ static void extract_cpu(pid_t pid) {
121 free(fname); 121 free(fname);
122} 122}
123 123
124#ifndef LTS
125static void extract_cgroup(pid_t pid) {
126 char *fname;
127 if (asprintf(&fname, "/proc/%d/root%s", pid, RUN_CGROUP_CFG) == -1)
128 errExit("asprintf");
129
130 struct stat s;
131 if (stat(fname, &s) == -1)
132 return;
133
134 // there is a cgroup file CGROUP_CFG, load it!
135 load_cgroup(fname);
136 free(fname);
137}
138#endif
139 124
140static void extract_caps_seccomp(pid_t pid) { 125static void extract_caps_seccomp(pid_t pid) {
141 // open stat file 126 // open stat file
@@ -289,19 +274,10 @@ void join(pid_t pid, int argc, char **argv, int index) {
289 if (getuid() != 0) { 274 if (getuid() != 0) {
290 extract_caps_seccomp(pid); 275 extract_caps_seccomp(pid);
291 extract_cpu(pid); 276 extract_cpu(pid);
292#ifndef LTS
293 extract_cgroup(pid);
294#endif
295 extract_nogroups(pid); 277 extract_nogroups(pid);
296 extract_user_namespace(pid); 278 extract_user_namespace(pid);
297 } 279 }
298 280
299#ifndef LTS
300 // set cgroup
301 if (cfg.cgroup) // not available for uid 0
302 set_cgroup(cfg.cgroup);
303#endif
304
305 // get umask, it will be set by start_application() 281 // get umask, it will be set by start_application()
306 extract_umask(pid); 282 extract_umask(pid);
307 283
diff --git a/src/firejail/main.c b/src/firejail/main.c
index d35d8c207..6709d6a6c 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -66,10 +66,6 @@ int arg_caps_drop_all = 0; // drop all capabilities
66int arg_caps_keep = 0; // keep list 66int arg_caps_keep = 0; // keep list
67char *arg_caps_list = NULL; // optional caps list 67char *arg_caps_list = NULL; // optional caps list
68 68
69#ifndef LTS
70int arg_trace = 0; // syscall tracing support
71int arg_tracelog = 0; // blacklist tracing support
72#endif
73int arg_rlimit_cpu = 0; // rlimit max cpu time 69int arg_rlimit_cpu = 0; // rlimit max cpu time
74int arg_rlimit_nofile = 0; // rlimit nofile 70int arg_rlimit_nofile = 0; // rlimit nofile
75int arg_rlimit_nproc = 0; // rlimit nproc 71int arg_rlimit_nproc = 0; // rlimit nproc
@@ -344,42 +340,6 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
344 exit(0); 340 exit(0);
345 } 341 }
346#endif 342#endif
347#ifndef LTS
348#ifdef HAVE_X11
349 else if (strcmp(argv[i], "--x11") == 0) {
350 if (checkcfg(CFG_X11)) {
351 x11_start(argc, argv);
352 exit(0);
353 }
354 else
355 exit_err_feature("x11");
356 }
357 else if (strcmp(argv[i], "--x11=xpra") == 0) {
358 if (checkcfg(CFG_X11)) {
359 x11_start_xpra(argc, argv);
360 exit(0);
361 }
362 else
363 exit_err_feature("x11");
364 }
365 else if (strcmp(argv[i], "--x11=xephyr") == 0) {
366 if (checkcfg(CFG_X11)) {
367 x11_start_xephyr(argc, argv);
368 exit(0);
369 }
370 else
371 exit_err_feature("x11");
372 }
373 else if (strcmp(argv[i], "--x11=xvfb") == 0) {
374 if (checkcfg(CFG_X11)) {
375 x11_start_xvfb(argc, argv);
376 exit(0);
377 }
378 else
379 exit_err_feature("x11");
380 }
381#endif
382#endif // LTS
383#ifdef HAVE_NETWORK 343#ifdef HAVE_NETWORK
384 else if (strncmp(argv[i], "--bandwidth=", 12) == 0) { 344 else if (strncmp(argv[i], "--bandwidth=", 12) == 0) {
385 if (checkcfg(CFG_NETWORK)) { 345 if (checkcfg(CFG_NETWORK)) {
@@ -598,88 +558,6 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
598 exit_err_feature("networking"); 558 exit_err_feature("networking");
599 } 559 }
600#endif 560#endif
601#ifndef LTS
602#ifdef HAVE_FILE_TRANSFER
603 else if (strncmp(argv[i], "--get=", 6) == 0) {
604 if (checkcfg(CFG_FILE_TRANSFER)) {
605 logargs(argc, argv);
606
607 // verify path
608 if ((i + 2) != argc) {
609 fprintf(stderr, "Error: invalid --get option, path expected\n");
610 exit(1);
611 }
612 char *path = argv[i + 1];
613 invalid_filename(path, 0); // no globbing
614 if (strstr(path, "..")) {
615 fprintf(stderr, "Error: invalid file name %s\n", path);
616 exit(1);
617 }
618
619 // get file
620 pid_t pid = require_pid(argv[i] + 6);
621 sandboxfs(SANDBOX_FS_GET, pid, path, NULL);
622 exit(0);
623 }
624 else
625 exit_err_feature("file transfer");
626 }
627 else if (strncmp(argv[i], "--put=", 6) == 0) {
628 if (checkcfg(CFG_FILE_TRANSFER)) {
629 logargs(argc, argv);
630
631 // verify path
632 if ((i + 3) != argc) {
633 fprintf(stderr, "Error: invalid --put option, 2 paths expected\n");
634 exit(1);
635 }
636 char *path1 = argv[i + 1];
637 invalid_filename(path1, 0); // no globbing
638 if (strstr(path1, "..")) {
639 fprintf(stderr, "Error: invalid file name %s\n", path1);
640 exit(1);
641 }
642 char *path2 = argv[i + 2];
643 invalid_filename(path2, 0); // no globbing
644 if (strstr(path2, "..")) {
645 fprintf(stderr, "Error: invalid file name %s\n", path2);
646 exit(1);
647 }
648
649 // get file
650 pid_t pid = require_pid(argv[i] + 6);
651 sandboxfs(SANDBOX_FS_PUT, pid, path1, path2);
652 exit(0);
653 }
654 else
655 exit_err_feature("file transfer");
656 }
657 else if (strncmp(argv[i], "--ls=", 5) == 0) {
658 if (checkcfg(CFG_FILE_TRANSFER)) {
659 logargs(argc, argv);
660
661 // verify path
662 if ((i + 2) != argc) {
663 fprintf(stderr, "Error: invalid --ls option, path expected\n");
664 exit(1);
665 }
666 char *path = argv[i + 1];
667 invalid_filename(path, 0); // no globbing
668 if (strstr(path, "..")) {
669 fprintf(stderr, "Error: invalid file name %s\n", path);
670 exit(1);
671 }
672
673 // list directory contents
674 pid_t pid = require_pid(argv[i] + 5);
675 sandboxfs(SANDBOX_FS_LS, pid, path, NULL);
676 exit(0);
677 }
678 else
679 exit_err_feature("file transfer");
680 }
681#endif
682#endif
683 else if (strncmp(argv[i], "--join=", 7) == 0) { 561 else if (strncmp(argv[i], "--join=", 7) == 0) {
684 if (checkcfg(CFG_JOIN) || getuid() == 0) { 562 if (checkcfg(CFG_JOIN) || getuid() == 0) {
685 logargs(argc, argv); 563 logargs(argc, argv);
@@ -831,29 +709,6 @@ static int check_arg(int argc, char **argv, const char *argument, int strict) {
831 return found; 709 return found;
832} 710}
833 711
834#ifndef LTS
835static void run_builder(int argc, char **argv) {
836 EUID_ASSERT();
837 (void) argc;
838
839 // drop privileges
840 EUID_ROOT();
841 if (setgid(getgid()) < 0)
842 errExit("setgid/getgid");
843 if (setuid(getuid()) < 0)
844 errExit("setuid/getuid");
845
846 assert(getenv("LD_PRELOAD") == NULL);
847 umask(orig_umask);
848
849 argv[0] = LIBDIR "/firejail/fbuilder";
850 execvp(argv[0], argv);
851
852 perror("execvp");
853 exit(1);
854}
855#endif // LTS
856
857//******************************************* 712//*******************************************
858// Main program 713// Main program
859//******************************************* 714//*******************************************
@@ -930,11 +785,6 @@ int main(int argc, char **argv) {
930 profile_add(cmd); 785 profile_add(cmd);
931 } 786 }
932 787
933#ifndef LTS
934 // profile builder
935 if (check_arg(argc, argv, "--build", 0)) // supports both --build and --build=filename
936 run_builder(argc, argv); // this function will not return
937#endif // LTS
938 // check argv[0] symlink wrapper if this is not a login shell 788 // check argv[0] symlink wrapper if this is not a login shell
939 if (*argv[0] != '-') 789 if (*argv[0] != '-')
940 run_symlink(argc, argv, 0); // if symlink detected, this function will not return 790 run_symlink(argc, argv, 0); // if symlink detected, this function will not return
@@ -967,113 +817,6 @@ int main(int argc, char **argv) {
967 delete_run_files(sandbox_pid); 817 delete_run_files(sandbox_pid);
968 EUID_USER(); 818 EUID_USER();
969 819
970#ifndef LTS
971 //check if the parent is sshd daemon
972 int parent_sshd = 0;
973 {
974 pid_t ppid = getppid();
975 EUID_ROOT();
976 char *comm = pid_proc_comm(ppid);
977 EUID_USER();
978 if (comm) {
979 if (strcmp(comm, "sshd") == 0) {
980 arg_quiet = 1;
981 parent_sshd = 1;
982
983#ifdef DEBUG_RESTRICTED_SHELL
984 {EUID_ROOT();
985 FILE *fp = fopen("/firelog", "w");
986 if (fp) {
987 int i;
988 fprintf(fp, "argc %d: ", argc);
989 for (i = 0; i < argc; i++)
990 fprintf(fp, "#%s# ", argv[i]);
991 fprintf(fp, "\n");
992 fclose(fp);
993 }
994 EUID_USER();}
995#endif
996 // run sftp and scp directly without any sandboxing
997 // regular login has argv[0] == "-firejail"
998 if (*argv[0] != '-') {
999 if (strcmp(argv[1], "-c") == 0 && argc > 2) {
1000 if (strcmp(argv[2], "/usr/lib/openssh/sftp-server") == 0 ||
1001 strncmp(argv[2], "scp ", 4) == 0) {
1002#ifdef DEBUG_RESTRICTED_SHELL
1003 {EUID_ROOT();
1004 FILE *fp = fopen("/firelog", "a");
1005 if (fp) {
1006 fprintf(fp, "run without a sandbox\n");
1007 fclose(fp);
1008 }
1009 EUID_USER();}
1010#endif
1011
1012 drop_privs(1);
1013 umask(orig_umask);
1014 int rv = system(argv[2]);
1015 exit(rv);
1016 }
1017 }
1018 }
1019 }
1020 free(comm);
1021 }
1022 }
1023 EUID_ASSERT();
1024
1025 // is this a login shell, or a command passed by sshd, insert command line options from /etc/firejail/login.users
1026 if (*argv[0] == '-' || parent_sshd) {
1027 if (argc == 1)
1028 login_shell = 1;
1029 fullargc = restricted_shell(cfg.username);
1030 if (fullargc) {
1031
1032#ifdef DEBUG_RESTRICTED_SHELL
1033 {EUID_ROOT();
1034 FILE *fp = fopen("/firelog", "a");
1035 if (fp) {
1036 fprintf(fp, "fullargc %d: ", fullargc);
1037 int i;
1038 for (i = 0; i < fullargc; i++)
1039 fprintf(fp, "#%s# ", fullargv[i]);
1040 fprintf(fp, "\n");
1041 fclose(fp);
1042 }
1043 EUID_USER();}
1044#endif
1045
1046 int j;
1047 for (i = 1, j = fullargc; i < argc && j < MAX_ARGS; i++, j++, fullargc++)
1048 fullargv[j] = argv[i];
1049
1050 // replace argc/argv with fullargc/fullargv
1051 argv = fullargv;
1052 argc = j;
1053
1054#ifdef DEBUG_RESTRICTED_SHELL
1055 {EUID_ROOT();
1056 FILE *fp = fopen("/firelog", "a");
1057 if (fp) {
1058 fprintf(fp, "argc %d: ", argc);
1059 int i;
1060 for (i = 0; i < argc; i++)
1061 fprintf(fp, "#%s# ", argv[i]);
1062 fprintf(fp, "\n");
1063 fclose(fp);
1064 }
1065 EUID_USER();}
1066#endif
1067 }
1068 }
1069 else {
1070 // check --output option and execute it;
1071 check_output(argc, argv); // the function will not return if --output or --output-stderr option was found
1072 }
1073#endif // LTS
1074 EUID_ASSERT();
1075
1076
1077 // check for force-nonewprivs in /etc/firejail/firejail.config file 820 // check for force-nonewprivs in /etc/firejail/firejail.config file
1078 if (checkcfg(CFG_FORCE_NONEWPRIVS)) 821 if (checkcfg(CFG_FORCE_NONEWPRIVS))
1079 arg_nonewprivs = 1; 822 arg_nonewprivs = 1;
@@ -1224,42 +967,6 @@ int main(int argc, char **argv) {
1224 } 967 }
1225 968
1226 969
1227#ifndef LTS
1228 else if (strcmp(argv[i], "--trace") == 0)
1229 arg_trace = 1;
1230 else if (strcmp(argv[i], "--tracelog") == 0)
1231 arg_tracelog = 1;
1232 else if (strncmp(argv[i], "--rlimit-cpu=", 13) == 0) {
1233 check_unsigned(argv[i] + 13, "Error: invalid rlimit");
1234 sscanf(argv[i] + 13, "%llu", &cfg.rlimit_cpu);
1235 arg_rlimit_cpu = 1;
1236 }
1237 else if (strncmp(argv[i], "--rlimit-nofile=", 16) == 0) {
1238 check_unsigned(argv[i] + 16, "Error: invalid rlimit");
1239 sscanf(argv[i] + 16, "%llu", &cfg.rlimit_nofile);
1240 arg_rlimit_nofile = 1;
1241 }
1242 else if (strncmp(argv[i], "--rlimit-nproc=", 15) == 0) {
1243 check_unsigned(argv[i] + 15, "Error: invalid rlimit");
1244 sscanf(argv[i] + 15, "%llu", &cfg.rlimit_nproc);
1245 arg_rlimit_nproc = 1;
1246 }
1247 else if (strncmp(argv[i], "--rlimit-fsize=", 15) == 0) {
1248 check_unsigned(argv[i] + 15, "Error: invalid rlimit");
1249 sscanf(argv[i] + 15, "%llu", &cfg.rlimit_fsize);
1250 arg_rlimit_fsize = 1;
1251 }
1252 else if (strncmp(argv[i], "--rlimit-sigpending=", 20) == 0) {
1253 check_unsigned(argv[i] + 20, "Error: invalid rlimit");
1254 sscanf(argv[i] + 20, "%llu", &cfg.rlimit_sigpending);
1255 arg_rlimit_sigpending = 1;
1256 }
1257 else if (strncmp(argv[i], "--rlimit-as=", 12) == 0) {
1258 check_unsigned(argv[i] + 12, "Error: invalid rlimit");
1259 sscanf(argv[i] + 12, "%llu", &cfg.rlimit_as);
1260 arg_rlimit_as = 1;
1261 }
1262#endif
1263 else if (strncmp(argv[i], "--ipc-namespace", 15) == 0) 970 else if (strncmp(argv[i], "--ipc-namespace", 15) == 0)
1264 arg_ipc = 1; 971 arg_ipc = 1;
1265 else if (strncmp(argv[i], "--cpu=", 6) == 0) 972 else if (strncmp(argv[i], "--cpu=", 6) == 0)
@@ -1270,20 +977,6 @@ int main(int argc, char **argv) {
1270 cfg.nice = 0; 977 cfg.nice = 0;
1271 arg_nice = 1; 978 arg_nice = 1;
1272 } 979 }
1273#ifndef LTS
1274 else if (strncmp(argv[i], "--cgroup=", 9) == 0) {
1275 if (option_cgroup) {
1276 fprintf(stderr, "Error: only a cgroup can be defined\n");
1277 exit(1);
1278 }
1279
1280 option_cgroup = 1;
1281 cfg.cgroup = strdup(argv[i] + 9);
1282 if (!cfg.cgroup)
1283 errExit("strdup");
1284 set_cgroup(cfg.cgroup);
1285 }
1286#endif
1287 //************************************* 980 //*************************************
1288 // filesystem 981 // filesystem
1289 //************************************* 982 //*************************************
@@ -1375,95 +1068,6 @@ int main(int argc, char **argv) {
1375 } 1068 }
1376 else if (strcmp(argv[i], "--disable-mnt") == 0) 1069 else if (strcmp(argv[i], "--disable-mnt") == 0)
1377 arg_disable_mnt = 1; 1070 arg_disable_mnt = 1;
1378#ifndef LTS
1379#ifdef HAVE_OVERLAYFS
1380 else if (strcmp(argv[i], "--overlay") == 0) {
1381 if (checkcfg(CFG_OVERLAYFS)) {
1382 if (arg_overlay) {
1383 fprintf(stderr, "Error: only one overlay command is allowed\n");
1384 exit(1);
1385 }
1386
1387 if (cfg.chrootdir) {
1388 fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n");
1389 exit(1);
1390 }
1391 struct stat s;
1392 if (stat("/proc/sys/kernel/grsecurity", &s) == 0) {
1393 fprintf(stderr, "Error: --overlay option is not available on Grsecurity systems\n");
1394 exit(1);
1395 }
1396 arg_overlay = 1;
1397 arg_overlay_keep = 1;
1398
1399 char *subdirname;
1400 if (asprintf(&subdirname, "%d", getpid()) == -1)
1401 errExit("asprintf");
1402 cfg.overlay_dir = fs_check_overlay_dir(subdirname, arg_overlay_reuse);
1403
1404 free(subdirname);
1405 }
1406 else
1407 exit_err_feature("overlayfs");
1408 }
1409 else if (strncmp(argv[i], "--overlay-named=", 16) == 0) {
1410 if (checkcfg(CFG_OVERLAYFS)) {
1411 if (arg_overlay) {
1412 fprintf(stderr, "Error: only one overlay command is allowed\n");
1413 exit(1);
1414 }
1415 if (cfg.chrootdir) {
1416 fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n");
1417 exit(1);
1418 }
1419 struct stat s;
1420 if (stat("/proc/sys/kernel/grsecurity", &s) == 0) {
1421 fprintf(stderr, "Error: --overlay option is not available on Grsecurity systems\n");
1422 exit(1);
1423 }
1424 arg_overlay = 1;
1425 arg_overlay_keep = 1;
1426 arg_overlay_reuse = 1;
1427
1428 char *subdirname = argv[i] + 16;
1429 if (*subdirname == '\0') {
1430 fprintf(stderr, "Error: invalid overlay option\n");
1431 exit(1);
1432 }
1433
1434 // check name
1435 invalid_filename(subdirname, 0); // no globbing
1436 if (strstr(subdirname, "..") || strstr(subdirname, "/")) {
1437 fprintf(stderr, "Error: invalid overlay name\n");
1438 exit(1);
1439 }
1440 cfg.overlay_dir = fs_check_overlay_dir(subdirname, arg_overlay_reuse);
1441 }
1442 else
1443 exit_err_feature("overlayfs");
1444 }
1445 else if (strcmp(argv[i], "--overlay-tmpfs") == 0) {
1446 if (checkcfg(CFG_OVERLAYFS)) {
1447 if (arg_overlay) {
1448 fprintf(stderr, "Error: only one overlay command is allowed\n");
1449 exit(1);
1450 }
1451 if (cfg.chrootdir) {
1452 fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n");
1453 exit(1);
1454 }
1455 struct stat s;
1456 if (stat("/proc/sys/kernel/grsecurity", &s) == 0) {
1457 fprintf(stderr, "Error: --overlay option is not available on Grsecurity systems\n");
1458 exit(1);
1459 }
1460 arg_overlay = 1;
1461 }
1462 else
1463 exit_err_feature("overlayfs");
1464 }
1465#endif
1466#endif //LTS
1467 else if (strncmp(argv[i], "--profile=", 10) == 0) { 1071 else if (strncmp(argv[i], "--profile=", 10) == 0) {
1468 // multiple profile files are allowed! 1072 // multiple profile files are allowed!
1469 1073
@@ -1494,55 +1098,6 @@ int main(int argc, char **argv) {
1494 } 1098 }
1495 profile_add_ignore(argv[i] + 9); 1099 profile_add_ignore(argv[i] + 9);
1496 } 1100 }
1497#ifndef LTS
1498#ifdef HAVE_CHROOT
1499 else if (strncmp(argv[i], "--chroot=", 9) == 0) {
1500 if (checkcfg(CFG_CHROOT)) {
1501 if (arg_overlay) {
1502 fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n");
1503 exit(1);
1504 }
1505
1506 struct stat s;
1507 if (stat("/proc/sys/kernel/grsecurity", &s) == 0) {
1508 fprintf(stderr, "Error: --chroot option is not available on Grsecurity systems\n");
1509 exit(1);
1510 }
1511
1512
1513 invalid_filename(argv[i] + 9, 0); // no globbing
1514
1515 // extract chroot dirname
1516 cfg.chrootdir = argv[i] + 9;
1517 // if the directory starts with ~, expand the home directory
1518 if (*cfg.chrootdir == '~') {
1519 char *tmp;
1520 if (asprintf(&tmp, "%s%s", cfg.homedir, cfg.chrootdir + 1) == -1)
1521 errExit("asprintf");
1522 cfg.chrootdir = tmp;
1523 }
1524
1525 if (strstr(cfg.chrootdir, "..") || is_link(cfg.chrootdir)) {
1526 fprintf(stderr, "Error: invalid chroot directory %s\n", cfg.chrootdir);
1527 return 1;
1528 }
1529
1530 // check chroot dirname exists, don't allow "--chroot=/"
1531 char *rpath = realpath(cfg.chrootdir, NULL);
1532 if (rpath == NULL || strcmp(rpath, "/") == 0) {
1533 fprintf(stderr, "Error: invalid chroot directory\n");
1534 exit(1);
1535 }
1536 cfg.chrootdir = rpath;
1537
1538 // check chroot directory structure
1539 fs_check_chroot_dir(cfg.chrootdir);
1540 }
1541 else
1542 exit_err_feature("chroot");
1543 }
1544#endif
1545#endif // LTS
1546 else if (strcmp(argv[i], "--writable-etc") == 0) { 1101 else if (strcmp(argv[i], "--writable-etc") == 0) {
1547 if (cfg.etc_private_keep) { 1102 if (cfg.etc_private_keep) {
1548 fprintf(stderr, "Error: --private-etc and --writable-etc are mutually exclusive\n"); 1103 fprintf(stderr, "Error: --private-etc and --writable-etc are mutually exclusive\n");
@@ -1589,112 +1144,12 @@ int main(int argc, char **argv) {
1589 } 1144 }
1590 arg_private = 1; 1145 arg_private = 1;
1591 } 1146 }
1592#ifndef LTS
1593#ifdef HAVE_PRIVATE_HOME
1594 else if (strncmp(argv[i], "--private-home=", 15) == 0) {
1595 if (checkcfg(CFG_PRIVATE_HOME)) {
1596 if (cfg.home_private) {
1597 fprintf(stderr, "Error: a private home directory was already defined with --private option.\n");
1598 exit(1);
1599 }
1600
1601 // extract private home dirname
1602 if (*(argv[i] + 15) == '\0') {
1603 fprintf(stderr, "Error: invalid private-home option\n");
1604 exit(1);
1605 }
1606 if (cfg.home_private_keep) {
1607 if ( asprintf(&cfg.home_private_keep, "%s,%s", cfg.home_private_keep, argv[i] + 15) < 0 )
1608 errExit("asprintf");
1609 } else
1610 cfg.home_private_keep = argv[i] + 15;
1611 arg_private = 1;
1612 }
1613 else
1614 exit_err_feature("private-home");
1615 }
1616#endif
1617#endif //LTS
1618 else if (strcmp(argv[i], "--private-dev") == 0) { 1147 else if (strcmp(argv[i], "--private-dev") == 0) {
1619 arg_private_dev = 1; 1148 arg_private_dev = 1;
1620 } 1149 }
1621 else if (strcmp(argv[i], "--keep-dev-shm") == 0) { 1150 else if (strcmp(argv[i], "--keep-dev-shm") == 0) {
1622 arg_keep_dev_shm = 1; 1151 arg_keep_dev_shm = 1;
1623 } 1152 }
1624#ifndef LTS
1625 else if (strncmp(argv[i], "--private-etc=", 14) == 0) {
1626 if (arg_writable_etc) {
1627 fprintf(stderr, "Error: --private-etc and --writable-etc are mutually exclusive\n");
1628 exit(1);
1629 }
1630
1631 // extract private etc list
1632 if (*(argv[i] + 14) == '\0') {
1633 fprintf(stderr, "Error: invalid private-etc option\n");
1634 exit(1);
1635 }
1636 if (cfg.etc_private_keep) {
1637 if ( asprintf(&cfg.etc_private_keep, "%s,%s", cfg.etc_private_keep, argv[i] + 14) < 0 )
1638 errExit("asprintf");
1639 } else
1640 cfg.etc_private_keep = argv[i] + 14;
1641 arg_private_etc = 1;
1642 }
1643 else if (strncmp(argv[i], "--private-opt=", 14) == 0) {
1644 // extract private opt list
1645 if (*(argv[i] + 14) == '\0') {
1646 fprintf(stderr, "Error: invalid private-opt option\n");
1647 exit(1);
1648 }
1649 if (cfg.opt_private_keep) {
1650 if ( asprintf(&cfg.opt_private_keep, "%s,%s", cfg.opt_private_keep, argv[i] + 14) < 0 )
1651 errExit("asprintf");
1652 } else
1653 cfg.opt_private_keep = argv[i] + 14;
1654 arg_private_opt = 1;
1655 }
1656 else if (strncmp(argv[i], "--private-srv=", 14) == 0) {
1657 // extract private srv list
1658 if (*(argv[i] + 14) == '\0') {
1659 fprintf(stderr, "Error: invalid private-srv option\n");
1660 exit(1);
1661 }
1662 if (cfg.srv_private_keep) {
1663 if ( asprintf(&cfg.srv_private_keep, "%s,%s", cfg.srv_private_keep, argv[i] + 14) < 0 )
1664 errExit("asprintf");
1665 } else
1666 cfg.srv_private_keep = argv[i] + 14;
1667 arg_private_srv = 1;
1668 }
1669 else if (strncmp(argv[i], "--private-bin=", 14) == 0) {
1670 // extract private bin list
1671 if (*(argv[i] + 14) == '\0') {
1672 fprintf(stderr, "Error: invalid private-bin option\n");
1673 exit(1);
1674 }
1675 if (cfg.bin_private_keep) {
1676 if ( asprintf(&cfg.bin_private_keep, "%s,%s", cfg.bin_private_keep, argv[i] + 14) < 0 )
1677 errExit("asprintf");
1678 } else
1679 cfg.bin_private_keep = argv[i] + 14;
1680 arg_private_bin = 1;
1681 }
1682 else if (strncmp(argv[i], "--private-lib", 13) == 0) {
1683 if (checkcfg(CFG_PRIVATE_LIB)) {
1684 // extract private lib list (if any)
1685 if (argv[i][13] == '=') {
1686 if (cfg.lib_private_keep) {
1687 if (argv[i][14] != '\0' && asprintf(&cfg.lib_private_keep, "%s,%s", cfg.lib_private_keep, argv[i] + 14) < 0)
1688 errExit("asprintf");
1689 } else
1690 cfg.lib_private_keep = argv[i] + 14;
1691 }
1692 arg_private_lib = 1;
1693 }
1694 else
1695 exit_err_feature("private-lib");
1696 }
1697#endif // LTS
1698 else if (strcmp(argv[i], "--private-tmp") == 0) { 1153 else if (strcmp(argv[i], "--private-tmp") == 0) {
1699 arg_private_tmp = 1; 1154 arg_private_tmp = 1;
1700 } 1155 }
@@ -2110,28 +1565,6 @@ int main(int argc, char **argv) {
2110 //************************************* 1565 //*************************************
2111 else if (strncmp(argv[i], "--timeout=", 10) == 0) 1566 else if (strncmp(argv[i], "--timeout=", 10) == 0)
2112 cfg.timeout = extract_timeout(argv[i] + 10); 1567 cfg.timeout = extract_timeout(argv[i] + 10);
2113#ifndef LTS
2114 else if (strcmp(argv[i], "--audit") == 0) {
2115 arg_audit_prog = LIBDIR "/firejail/faudit";
2116 arg_audit = 1;
2117 }
2118 else if (strncmp(argv[i], "--audit=", 8) == 0) {
2119 if (strlen(argv[i] + 8) == 0) {
2120 fprintf(stderr, "Error: invalid audit program\n");
2121 exit(1);
2122 }
2123 arg_audit_prog = strdup(argv[i] + 8);
2124 if (!arg_audit_prog)
2125 errExit("strdup");
2126
2127 struct stat s;
2128 if (stat(arg_audit_prog, &s) != 0) {
2129 fprintf(stderr, "Error: cannot find the audit program %s\n", arg_audit_prog);
2130 exit(1);
2131 }
2132 arg_audit = 1;
2133 }
2134#endif // LTS
2135 else if (strcmp(argv[i], "--appimage") == 0) 1568 else if (strcmp(argv[i], "--appimage") == 0)
2136 arg_appimage = 1; 1569 arg_appimage = 1;
2137 else if (strcmp(argv[i], "--shell=none") == 0) { 1570 else if (strcmp(argv[i], "--shell=none") == 0) {
@@ -2255,12 +1688,6 @@ int main(int argc, char **argv) {
2255 exit(1); 1688 exit(1);
2256 } 1689 }
2257 1690
2258#ifndef LTS
2259 // check trace configuration
2260 if (arg_trace && arg_tracelog) {
2261 fwarning("--trace and --tracelog are mutually exclusive; --tracelog disabled\n");
2262 }
2263#endif
2264 // check user namespace (--noroot) options 1691 // check user namespace (--noroot) options
2265 if (arg_noroot) { 1692 if (arg_noroot) {
2266 if (arg_overlay) { 1693 if (arg_overlay) {
@@ -2370,11 +1797,6 @@ int main(int argc, char **argv) {
2370 } 1797 }
2371 EUID_ASSERT(); 1798 EUID_ASSERT();
2372 1799
2373#ifndef LTS
2374 // block X11 sockets
2375 if (arg_x11_block)
2376 x11_block();
2377#endif //LTS
2378 // check network configuration options - it will exit if anything went wrong 1800 // check network configuration options - it will exit if anything went wrong
2379 net_check_cfg(); 1801 net_check_cfg();
2380 1802
@@ -2429,11 +1851,6 @@ int main(int argc, char **argv) {
2429 } 1851 }
2430 if (cfg.name) 1852 if (cfg.name)
2431 set_name_run_file(sandbox_pid); 1853 set_name_run_file(sandbox_pid);
2432#ifndef LTS
2433 int display = x11_display();
2434 if (display > 0)
2435 set_x11_run_file(sandbox_pid, display);
2436#endif
2437 if (lockfd_directory != -1) { 1854 if (lockfd_directory != -1) {
2438 flock(lockfd_directory, LOCK_UN); 1855 flock(lockfd_directory, LOCK_UN);
2439 close(lockfd_directory); 1856 close(lockfd_directory);
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index 5f6707e4b..bce96727d 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -197,33 +197,10 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
197 arg_shell_none = 1; 197 arg_shell_none = 1;
198 return 0; 198 return 0;
199 } 199 }
200#ifndef LTS
201 else if (strcmp(ptr, "tracelog") == 0) {
202 arg_tracelog = 1;
203 return 0;
204 }
205#endif
206 else if (strcmp(ptr, "private") == 0) { 200 else if (strcmp(ptr, "private") == 0) {
207 arg_private = 1; 201 arg_private = 1;
208 return 0; 202 return 0;
209 } 203 }
210#ifndef LTS
211 if (strncmp(ptr, "private-home ", 13) == 0) {
212#ifdef HAVE_PRIVATE_HOME
213 if (checkcfg(CFG_PRIVATE_HOME)) {
214 if (cfg.home_private_keep) {
215 if ( asprintf(&cfg.home_private_keep, "%s,%s", cfg.home_private_keep, ptr + 13) < 0 )
216 errExit("asprintf");
217 } else
218 cfg.home_private_keep = ptr + 13;
219 arg_private = 1;
220 }
221 else
222 warning_feature_disabled("private-home");
223#endif
224 return 0;
225 }
226#endif //LTS
227 else if (strcmp(ptr, "allusers") == 0) { 204 else if (strcmp(ptr, "allusers") == 0) {
228 arg_allusers = 1; 205 arg_allusers = 1;
229 return 0; 206 return 0;
@@ -749,14 +726,6 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
749 return 0; 726 return 0;
750 } 727 }
751 728
752#ifndef LTS
753 // cgroup
754 if (strncmp(ptr, "cgroup ", 7) == 0) {
755 set_cgroup(ptr + 7);
756 return 0;
757 }
758#endif
759
760 // writable-etc 729 // writable-etc
761 if (strcmp(ptr, "writable-etc") == 0) { 730 if (strcmp(ptr, "writable-etc") == 0) {
762 if (cfg.etc_private_keep) { 731 if (cfg.etc_private_keep) {
@@ -804,253 +773,6 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
804 return 0; 773 return 0;
805 } 774 }
806 775
807#ifndef LTS
808 if (strcmp(ptr, "x11 xephyr") == 0) {
809#ifdef HAVE_X11
810 if (checkcfg(CFG_X11)) {
811 char *x11env = getenv("FIREJAIL_X11");
812 if (x11env && strcmp(x11env, "yes") == 0) {
813 return 0;
814 }
815 else {
816 // start x11
817 x11_start_xephyr(cfg.original_argc, cfg.original_argv);
818 exit(0);
819 }
820 }
821 else
822 warning_feature_disabled("x11");
823#endif
824 return 0;
825 }
826
827 if (strcmp(ptr, "x11 xorg") == 0) {
828#ifdef HAVE_X11
829 if (checkcfg(CFG_X11))
830 arg_x11_xorg = 1;
831 else
832 warning_feature_disabled("x11");
833#endif
834 return 0;
835 }
836
837 if (strcmp(ptr, "x11 xpra") == 0) {
838#ifdef HAVE_X11
839 if (checkcfg(CFG_X11)) {
840 char *x11env = getenv("FIREJAIL_X11");
841 if (x11env && strcmp(x11env, "yes") == 0) {
842 return 0;
843 }
844 else {
845 // start x11
846 x11_start_xpra(cfg.original_argc, cfg.original_argv);
847 exit(0);
848 }
849 }
850 else
851 warning_feature_disabled("x11");
852#endif
853 return 0;
854 }
855
856 if (strcmp(ptr, "x11 xvfb") == 0) {
857#ifdef HAVE_X11
858 if (checkcfg(CFG_X11)) {
859 char *x11env = getenv("FIREJAIL_X11");
860 if (x11env && strcmp(x11env, "yes") == 0) {
861 return 0;
862 }
863 else {
864 // start x11
865 x11_start_xvfb(cfg.original_argc, cfg.original_argv);
866 exit(0);
867 }
868 }
869 else
870 warning_feature_disabled("x11");
871#endif
872 return 0;
873 }
874
875 if (strcmp(ptr, "x11") == 0) {
876#ifdef HAVE_X11
877 if (checkcfg(CFG_X11)) {
878 char *x11env = getenv("FIREJAIL_X11");
879 if (x11env && strcmp(x11env, "yes") == 0) {
880 return 0;
881 }
882 else {
883 // start x11
884 x11_start(cfg.original_argc, cfg.original_argv);
885 exit(0);
886 }
887 }
888 else
889 warning_feature_disabled("x11");
890#endif
891 return 0;
892 }
893
894 // private /etc list of files and directories
895 if (strncmp(ptr, "private-etc ", 12) == 0) {
896 if (arg_writable_etc) {
897 fprintf(stderr, "Error: --private-etc and --writable-etc are mutually exclusive\n");
898 exit(1);
899 }
900 if (cfg.etc_private_keep) {
901 if ( asprintf(&cfg.etc_private_keep, "%s,%s", cfg.etc_private_keep, ptr + 12) < 0 )
902 errExit("asprintf");
903 } else {
904 cfg.etc_private_keep = ptr + 12;
905 }
906 arg_private_etc = 1;
907
908 return 0;
909 }
910
911 // private /opt list of files and directories
912 if (strncmp(ptr, "private-opt ", 12) == 0) {
913 if (cfg.opt_private_keep) {
914 if ( asprintf(&cfg.opt_private_keep, "%s,%s", cfg.opt_private_keep, ptr + 12) < 0 )
915 errExit("asprintf");
916 } else {
917 cfg.opt_private_keep = ptr + 12;
918 }
919 arg_private_opt = 1;
920
921 return 0;
922 }
923
924 // private /srv list of files and directories
925 if (strncmp(ptr, "private-srv ", 12) == 0) {
926 if (cfg.srv_private_keep) {
927 if ( asprintf(&cfg.srv_private_keep, "%s,%s", cfg.srv_private_keep, ptr + 12) < 0 )
928 errExit("asprintf");
929 } else {
930 cfg.srv_private_keep = ptr + 12;
931 }
932 arg_private_srv = 1;
933
934 return 0;
935 }
936
937 // private /bin list of files
938 if (strncmp(ptr, "private-bin ", 12) == 0) {
939 if (cfg.bin_private_keep) {
940 if ( asprintf(&cfg.bin_private_keep, "%s,%s", cfg.bin_private_keep, ptr + 12) < 0 )
941 errExit("asprintf");
942 } else {
943 cfg.bin_private_keep = ptr + 12;
944 }
945 arg_private_bin = 1;
946 return 0;
947 }
948
949 // private /lib list of files
950 if (strncmp(ptr, "private-lib", 11) == 0) {
951 if (checkcfg(CFG_PRIVATE_LIB)) {
952 if (ptr[11] == ' ') {
953 if (cfg.lib_private_keep) {
954 if (ptr[12] != '\0' && asprintf(&cfg.lib_private_keep, "%s,%s", cfg.lib_private_keep, ptr + 12) < 0)
955 errExit("asprintf");
956 } else {
957 cfg.lib_private_keep = ptr + 12;
958 }
959 }
960 arg_private_lib = 1;
961 }
962 else
963 warning_feature_disabled("private-lib");
964 return 0;
965 }
966
967
968#ifdef HAVE_OVERLAYFS
969 if (strncmp(ptr, "overlay-named ", 14) == 0) {
970 if (checkcfg(CFG_OVERLAYFS)) {
971 if (arg_overlay) {
972 fprintf(stderr, "Error: only one overlay command is allowed\n");
973 exit(1);
974 }
975 if (cfg.chrootdir) {
976 fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n");
977 exit(1);
978 }
979 struct stat s;
980 if (stat("/proc/sys/kernel/grsecurity", &s) == 0) {
981 fprintf(stderr, "Error: --overlay option is not available on Grsecurity systems\n");
982 exit(1);
983 }
984 arg_overlay = 1;
985 arg_overlay_keep = 1;
986 arg_overlay_reuse = 1;
987
988 char *subdirname = ptr + 14;
989 if (*subdirname == '\0') {
990 fprintf(stderr, "Error: invalid overlay option\n");
991 exit(1);
992 }
993
994 // check name
995 invalid_filename(subdirname, 0); // no globbing
996 if (strstr(subdirname, "..") || strstr(subdirname, "/")) {
997 fprintf(stderr, "Error: invalid overlay name\n");
998 exit(1);
999 }
1000 cfg.overlay_dir = fs_check_overlay_dir(subdirname, arg_overlay_reuse);
1001 }
1002
1003 return 0;
1004 } else if (strcmp(ptr, "overlay-tmpfs") == 0) {
1005 if (checkcfg(CFG_OVERLAYFS)) {
1006 if (arg_overlay) {
1007 fprintf(stderr, "Error: only one overlay command is allowed\n");
1008 exit(1);
1009 }
1010 if (cfg.chrootdir) {
1011 fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n");
1012 exit(1);
1013 }
1014 struct stat s;
1015 if (stat("/proc/sys/kernel/grsecurity", &s) == 0) {
1016 fprintf(stderr, "Error: --overlay option is not available on Grsecurity systems\n");
1017 exit(1);
1018 }
1019 arg_overlay = 1;
1020
1021 return 0;
1022 }
1023 } else if (strcmp(ptr, "overlay") == 0) {
1024 if (checkcfg(CFG_OVERLAYFS)) {
1025 if (arg_overlay) {
1026 fprintf(stderr, "Error: only one overlay command is allowed\n");
1027 exit(1);
1028 }
1029 if (cfg.chrootdir) {
1030 fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n");
1031 exit(1);
1032 }
1033 struct stat s;
1034 if (stat("/proc/sys/kernel/grsecurity", &s) == 0) {
1035 fprintf(stderr, "Error: --overlay option is not available on Grsecurity systems\n");
1036 exit(1);
1037 }
1038 arg_overlay = 1;
1039 arg_overlay_keep = 1;
1040
1041 char *subdirname;
1042 if (asprintf(&subdirname, "%d", getpid()) == -1)
1043 errExit("asprintf");
1044 cfg.overlay_dir = fs_check_overlay_dir(subdirname, arg_overlay_reuse);
1045
1046 free(subdirname);
1047
1048 return 0;
1049 }
1050 }
1051#endif
1052#endif // LTS
1053
1054 // filesystem bind 776 // filesystem bind
1055 if (strncmp(ptr, "bind ", 5) == 0) { 777 if (strncmp(ptr, "bind ", 5) == 0) {
1056 if (checkcfg(CFG_BIND)) { 778 if (checkcfg(CFG_BIND)) {
@@ -1088,47 +810,6 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
1088 return 0; 810 return 0;
1089 } 811 }
1090 812
1091#ifndef LTS
1092 // rlimit
1093 if (strncmp(ptr, "rlimit", 6) == 0) {
1094 if (strncmp(ptr, "rlimit-nofile ", 14) == 0) {
1095 check_unsigned(ptr + 14, "Error: invalid rlimit in profile file: ");
1096 sscanf(ptr + 14, "%llu", &cfg.rlimit_nofile);
1097 arg_rlimit_nofile = 1;
1098 }
1099 else if (strncmp(ptr, "rlimit-cpu ", 11) == 0) {
1100 check_unsigned(ptr + 11, "Error: invalid rlimit in profile file: ");
1101 sscanf(ptr + 11, "%llu", &cfg.rlimit_cpu);
1102 arg_rlimit_cpu = 1;
1103 }
1104 else if (strncmp(ptr, "rlimit-nproc ", 13) == 0) {
1105 check_unsigned(ptr + 13, "Error: invalid rlimit in profile file: ");
1106 sscanf(ptr + 13, "%llu", &cfg.rlimit_nproc);
1107 arg_rlimit_nproc = 1;
1108 }
1109 else if (strncmp(ptr, "rlimit-fsize ", 13) == 0) {
1110 check_unsigned(ptr + 13, "Error: invalid rlimit in profile file: ");
1111 sscanf(ptr + 13, "%llu", &cfg.rlimit_fsize);
1112 arg_rlimit_fsize = 1;
1113 }
1114 else if (strncmp(ptr, "rlimit-sigpending ", 18) == 0) {
1115 check_unsigned(ptr + 18, "Error: invalid rlimit in profile file: ");
1116 sscanf(ptr + 18, "%llu", &cfg.rlimit_sigpending);
1117 arg_rlimit_sigpending = 1;
1118 }
1119 else if (strncmp(ptr, "rlimit-as ", 10) == 0) {
1120 check_unsigned(ptr + 10, "Error: invalid rlimit in profile file: ");
1121 sscanf(ptr + 10, "%llu", &cfg.rlimit_as);
1122 arg_rlimit_as = 1;
1123 }
1124 else {
1125 fprintf(stderr, "Invalid rlimit option on line %d\n", lineno);
1126 exit(1);
1127 }
1128
1129 return 0;
1130 }
1131#endif
1132 813
1133 if (strncmp(ptr, "timeout ", 8) == 0) { 814 if (strncmp(ptr, "timeout ", 8) == 0) {
1134 cfg.timeout = extract_timeout(ptr +8); 815 cfg.timeout = extract_timeout(ptr +8);
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index e0bc0e02f..483681779 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -400,30 +400,6 @@ void start_application(int no_sandbox, FILE *fp) {
400 printf("LD_PRELOAD=%s\n", getenv("LD_PRELOAD")); 400 printf("LD_PRELOAD=%s\n", getenv("LD_PRELOAD"));
401 } 401 }
402 402
403 //****************************************
404 // audit
405 //****************************************
406#ifndef LTS
407 if (arg_audit) {
408 assert(arg_audit_prog);
409
410 if (fp) {
411 fprintf(fp, "ready\n");
412 fclose(fp);
413 }
414#ifdef HAVE_GCOV
415 __gcov_dump();
416#endif
417#ifdef HAVE_SECCOMP
418 seccomp_install_filters();
419#endif
420 execl(arg_audit_prog, arg_audit_prog, NULL);
421 }
422 //****************************************
423 // start the program without using a shell
424 //****************************************
425 else
426#endif // LTS
427 if (arg_shell_none) { 403 if (arg_shell_none) {
428 if (arg_debug) { 404 if (arg_debug) {
429 int i; 405 int i;
@@ -747,20 +723,12 @@ int sandbox(void* sandbox_arg) {
747#endif 723#endif
748 724
749 // need ld.so.preload if tracing or seccomp with any non-default lists 725 // need ld.so.preload if tracing or seccomp with any non-default lists
750#ifndef LTS
751 bool need_preload = arg_trace || arg_tracelog || arg_seccomp_postexec;
752#else
753 bool need_preload = arg_seccomp_postexec; 726 bool need_preload = arg_seccomp_postexec;
754#endif
755 // for --appimage, --chroot and --overlay* we replace the seccomp filter with the default one 727 // for --appimage, --chroot and --overlay* we replace the seccomp filter with the default one
756 // we also drop all capabilities 728 // we also drop all capabilities
757 if (getuid() != 0 && (arg_appimage || cfg.chrootdir || arg_overlay)) { 729 if (getuid() != 0 && (arg_appimage || cfg.chrootdir || arg_overlay)) {
758 enforce_filters(); 730 enforce_filters();
759#ifdef LTS
760 need_preload = 0; 731 need_preload = 0;
761#else
762 need_preload = arg_trace || arg_tracelog;
763#endif
764 arg_seccomp = 1; 732 arg_seccomp = 1;
765 } 733 }
766 // trace pre-install 734 // trace pre-install
@@ -774,26 +742,7 @@ int sandbox(void* sandbox_arg) {
774 //**************************** 742 //****************************
775 // configure filesystem 743 // configure filesystem
776 //**************************** 744 //****************************
777#ifndef LTS 745 fs_basic_fs();
778#ifdef HAVE_CHROOT
779 if (cfg.chrootdir) {
780 fs_chroot(cfg.chrootdir);
781
782 //****************************
783 // trace pre-install, this time inside chroot
784 //****************************
785 if (need_preload)
786 fs_trace_preload();
787 }
788 else
789#endif
790#ifdef HAVE_OVERLAYFS
791 if (arg_overlay)
792 fs_overlayfs();
793 else
794#endif
795#endif // LTS
796 fs_basic_fs();
797 746
798 //**************************** 747 //****************************
799 // private mode 748 // private mode
@@ -807,16 +756,6 @@ int sandbox(void* sandbox_arg) {
807 else 756 else
808 fs_private_homedir(); 757 fs_private_homedir();
809 } 758 }
810#ifndef LTS
811 else if (cfg.home_private_keep) { // --private-home=
812 if (cfg.chrootdir)
813 fwarning("private-home= feature is disabled in chroot\n");
814 else if (arg_overlay)
815 fwarning("private-home= feature is disabled in overlay\n");
816 else
817 fs_private_home_list();
818 }
819#endif //LTS
820 else // --private 759 else // --private
821 fs_private(); 760 fs_private();
822 } 761 }
@@ -824,71 +763,6 @@ int sandbox(void* sandbox_arg) {
824 if (arg_private_dev) 763 if (arg_private_dev)
825 fs_private_dev(); 764 fs_private_dev();
826 765
827#ifndef LTS
828 if (arg_private_etc) {
829 if (cfg.chrootdir)
830 fwarning("private-etc feature is disabled in chroot\n");
831 else if (arg_overlay)
832 fwarning("private-etc feature is disabled in overlay\n");
833 else {
834 fs_private_dir_list("/etc", RUN_ETC_DIR, cfg.etc_private_keep);
835 // create /etc/ld.so.preload file again
836 if (need_preload)
837 fs_trace_preload();
838 }
839 }
840
841 if (arg_private_opt) {
842 if (cfg.chrootdir)
843 fwarning("private-opt feature is disabled in chroot\n");
844 else if (arg_overlay)
845 fwarning("private-opt feature is disabled in overlay\n");
846 else {
847 fs_private_dir_list("/opt", RUN_OPT_DIR, cfg.opt_private_keep);
848 }
849 }
850
851 if (arg_private_srv) {
852 if (cfg.chrootdir)
853 fwarning("private-srv feature is disabled in chroot\n");
854 else if (arg_overlay)
855 fwarning("private-srv feature is disabled in overlay\n");
856 else {
857 fs_private_dir_list("/srv", RUN_SRV_DIR, cfg.srv_private_keep);
858 }
859 }
860
861 // private-bin is disabled for appimages
862 if (arg_private_bin && !arg_appimage) {
863 if (cfg.chrootdir)
864 fwarning("private-bin feature is disabled in chroot\n");
865 else if (arg_overlay)
866 fwarning("private-bin feature is disabled in overlay\n");
867 else {
868 // for --x11=xorg we need to add xauth command
869 if (arg_x11_xorg) {
870 EUID_USER();
871 char *tmp;
872 if (asprintf(&tmp, "%s,xauth", cfg.bin_private_keep) == -1)
873 errExit("asprintf");
874 cfg.bin_private_keep = tmp;
875 EUID_ROOT();
876 }
877 fs_private_bin_list();
878 }
879 }
880
881 // private-lib is disabled for appimages
882 if (arg_private_lib && !arg_appimage) {
883 if (cfg.chrootdir)
884 fwarning("private-lib feature is disabled in chroot\n");
885 else if (arg_overlay)
886 fwarning("private-lib feature is disabled in overlay\n");
887 else {
888 fs_private_lib();
889 }
890 }
891#endif // LTS
892 766
893 if (arg_private_cache) { 767 if (arg_private_cache) {
894 if (cfg.chrootdir) 768 if (cfg.chrootdir)
@@ -1037,22 +911,11 @@ int sandbox(void* sandbox_arg) {
1037 } 911 }
1038 } 912 }
1039 913
1040#ifndef LTS
1041 // clean /tmp/.X11-unix sockets
1042 fs_x11();
1043 if (arg_x11_xorg)
1044 x11_xorg();
1045#endif //LTS
1046
1047 //**************************** 914 //****************************
1048 // set security filters 915 // set security filters
1049 //**************************** 916 //****************************
1050 // set capabilities 917 // set capabilities
1051 set_caps(); 918 set_caps();
1052#ifndef LTS
1053 // set rlimits
1054 set_rlimits();
1055#endif //LTS
1056 // set cpu affinity 919 // set cpu affinity
1057 if (cfg.cpus) { 920 if (cfg.cpus) {
1058 save_cpu(); // save cpu affinity mask to CPU_CFG file 921 save_cpu(); // save cpu affinity mask to CPU_CFG file
@@ -1061,12 +924,6 @@ int sandbox(void* sandbox_arg) {
1061 EUID_ROOT(); 924 EUID_ROOT();
1062 } 925 }
1063 926
1064#ifndef LTS
1065 // save cgroup in CGROUP_CFG file
1066 if (cfg.cgroup)
1067 save_cgroup();
1068#endif
1069
1070 // set seccomp 927 // set seccomp
1071#ifdef HAVE_SECCOMP 928#ifdef HAVE_SECCOMP
1072 // install protocol filter 929 // install protocol filter