diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/firejail/main.c | 189 | ||||
-rw-r--r-- | src/firejail/no_sandbox.c | 3 | ||||
-rw-r--r-- | src/firejail/util.c | 5 |
3 files changed, 96 insertions, 101 deletions
diff --git a/src/firejail/main.c b/src/firejail/main.c index f64994e02..655e6e9d0 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -985,24 +985,16 @@ int main(int argc, char **argv, char **envp) { | |||
985 | int arg_caps_cmdline = 0; // caps requested on command line (used to break out of --chroot) | 985 | int arg_caps_cmdline = 0; // caps requested on command line (used to break out of --chroot) |
986 | char **ptr; | 986 | char **ptr; |
987 | 987 | ||
988 | #ifndef HAVE_SUID | ||
989 | if (geteuid() != 0) { | ||
990 | fprintf(stderr, "Error: Firejail needs to be SUID.\n"); | ||
991 | fprintf(stderr, "Assuming firejail is installed in /usr/bin, execute the following command as root:\n"); | ||
992 | fprintf(stderr, " chmod u+s /usr/bin/firejail\n"); | ||
993 | } | ||
994 | #endif | ||
995 | |||
996 | // sanitize the umask | 988 | // sanitize the umask |
997 | orig_umask = umask(022); | 989 | orig_umask = umask(022); |
998 | 990 | ||
999 | // check standard streams before printing anything | ||
1000 | fix_std_streams(); | ||
1001 | |||
1002 | // drop permissions by default and rise them when required | 991 | // drop permissions by default and rise them when required |
1003 | EUID_INIT(); | 992 | EUID_INIT(); |
1004 | EUID_USER(); | 993 | EUID_USER(); |
1005 | 994 | ||
995 | // check standard streams before opening any file | ||
996 | fix_std_streams(); | ||
997 | |||
1006 | // argument count should be larger than 0 | 998 | // argument count should be larger than 0 |
1007 | if (argc == 0 || !argv || strlen(argv[0]) == 0) { | 999 | if (argc == 0 || !argv || strlen(argv[0]) == 0) { |
1008 | fprintf(stderr, "Error: argv is invalid\n"); | 1000 | fprintf(stderr, "Error: argv is invalid\n"); |
@@ -1012,16 +1004,6 @@ int main(int argc, char **argv, char **envp) { | |||
1012 | exit(1); | 1004 | exit(1); |
1013 | } | 1005 | } |
1014 | 1006 | ||
1015 | // Stash environment variables | ||
1016 | for (i = 0, ptr = envp; ptr && *ptr && i < MAX_ENVS; i++, ptr++) | ||
1017 | env_store(*ptr, SETENV); | ||
1018 | |||
1019 | // sanity check for environment variables | ||
1020 | if (i >= MAX_ENVS) { | ||
1021 | fprintf(stderr, "Error: too many environment variables\n"); | ||
1022 | exit(1); | ||
1023 | } | ||
1024 | |||
1025 | // sanity check for arguments | 1007 | // sanity check for arguments |
1026 | for (i = 0; i < argc; i++) { | 1008 | for (i = 0; i < argc; i++) { |
1027 | if (*argv[i] == 0) { | 1009 | if (*argv[i] == 0) { |
@@ -1034,82 +1016,29 @@ int main(int argc, char **argv, char **envp) { | |||
1034 | } | 1016 | } |
1035 | } | 1017 | } |
1036 | 1018 | ||
1019 | // Stash environment variables | ||
1020 | for (i = 0, ptr = envp; ptr && *ptr && i < MAX_ENVS; i++, ptr++) | ||
1021 | env_store(*ptr, SETENV); | ||
1022 | |||
1023 | // sanity check for environment variables | ||
1024 | if (i >= MAX_ENVS) { | ||
1025 | fprintf(stderr, "Error: too many environment variables\n"); | ||
1026 | exit(1); | ||
1027 | } | ||
1028 | |||
1037 | // Reapply a minimal set of environment variables | 1029 | // Reapply a minimal set of environment variables |
1038 | env_apply_whitelist(); | 1030 | env_apply_whitelist(); |
1039 | 1031 | ||
1040 | // check if the user is allowed to use firejail | 1032 | // process --quiet |
1041 | init_cfg(argc, argv); | ||
1042 | |||
1043 | // get starting timestamp, process --quiet | ||
1044 | timetrace_start(); | ||
1045 | const char *env_quiet = env_get("FIREJAIL_QUIET"); | 1033 | const char *env_quiet = env_get("FIREJAIL_QUIET"); |
1046 | if (check_arg(argc, argv, "--quiet", 1) || (env_quiet && strcmp(env_quiet, "yes") == 0)) | 1034 | if (check_arg(argc, argv, "--quiet", 1) || (env_quiet && strcmp(env_quiet, "yes") == 0)) |
1047 | arg_quiet = 1; | 1035 | arg_quiet = 1; |
1048 | 1036 | ||
1049 | // cleanup at exit | 1037 | // check if the user is allowed to use firejail |
1050 | EUID_ROOT(); | 1038 | init_cfg(argc, argv); |
1051 | atexit(clear_atexit); | ||
1052 | |||
1053 | // build /run/firejail directory structure | ||
1054 | preproc_build_firejail_dir(); | ||
1055 | const char *container_name = env_get("container"); | ||
1056 | if (!container_name || strcmp(container_name, "firejail")) { | ||
1057 | lockfd_directory = open(RUN_DIRECTORY_LOCK_FILE, O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR); | ||
1058 | if (lockfd_directory != -1) { | ||
1059 | int rv = fchown(lockfd_directory, 0, 0); | ||
1060 | (void) rv; | ||
1061 | flock(lockfd_directory, LOCK_EX); | ||
1062 | } | ||
1063 | preproc_clean_run(); | ||
1064 | flock(lockfd_directory, LOCK_UN); | ||
1065 | close(lockfd_directory); | ||
1066 | } | ||
1067 | EUID_USER(); | ||
1068 | |||
1069 | // --ip=dhcp - we need access to /sbin and /usr/sbin directories in order to run ISC DHCP client (dhclient) | ||
1070 | // these paths are disabled in disable-common.inc | ||
1071 | if ((i = check_arg(argc, argv, "--ip", 0)) != 0) { | ||
1072 | if (strncmp(argv[i] + 4, "=dhcp", 5) == 0) { | ||
1073 | profile_add("noblacklist /sbin"); | ||
1074 | profile_add("noblacklist /usr/sbin"); | ||
1075 | } | ||
1076 | } | ||
1077 | |||
1078 | // for appimages we need to remove "include disable-shell.inc from the profile | ||
1079 | // a --profile command can show up before --appimage | ||
1080 | if (check_arg(argc, argv, "--appimage", 1)) | ||
1081 | arg_appimage = 1; | ||
1082 | |||
1083 | // process allow-debuggers | ||
1084 | if (check_arg(argc, argv, "--allow-debuggers", 1)) { | ||
1085 | // check kernel version | ||
1086 | struct utsname u; | ||
1087 | int rv = uname(&u); | ||
1088 | if (rv != 0) | ||
1089 | errExit("uname"); | ||
1090 | int major; | ||
1091 | int minor; | ||
1092 | if (2 != sscanf(u.release, "%d.%d", &major, &minor)) { | ||
1093 | fprintf(stderr, "Error: cannot extract Linux kernel version: %s\n", u.version); | ||
1094 | exit(1); | ||
1095 | } | ||
1096 | if (major < 4 || (major == 4 && minor < 8)) { | ||
1097 | fprintf(stderr, "Error: --allow-debuggers is disabled on Linux kernels prior to 4.8. " | ||
1098 | "A bug in ptrace call allows a full bypass of the seccomp filter. " | ||
1099 | "Your current kernel version is %d.%d.\n", major, minor); | ||
1100 | exit(1); | ||
1101 | } | ||
1102 | |||
1103 | arg_allow_debuggers = 1; | ||
1104 | char *cmd = strdup("noblacklist ${PATH}/strace"); | ||
1105 | if (!cmd) | ||
1106 | errExit("strdup"); | ||
1107 | profile_add(cmd); | ||
1108 | } | ||
1109 | 1039 | ||
1110 | // profile builder | 1040 | // get starting timestamp |
1111 | if (check_arg(argc, argv, "--build", 0)) // supports both --build and --build=filename | 1041 | timetrace_start(); |
1112 | run_builder(argc, argv); // this function will not return | ||
1113 | 1042 | ||
1114 | // check argv[0] symlink wrapper if this is not a login shell | 1043 | // check argv[0] symlink wrapper if this is not a login shell |
1115 | if (*argv[0] != '-') | 1044 | if (*argv[0] != '-') |
@@ -1134,15 +1063,40 @@ int main(int argc, char **argv, char **envp) { | |||
1134 | __builtin_unreachable(); | 1063 | __builtin_unreachable(); |
1135 | } | 1064 | } |
1136 | } | 1065 | } |
1137 | EUID_ASSERT(); | ||
1138 | 1066 | ||
1067 | // profile builder | ||
1068 | if (check_arg(argc, argv, "--build", 0)) // supports both --build and --build=filename | ||
1069 | run_builder(argc, argv); // this function will not return | ||
1139 | 1070 | ||
1140 | // check firejail directories | ||
1141 | EUID_ROOT(); | 1071 | EUID_ROOT(); |
1142 | delete_run_files(sandbox_pid); | 1072 | #ifndef HAVE_SUID |
1073 | if (geteuid() != 0) { | ||
1074 | fprintf(stderr, "Error: Firejail needs to be SUID.\n"); | ||
1075 | fprintf(stderr, "Assuming firejail is installed in /usr/bin, execute the following command as root:\n"); | ||
1076 | fprintf(stderr, " chmod u+s /usr/bin/firejail\n"); | ||
1077 | } | ||
1078 | #endif | ||
1079 | |||
1080 | // build /run/firejail directory structure | ||
1081 | preproc_build_firejail_dir(); | ||
1082 | const char *container_name = env_get("container"); | ||
1083 | if (!container_name || strcmp(container_name, "firejail")) { | ||
1084 | lockfd_directory = open(RUN_DIRECTORY_LOCK_FILE, O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR); | ||
1085 | if (lockfd_directory != -1) { | ||
1086 | int rv = fchown(lockfd_directory, 0, 0); | ||
1087 | (void) rv; | ||
1088 | flock(lockfd_directory, LOCK_EX); | ||
1089 | } | ||
1090 | preproc_clean_run(); | ||
1091 | flock(lockfd_directory, LOCK_UN); | ||
1092 | close(lockfd_directory); | ||
1093 | } | ||
1094 | |||
1095 | delete_run_files(getpid()); | ||
1096 | atexit(clear_atexit); | ||
1143 | EUID_USER(); | 1097 | EUID_USER(); |
1144 | 1098 | ||
1145 | //check if the parent is sshd daemon | 1099 | // check if the parent is sshd daemon |
1146 | int parent_sshd = 0; | 1100 | int parent_sshd = 0; |
1147 | { | 1101 | { |
1148 | pid_t ppid = getppid(); | 1102 | pid_t ppid = getppid(); |
@@ -1199,7 +1153,8 @@ int main(int argc, char **argv, char **envp) { | |||
1199 | } | 1153 | } |
1200 | EUID_ASSERT(); | 1154 | EUID_ASSERT(); |
1201 | 1155 | ||
1202 | // is this a login shell, or a command passed by sshd, insert command line options from /etc/firejail/login.users | 1156 | // is this a login shell, or a command passed by sshd, |
1157 | // insert command line options from /etc/firejail/login.users | ||
1203 | if (*argv[0] == '-' || parent_sshd) { | 1158 | if (*argv[0] == '-' || parent_sshd) { |
1204 | if (argc == 1) | 1159 | if (argc == 1) |
1205 | login_shell = 1; | 1160 | login_shell = 1; |
@@ -1251,6 +1206,47 @@ int main(int argc, char **argv, char **envp) { | |||
1251 | #endif | 1206 | #endif |
1252 | EUID_ASSERT(); | 1207 | EUID_ASSERT(); |
1253 | 1208 | ||
1209 | // --ip=dhcp - we need access to /sbin and /usr/sbin directories in order to run ISC DHCP client (dhclient) | ||
1210 | // these paths are disabled in disable-common.inc | ||
1211 | if ((i = check_arg(argc, argv, "--ip", 0)) != 0) { | ||
1212 | if (strncmp(argv[i] + 4, "=dhcp", 5) == 0) { | ||
1213 | profile_add("noblacklist /sbin"); | ||
1214 | profile_add("noblacklist /usr/sbin"); | ||
1215 | } | ||
1216 | } | ||
1217 | |||
1218 | // process allow-debuggers | ||
1219 | if (check_arg(argc, argv, "--allow-debuggers", 1)) { | ||
1220 | // check kernel version | ||
1221 | struct utsname u; | ||
1222 | int rv = uname(&u); | ||
1223 | if (rv != 0) | ||
1224 | errExit("uname"); | ||
1225 | int major; | ||
1226 | int minor; | ||
1227 | if (2 != sscanf(u.release, "%d.%d", &major, &minor)) { | ||
1228 | fprintf(stderr, "Error: cannot extract Linux kernel version: %s\n", u.version); | ||
1229 | exit(1); | ||
1230 | } | ||
1231 | if (major < 4 || (major == 4 && minor < 8)) { | ||
1232 | fprintf(stderr, "Error: --allow-debuggers is disabled on Linux kernels prior to 4.8. " | ||
1233 | "A bug in ptrace call allows a full bypass of the seccomp filter. " | ||
1234 | "Your current kernel version is %d.%d.\n", major, minor); | ||
1235 | exit(1); | ||
1236 | } | ||
1237 | |||
1238 | arg_allow_debuggers = 1; | ||
1239 | char *cmd = strdup("noblacklist ${PATH}/strace"); | ||
1240 | if (!cmd) | ||
1241 | errExit("strdup"); | ||
1242 | profile_add(cmd); | ||
1243 | } | ||
1244 | |||
1245 | // for appimages we need to remove "include disable-shell.inc from the profile | ||
1246 | // a --profile command can show up before --appimage | ||
1247 | if (check_arg(argc, argv, "--appimage", 1)) | ||
1248 | arg_appimage = 1; | ||
1249 | |||
1254 | // check for force-nonewprivs in /etc/firejail/firejail.config file | 1250 | // check for force-nonewprivs in /etc/firejail/firejail.config file |
1255 | if (checkcfg(CFG_FORCE_NONEWPRIVS)) | 1251 | if (checkcfg(CFG_FORCE_NONEWPRIVS)) |
1256 | arg_nonewprivs = 1; | 1252 | arg_nonewprivs = 1; |
@@ -2680,8 +2676,9 @@ int main(int argc, char **argv, char **envp) { | |||
2680 | //************************************* | 2676 | //************************************* |
2681 | else if (strncmp(argv[i], "--timeout=", 10) == 0) | 2677 | else if (strncmp(argv[i], "--timeout=", 10) == 0) |
2682 | cfg.timeout = extract_timeout(argv[i] + 10); | 2678 | cfg.timeout = extract_timeout(argv[i] + 10); |
2683 | else if (strcmp(argv[i], "--appimage") == 0) | 2679 | else if (strcmp(argv[i], "--appimage") == 0) { |
2684 | arg_appimage = 1; | 2680 | // already handled |
2681 | } | ||
2685 | else if (strcmp(argv[i], "--shell=none") == 0) { | 2682 | else if (strcmp(argv[i], "--shell=none") == 0) { |
2686 | arg_shell_none = 1; | 2683 | arg_shell_none = 1; |
2687 | if (cfg.shell) { | 2684 | if (cfg.shell) { |
diff --git a/src/firejail/no_sandbox.c b/src/firejail/no_sandbox.c index 665bef73d..0e5562d90 100644 --- a/src/firejail/no_sandbox.c +++ b/src/firejail/no_sandbox.c | |||
@@ -49,6 +49,7 @@ int check_namespace_virt(void) { | |||
49 | // check PID 1 container environment variable | 49 | // check PID 1 container environment variable |
50 | EUID_ROOT(); | 50 | EUID_ROOT(); |
51 | FILE *fp = fopen("/proc/1/environ", "re"); | 51 | FILE *fp = fopen("/proc/1/environ", "re"); |
52 | EUID_USER(); | ||
52 | if (fp) { | 53 | if (fp) { |
53 | int c = 0; | 54 | int c = 0; |
54 | while (c != EOF) { | 55 | while (c != EOF) { |
@@ -69,7 +70,6 @@ int check_namespace_virt(void) { | |||
69 | // found it | 70 | // found it |
70 | if (is_container(buf + 10)) { | 71 | if (is_container(buf + 10)) { |
71 | fclose(fp); | 72 | fclose(fp); |
72 | EUID_USER(); | ||
73 | return 1; | 73 | return 1; |
74 | } | 74 | } |
75 | } | 75 | } |
@@ -79,7 +79,6 @@ int check_namespace_virt(void) { | |||
79 | fclose(fp); | 79 | fclose(fp); |
80 | } | 80 | } |
81 | 81 | ||
82 | EUID_USER(); | ||
83 | return 0; | 82 | return 0; |
84 | } | 83 | } |
85 | 84 | ||
diff --git a/src/firejail/util.c b/src/firejail/util.c index de31ebdd6..094a68c60 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -1513,8 +1513,7 @@ void check_homedir(const char *dir) { | |||
1513 | exit(1); | 1513 | exit(1); |
1514 | } | 1514 | } |
1515 | // symlinks are rejected in many places | 1515 | // symlinks are rejected in many places |
1516 | if (has_link(dir)) { | 1516 | if (has_link(dir)) |
1517 | fprintf(stderr, "No full support for symbolic links in path of user directory.\n" | 1517 | fmessage("No full support for symbolic links in path of user directory.\n" |
1518 | "Please provide resolved path in password database (/etc/passwd).\n\n"); | 1518 | "Please provide resolved path in password database (/etc/passwd).\n\n"); |
1519 | } | ||
1520 | } | 1519 | } |