diff options
author | smitsohu <smitsohu@gmail.com> | 2021-07-24 13:42:06 +0200 |
---|---|---|
committer | smitsohu <smitsohu@gmail.com> | 2021-07-24 15:27:22 +0200 |
commit | ee31d6b817e3777e625f23f460aa1daeda3637f7 (patch) | |
tree | 227eee9196775c5452cf6f572792fb274b0cd8f1 /src | |
parent | tweaks (diff) | |
download | firejail-ee31d6b817e3777e625f23f460aa1daeda3637f7.tar.gz firejail-ee31d6b817e3777e625f23f460aa1daeda3637f7.tar.zst firejail-ee31d6b817e3777e625f23f460aa1daeda3637f7.zip |
organize program startup
fixes a number of smaller issues:
* enable allow-debuggers option for Firejail login shells
* dhcp: noblacklist /sbin and /usr/sbin also when configuring a Firejail login shell
* don't print error when built with disable-suid: firejail --nonewprivs --quiet firejail
* don't process appimage option twice
* no unnecessary argument parsing when run via firecfg symbolic link
* process quiet option earlier, so it is available to init_cfg
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 374afed11..a59d508e5 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -988,24 +988,16 @@ int main(int argc, char **argv, char **envp) { | |||
988 | int arg_caps_cmdline = 0; // caps requested on command line (used to break out of --chroot) | 988 | int arg_caps_cmdline = 0; // caps requested on command line (used to break out of --chroot) |
989 | char **ptr; | 989 | char **ptr; |
990 | 990 | ||
991 | #ifndef HAVE_SUID | ||
992 | if (geteuid() != 0) { | ||
993 | fprintf(stderr, "Error: Firejail needs to be SUID.\n"); | ||
994 | fprintf(stderr, "Assuming firejail is installed in /usr/bin, execute the following command as root:\n"); | ||
995 | fprintf(stderr, " chmod u+s /usr/bin/firejail\n"); | ||
996 | } | ||
997 | #endif | ||
998 | |||
999 | // sanitize the umask | 991 | // sanitize the umask |
1000 | orig_umask = umask(022); | 992 | orig_umask = umask(022); |
1001 | 993 | ||
1002 | // check standard streams before printing anything | ||
1003 | fix_std_streams(); | ||
1004 | |||
1005 | // drop permissions by default and rise them when required | 994 | // drop permissions by default and rise them when required |
1006 | EUID_INIT(); | 995 | EUID_INIT(); |
1007 | EUID_USER(); | 996 | EUID_USER(); |
1008 | 997 | ||
998 | // check standard streams before opening any file | ||
999 | fix_std_streams(); | ||
1000 | |||
1009 | // argument count should be larger than 0 | 1001 | // argument count should be larger than 0 |
1010 | if (argc == 0 || !argv || strlen(argv[0]) == 0) { | 1002 | if (argc == 0 || !argv || strlen(argv[0]) == 0) { |
1011 | fprintf(stderr, "Error: argv is invalid\n"); | 1003 | fprintf(stderr, "Error: argv is invalid\n"); |
@@ -1015,16 +1007,6 @@ int main(int argc, char **argv, char **envp) { | |||
1015 | exit(1); | 1007 | exit(1); |
1016 | } | 1008 | } |
1017 | 1009 | ||
1018 | // Stash environment variables | ||
1019 | for (i = 0, ptr = envp; ptr && *ptr && i < MAX_ENVS; i++, ptr++) | ||
1020 | env_store(*ptr, SETENV); | ||
1021 | |||
1022 | // sanity check for environment variables | ||
1023 | if (i >= MAX_ENVS) { | ||
1024 | fprintf(stderr, "Error: too many environment variables\n"); | ||
1025 | exit(1); | ||
1026 | } | ||
1027 | |||
1028 | // sanity check for arguments | 1010 | // sanity check for arguments |
1029 | for (i = 0; i < argc; i++) { | 1011 | for (i = 0; i < argc; i++) { |
1030 | if (*argv[i] == 0) { | 1012 | if (*argv[i] == 0) { |
@@ -1037,82 +1019,29 @@ int main(int argc, char **argv, char **envp) { | |||
1037 | } | 1019 | } |
1038 | } | 1020 | } |
1039 | 1021 | ||
1022 | // Stash environment variables | ||
1023 | for (i = 0, ptr = envp; ptr && *ptr && i < MAX_ENVS; i++, ptr++) | ||
1024 | env_store(*ptr, SETENV); | ||
1025 | |||
1026 | // sanity check for environment variables | ||
1027 | if (i >= MAX_ENVS) { | ||
1028 | fprintf(stderr, "Error: too many environment variables\n"); | ||
1029 | exit(1); | ||
1030 | } | ||
1031 | |||
1040 | // Reapply a minimal set of environment variables | 1032 | // Reapply a minimal set of environment variables |
1041 | env_apply_whitelist(); | 1033 | env_apply_whitelist(); |
1042 | 1034 | ||
1043 | // check if the user is allowed to use firejail | 1035 | // process --quiet |
1044 | init_cfg(argc, argv); | ||
1045 | |||
1046 | // get starting timestamp, process --quiet | ||
1047 | timetrace_start(); | ||
1048 | const char *env_quiet = env_get("FIREJAIL_QUIET"); | 1036 | const char *env_quiet = env_get("FIREJAIL_QUIET"); |
1049 | if (check_arg(argc, argv, "--quiet", 1) || (env_quiet && strcmp(env_quiet, "yes") == 0)) | 1037 | if (check_arg(argc, argv, "--quiet", 1) || (env_quiet && strcmp(env_quiet, "yes") == 0)) |
1050 | arg_quiet = 1; | 1038 | arg_quiet = 1; |
1051 | 1039 | ||
1052 | // cleanup at exit | 1040 | // check if the user is allowed to use firejail |
1053 | EUID_ROOT(); | 1041 | init_cfg(argc, argv); |
1054 | atexit(clear_atexit); | ||
1055 | |||
1056 | // build /run/firejail directory structure | ||
1057 | preproc_build_firejail_dir(); | ||
1058 | const char *container_name = env_get("container"); | ||
1059 | if (!container_name || strcmp(container_name, "firejail")) { | ||
1060 | lockfd_directory = open(RUN_DIRECTORY_LOCK_FILE, O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR); | ||
1061 | if (lockfd_directory != -1) { | ||
1062 | int rv = fchown(lockfd_directory, 0, 0); | ||
1063 | (void) rv; | ||
1064 | flock(lockfd_directory, LOCK_EX); | ||
1065 | } | ||
1066 | preproc_clean_run(); | ||
1067 | flock(lockfd_directory, LOCK_UN); | ||
1068 | close(lockfd_directory); | ||
1069 | } | ||
1070 | EUID_USER(); | ||
1071 | |||
1072 | // --ip=dhcp - we need access to /sbin and /usr/sbin directories in order to run ISC DHCP client (dhclient) | ||
1073 | // these paths are disabled in disable-common.inc | ||
1074 | if ((i = check_arg(argc, argv, "--ip", 0)) != 0) { | ||
1075 | if (strncmp(argv[i] + 4, "=dhcp", 5) == 0) { | ||
1076 | profile_add("noblacklist /sbin"); | ||
1077 | profile_add("noblacklist /usr/sbin"); | ||
1078 | } | ||
1079 | } | ||
1080 | |||
1081 | // for appimages we need to remove "include disable-shell.inc from the profile | ||
1082 | // a --profile command can show up before --appimage | ||
1083 | if (check_arg(argc, argv, "--appimage", 1)) | ||
1084 | arg_appimage = 1; | ||
1085 | |||
1086 | // process allow-debuggers | ||
1087 | if (check_arg(argc, argv, "--allow-debuggers", 1)) { | ||
1088 | // check kernel version | ||
1089 | struct utsname u; | ||
1090 | int rv = uname(&u); | ||
1091 | if (rv != 0) | ||
1092 | errExit("uname"); | ||
1093 | int major; | ||
1094 | int minor; | ||
1095 | if (2 != sscanf(u.release, "%d.%d", &major, &minor)) { | ||
1096 | fprintf(stderr, "Error: cannot extract Linux kernel version: %s\n", u.version); | ||
1097 | exit(1); | ||
1098 | } | ||
1099 | if (major < 4 || (major == 4 && minor < 8)) { | ||
1100 | fprintf(stderr, "Error: --allow-debuggers is disabled on Linux kernels prior to 4.8. " | ||
1101 | "A bug in ptrace call allows a full bypass of the seccomp filter. " | ||
1102 | "Your current kernel version is %d.%d.\n", major, minor); | ||
1103 | exit(1); | ||
1104 | } | ||
1105 | |||
1106 | arg_allow_debuggers = 1; | ||
1107 | char *cmd = strdup("noblacklist ${PATH}/strace"); | ||
1108 | if (!cmd) | ||
1109 | errExit("strdup"); | ||
1110 | profile_add(cmd); | ||
1111 | } | ||
1112 | 1042 | ||
1113 | // profile builder | 1043 | // get starting timestamp |
1114 | if (check_arg(argc, argv, "--build", 0)) // supports both --build and --build=filename | 1044 | timetrace_start(); |
1115 | run_builder(argc, argv); // this function will not return | ||
1116 | 1045 | ||
1117 | // check argv[0] symlink wrapper if this is not a login shell | 1046 | // check argv[0] symlink wrapper if this is not a login shell |
1118 | if (*argv[0] != '-') | 1047 | if (*argv[0] != '-') |
@@ -1137,15 +1066,40 @@ int main(int argc, char **argv, char **envp) { | |||
1137 | __builtin_unreachable(); | 1066 | __builtin_unreachable(); |
1138 | } | 1067 | } |
1139 | } | 1068 | } |
1140 | EUID_ASSERT(); | ||
1141 | 1069 | ||
1070 | // profile builder | ||
1071 | if (check_arg(argc, argv, "--build", 0)) // supports both --build and --build=filename | ||
1072 | run_builder(argc, argv); // this function will not return | ||
1142 | 1073 | ||
1143 | // check firejail directories | ||
1144 | EUID_ROOT(); | 1074 | EUID_ROOT(); |
1145 | delete_run_files(sandbox_pid); | 1075 | #ifndef HAVE_SUID |
1076 | if (geteuid() != 0) { | ||
1077 | fprintf(stderr, "Error: Firejail needs to be SUID.\n"); | ||
1078 | fprintf(stderr, "Assuming firejail is installed in /usr/bin, execute the following command as root:\n"); | ||
1079 | fprintf(stderr, " chmod u+s /usr/bin/firejail\n"); | ||
1080 | } | ||
1081 | #endif | ||
1082 | |||
1083 | // build /run/firejail directory structure | ||
1084 | preproc_build_firejail_dir(); | ||
1085 | const char *container_name = env_get("container"); | ||
1086 | if (!container_name || strcmp(container_name, "firejail")) { | ||
1087 | lockfd_directory = open(RUN_DIRECTORY_LOCK_FILE, O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR); | ||
1088 | if (lockfd_directory != -1) { | ||
1089 | int rv = fchown(lockfd_directory, 0, 0); | ||
1090 | (void) rv; | ||
1091 | flock(lockfd_directory, LOCK_EX); | ||
1092 | } | ||
1093 | preproc_clean_run(); | ||
1094 | flock(lockfd_directory, LOCK_UN); | ||
1095 | close(lockfd_directory); | ||
1096 | } | ||
1097 | |||
1098 | delete_run_files(getpid()); | ||
1099 | atexit(clear_atexit); | ||
1146 | EUID_USER(); | 1100 | EUID_USER(); |
1147 | 1101 | ||
1148 | //check if the parent is sshd daemon | 1102 | // check if the parent is sshd daemon |
1149 | int parent_sshd = 0; | 1103 | int parent_sshd = 0; |
1150 | { | 1104 | { |
1151 | pid_t ppid = getppid(); | 1105 | pid_t ppid = getppid(); |
@@ -1202,7 +1156,8 @@ int main(int argc, char **argv, char **envp) { | |||
1202 | } | 1156 | } |
1203 | EUID_ASSERT(); | 1157 | EUID_ASSERT(); |
1204 | 1158 | ||
1205 | // is this a login shell, or a command passed by sshd, insert command line options from /etc/firejail/login.users | 1159 | // is this a login shell, or a command passed by sshd, |
1160 | // insert command line options from /etc/firejail/login.users | ||
1206 | if (*argv[0] == '-' || parent_sshd) { | 1161 | if (*argv[0] == '-' || parent_sshd) { |
1207 | if (argc == 1) | 1162 | if (argc == 1) |
1208 | login_shell = 1; | 1163 | login_shell = 1; |
@@ -1254,6 +1209,47 @@ int main(int argc, char **argv, char **envp) { | |||
1254 | #endif | 1209 | #endif |
1255 | EUID_ASSERT(); | 1210 | EUID_ASSERT(); |
1256 | 1211 | ||
1212 | // --ip=dhcp - we need access to /sbin and /usr/sbin directories in order to run ISC DHCP client (dhclient) | ||
1213 | // these paths are disabled in disable-common.inc | ||
1214 | if ((i = check_arg(argc, argv, "--ip", 0)) != 0) { | ||
1215 | if (strncmp(argv[i] + 4, "=dhcp", 5) == 0) { | ||
1216 | profile_add("noblacklist /sbin"); | ||
1217 | profile_add("noblacklist /usr/sbin"); | ||
1218 | } | ||
1219 | } | ||
1220 | |||
1221 | // process allow-debuggers | ||
1222 | if (check_arg(argc, argv, "--allow-debuggers", 1)) { | ||
1223 | // check kernel version | ||
1224 | struct utsname u; | ||
1225 | int rv = uname(&u); | ||
1226 | if (rv != 0) | ||
1227 | errExit("uname"); | ||
1228 | int major; | ||
1229 | int minor; | ||
1230 | if (2 != sscanf(u.release, "%d.%d", &major, &minor)) { | ||
1231 | fprintf(stderr, "Error: cannot extract Linux kernel version: %s\n", u.version); | ||
1232 | exit(1); | ||
1233 | } | ||
1234 | if (major < 4 || (major == 4 && minor < 8)) { | ||
1235 | fprintf(stderr, "Error: --allow-debuggers is disabled on Linux kernels prior to 4.8. " | ||
1236 | "A bug in ptrace call allows a full bypass of the seccomp filter. " | ||
1237 | "Your current kernel version is %d.%d.\n", major, minor); | ||
1238 | exit(1); | ||
1239 | } | ||
1240 | |||
1241 | arg_allow_debuggers = 1; | ||
1242 | char *cmd = strdup("noblacklist ${PATH}/strace"); | ||
1243 | if (!cmd) | ||
1244 | errExit("strdup"); | ||
1245 | profile_add(cmd); | ||
1246 | } | ||
1247 | |||
1248 | // for appimages we need to remove "include disable-shell.inc from the profile | ||
1249 | // a --profile command can show up before --appimage | ||
1250 | if (check_arg(argc, argv, "--appimage", 1)) | ||
1251 | arg_appimage = 1; | ||
1252 | |||
1257 | // check for force-nonewprivs in /etc/firejail/firejail.config file | 1253 | // check for force-nonewprivs in /etc/firejail/firejail.config file |
1258 | if (checkcfg(CFG_FORCE_NONEWPRIVS)) | 1254 | if (checkcfg(CFG_FORCE_NONEWPRIVS)) |
1259 | arg_nonewprivs = 1; | 1255 | arg_nonewprivs = 1; |
@@ -2652,8 +2648,9 @@ int main(int argc, char **argv, char **envp) { | |||
2652 | //************************************* | 2648 | //************************************* |
2653 | else if (strncmp(argv[i], "--timeout=", 10) == 0) | 2649 | else if (strncmp(argv[i], "--timeout=", 10) == 0) |
2654 | cfg.timeout = extract_timeout(argv[i] + 10); | 2650 | cfg.timeout = extract_timeout(argv[i] + 10); |
2655 | else if (strcmp(argv[i], "--appimage") == 0) | 2651 | else if (strcmp(argv[i], "--appimage") == 0) { |
2656 | arg_appimage = 1; | 2652 | // already handled |
2653 | } | ||
2657 | else if (strcmp(argv[i], "--shell=none") == 0) { | 2654 | else if (strcmp(argv[i], "--shell=none") == 0) { |
2658 | arg_shell_none = 1; | 2655 | arg_shell_none = 1; |
2659 | if (cfg.shell) { | 2656 | 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 8fcaf3f7b..2ff2d2973 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -1516,8 +1516,7 @@ void check_homedir(const char *dir) { | |||
1516 | exit(1); | 1516 | exit(1); |
1517 | } | 1517 | } |
1518 | // symlinks are rejected in many places | 1518 | // symlinks are rejected in many places |
1519 | if (has_link(dir)) { | 1519 | if (has_link(dir)) |
1520 | fprintf(stderr, "No full support for symbolic links in path of user directory.\n" | 1520 | fmessage("No full support for symbolic links in path of user directory.\n" |
1521 | "Please provide resolved path in password database (/etc/passwd).\n\n"); | 1521 | "Please provide resolved path in password database (/etc/passwd).\n\n"); |
1522 | } | ||
1523 | } | 1522 | } |