Merge tag 'upstream/0.9.44.6'
Upstream version 0.9.44.6
# gpg: Signature made Mon 16 Jan 2017 07:24:43 PM CET
# gpg: using RSA key D8F6FA7DEA24D90D6EAC733BCCF04928DB0EEAA7
# gpg: issuer "reiner@reiner-h.de"
# gpg: Good signature from "Reiner Herrmann <reiner@reiner-h.de>" [ultimate]
# Primary key fingerprint: 2F5D AF3F C1F7 93D9 4F3D 900C A721 DA05 5374 AA4F
# Subkey fingerprint: D8F6 FA7D EA24 D90D 6EAC 733B CCF0 4928 DB0E EAA7
Reiner Herrmann
7 years ago
76 | 76 | - added gnome-chess profile |
77 | 77 | - added DOSBox profile |
78 | 78 | - evince profile enhancement |
79 | Mike Frysinger (vapier@gentoo.org) | |
80 | - Gentoo compile patch | |
79 | 81 | valoq (https://github.com/valoq) |
80 | 82 | - LibreOffice profile fixes |
81 | 83 | - cherrytree profile fixes |
0 | firejail (0.9.44.6) baseline; urgency=low | |
1 | * security: new fix for CVE-2017-5180 reported by Sebastian Krahmer last week | |
2 | * security: major cleanup of file copying code | |
3 | * security: tightening the rules for --chroot and --overlay features | |
4 | * bugfix: ported Gentoo compile patch | |
5 | * bugfix: Nvidia drivers bug in --private-dev | |
6 | * bugfix: fix ASSERT_PERMS_FD macro | |
7 | * feature: allow local customization using .local files under /etc/firejail | |
8 | backported from our development branch | |
9 | * feature: spoof machine-id backported from our development branch | |
10 | -- netblue30 <netblue30@yahoo.com> Sun, 15 Jan 2017 10:00:00 -0500 | |
11 | ||
0 | 12 | firejail (0.9.44.4) baseline; urgency=low |
1 | * security: --bandwidth root shell found by Martin Carpenter | |
13 | * security: --bandwidth root shell found by Martin Carpenter (CVE-2017-5207) | |
2 | 14 | * security: disabled --allow-debuggers when running on kernel |
3 | 15 | versions prior to 4.8; a kernel bug in ptrace system call |
4 | 16 | allows a full bypass of seccomp filter; problem reported by Lizzie Dixon |
17 | (CVE-2017-5206) | |
5 | 18 | * security: root exploit found by Sebastian Krahmer (CVE-2017-5180) |
6 | 19 | -- netblue30 <netblue30@yahoo.com> Sat, 7 Jan 2017 10:00:00 -0500 |
7 | 20 |
0 | 0 | #! /bin/sh |
1 | 1 | # Guess values for system-dependent variables and create Makefiles. |
2 | # Generated by GNU Autoconf 2.69 for firejail 0.9.44.4. | |
2 | # Generated by GNU Autoconf 2.69 for firejail 0.9.44.6. | |
3 | 3 | # |
4 | 4 | # Report bugs to <netblue30@yahoo.com>. |
5 | 5 | # |
579 | 579 | # Identity of this package. |
580 | 580 | PACKAGE_NAME='firejail' |
581 | 581 | PACKAGE_TARNAME='firejail' |
582 | PACKAGE_VERSION='0.9.44.4' | |
583 | PACKAGE_STRING='firejail 0.9.44.4' | |
582 | PACKAGE_VERSION='0.9.44.6' | |
583 | PACKAGE_STRING='firejail 0.9.44.6' | |
584 | 584 | PACKAGE_BUGREPORT='netblue30@yahoo.com' |
585 | 585 | PACKAGE_URL='http://firejail.wordpress.com' |
586 | 586 | |
1258 | 1258 | # Omit some internal or obsolete options to make the list less imposing. |
1259 | 1259 | # This message is too long to be a string in the A/UX 3.1 sh. |
1260 | 1260 | cat <<_ACEOF |
1261 | \`configure' configures firejail 0.9.44.4 to adapt to many kinds of systems. | |
1261 | \`configure' configures firejail 0.9.44.6 to adapt to many kinds of systems. | |
1262 | 1262 | |
1263 | 1263 | Usage: $0 [OPTION]... [VAR=VALUE]... |
1264 | 1264 | |
1319 | 1319 | |
1320 | 1320 | if test -n "$ac_init_help"; then |
1321 | 1321 | case $ac_init_help in |
1322 | short | recursive ) echo "Configuration of firejail 0.9.44.4:";; | |
1322 | short | recursive ) echo "Configuration of firejail 0.9.44.6:";; | |
1323 | 1323 | esac |
1324 | 1324 | cat <<\_ACEOF |
1325 | 1325 | |
1423 | 1423 | test -n "$ac_init_help" && exit $ac_status |
1424 | 1424 | if $ac_init_version; then |
1425 | 1425 | cat <<\_ACEOF |
1426 | firejail configure 0.9.44.4 | |
1426 | firejail configure 0.9.44.6 | |
1427 | 1427 | generated by GNU Autoconf 2.69 |
1428 | 1428 | |
1429 | 1429 | Copyright (C) 2012 Free Software Foundation, Inc. |
1725 | 1725 | This file contains any messages produced by compilers while |
1726 | 1726 | running configure, to aid debugging if configure makes a mistake. |
1727 | 1727 | |
1728 | It was created by firejail $as_me 0.9.44.4, which was | |
1728 | It was created by firejail $as_me 0.9.44.6, which was | |
1729 | 1729 | generated by GNU Autoconf 2.69. Invocation command line was |
1730 | 1730 | |
1731 | 1731 | $ $0 $@ |
4302 | 4302 | # report actual input values of CONFIG_FILES etc. instead of their |
4303 | 4303 | # values after options handling. |
4304 | 4304 | ac_log=" |
4305 | This file was extended by firejail $as_me 0.9.44.4, which was | |
4305 | This file was extended by firejail $as_me 0.9.44.6, which was | |
4306 | 4306 | generated by GNU Autoconf 2.69. Invocation command line was |
4307 | 4307 | |
4308 | 4308 | CONFIG_FILES = $CONFIG_FILES |
4356 | 4356 | cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 |
4357 | 4357 | ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" |
4358 | 4358 | ac_cs_version="\\ |
4359 | firejail config.status 0.9.44.4 | |
4359 | firejail config.status 0.9.44.6 | |
4360 | 4360 | configured by $0, generated by GNU Autoconf 2.69, |
4361 | 4361 | with options \\"\$ac_cs_config\\" |
4362 | 4362 |
0 | 0 | AC_PREREQ([2.68]) |
1 | AC_INIT(firejail, 0.9.44.4, netblue30@yahoo.com, , http://firejail.wordpress.com) | |
1 | AC_INIT(firejail, 0.9.44.6, netblue30@yahoo.com, , http://firejail.wordpress.com) | |
2 | 2 | AC_CONFIG_SRCDIR([src/firejail/main.c]) |
3 | 3 | #AC_CONFIG_HEADERS([config.h]) |
4 | 4 |
0 | # Local customizations come here | |
1 | include /etc/firejail/disable-common.local | |
2 | ||
0 | 3 | # History files in $HOME |
1 | 4 | blacklist-nolog ${HOME}/.history |
2 | 5 | blacklist-nolog ${HOME}/.*_history |
0 | # Local customizations come here | |
1 | include /etc/firejail/disable-devel.local | |
2 | ||
0 | 3 | # development tools |
1 | 4 | |
2 | 5 | # GCC |
0 | # Local customizations come here | |
1 | include /etc/firejail/disable-passwdmgr.local | |
2 | ||
0 | 3 | blacklist ${HOME}/.pki/nssdb |
1 | 4 | blacklist ${HOME}/.lastpass |
2 | 5 | blacklist ${HOME}/.keepassx |
0 | # Local customizations come here | |
1 | include /etc/firejail/disable-programs.local | |
2 | ||
0 | 3 | # various programs |
1 | 4 | blacklist ${HOME}/.Atom |
2 | 5 | blacklist ${HOME}/.remmina |
0 | # Local customizations come here | |
1 | include /etc/firejail/whitelist-common.local | |
2 | ||
0 | 3 | # common whitelist for all profiles |
1 | 4 | |
2 | 5 | whitelist ~/.XCompose |
0 | 0 | #!/bin/bash |
1 | VERSION="0.9.44.4" | |
1 | VERSION="0.9.44.6" | |
2 | 2 | rm -fr ~/rpmbuild |
3 | 3 | rm -f firejail-$VERSION-1.x86_64.rpm |
4 | 4 | |
457 | 457 | chmod u+s /usr/bin/firejail |
458 | 458 | |
459 | 459 | %changelog |
460 | * Sun Jan 15 2017 netblue30 <netblue30@yahoo.com> 0.9.44.6-1 | |
461 | - security release | |
462 | ||
460 | 463 | * Sat Jan 7 2017 netblue30 <netblue30@yahoo.com> 0.9.44.4-1 |
461 | 464 | - security release |
462 | 465 |
67 | 67 | #define RUN_HOSTNAME_FILE "/run/firejail/mnt/hostname" |
68 | 68 | #define RUN_HOSTS_FILE "/run/firejail/mnt/hosts" |
69 | 69 | #define RUN_RESOLVCONF_FILE "/run/firejail/mnt/resolv.conf" |
70 | #define RUN_MACHINEID "/run/firejail/mnt/machine-id" | |
70 | 71 | #define RUN_LDPRELOAD_FILE "/run/firejail/mnt/ld.so.preload" |
71 | 72 | #define RUN_UTMP_FILE "/run/firejail/mnt/utmp" |
72 | 73 | #define RUN_PASSWD_FILE "/run/firejail/mnt/passwd" |
91 | 92 | #define ASSERT_PERMS_FD(fd, uid, gid, mode) \ |
92 | 93 | do { \ |
93 | 94 | struct stat s;\ |
94 | if (stat(fd, &s) == -1) errExit("stat");\ | |
95 | if (fstat(fd, &s) == -1) errExit("stat");\ | |
95 | 96 | assert(s.st_uid == uid);\ |
96 | 97 | assert(s.st_gid == gid);\ |
97 | 98 | assert((s.st_mode & 07777) == (mode));\ |
326 | 327 | extern int arg_x11_block; // block X11 |
327 | 328 | extern int arg_x11_xorg; // use X11 security extention |
328 | 329 | extern int arg_allusers; // all user home directories visible |
330 | extern int arg_machineid; // preserve /etc/machine-id | |
329 | 331 | |
330 | 332 | extern int login_shell; |
331 | 333 | extern int parent_to_child_fds[2]; |
390 | 392 | void fs_overlayfs(void); |
391 | 393 | // chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf |
392 | 394 | void fs_chroot(const char *rootdir); |
393 | int fs_check_chroot_dir(const char *rootdir); | |
395 | void fs_check_chroot_dir(const char *rootdir); | |
394 | 396 | void fs_private_tmp(void); |
395 | 397 | |
396 | 398 | // profile.c |
445 | 447 | void logargs(int argc, char **argv) ; |
446 | 448 | void logerr(const char *msg); |
447 | 449 | int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode); |
450 | void copy_file_as_user(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode); | |
451 | void touch_file_as_user(const char *fname, uid_t uid, gid_t gid, mode_t mode); | |
448 | 452 | int is_dir(const char *fname); |
449 | 453 | int is_link(const char *fname); |
450 | 454 | char *line_remove_spaces(const char *buf); |
564 | 568 | // fs_etc.c |
565 | 569 | void fs_check_etc_list(void); |
566 | 570 | void fs_private_etc_list(void); |
571 | void fs_machineid(void); | |
567 | 572 | |
568 | 573 | // no_sandbox.c |
569 | 574 | int check_namespace_virt(void); |
25 | 25 | #include <dirent.h> |
26 | 26 | #include <fcntl.h> |
27 | 27 | #include <errno.h> |
28 | #include <sys/wait.h> | |
29 | ||
28 | 30 | |
29 | 31 | static void fs_rdwr(const char *dir); |
30 | 32 | |
161 | 163 | fprintf(stderr, "Error: invalid /bin/cp file\n"); |
162 | 164 | exit(1); |
163 | 165 | } |
164 | int rv = copy_file(fname, RUN_CP_COMMAND, 0, 0, 0755); | |
166 | int rv = copy_file(fname, RUN_CP_COMMAND, 0, 0, 0755); // root needed | |
165 | 167 | if (rv) { |
166 | 168 | fprintf(stderr, "Error: cannot access /bin/cp\n"); |
167 | 169 | exit(1); |
775 | 777 | fs_var_lib(); |
776 | 778 | fs_var_cache(); |
777 | 779 | fs_var_utmp(); |
778 | ||
780 | fs_machineid(); | |
781 | ||
779 | 782 | // don't leak user information |
780 | 783 | restrict_users(); |
781 | 784 | |
796 | 799 | // create ~/.firejail directory |
797 | 800 | if (asprintf(&dirname, "%s/.firejail", cfg.homedir) == -1) |
798 | 801 | errExit("asprintf"); |
802 | ||
803 | if (is_link(dirname)) { | |
804 | fprintf(stderr, "Error: invalid ~/.firejail directory\n"); | |
805 | exit(1); | |
806 | } | |
799 | 807 | if (stat(dirname, &s) == -1) { |
800 | /* coverity[toctou] */ | |
801 | if (mkdir(dirname, 0700)) | |
802 | errExit("mkdir"); | |
803 | if (chmod(dirname, 0700) == -1) | |
804 | errExit("chmod"); | |
805 | ASSERT_PERMS(dirname, getuid(), getgid(), 0700); | |
806 | } | |
807 | else if (is_link(dirname)) { | |
808 | // create directory | |
809 | pid_t child = fork(); | |
810 | if (child < 0) | |
811 | errExit("fork"); | |
812 | if (child == 0) { | |
813 | // drop privileges | |
814 | drop_privs(0); | |
815 | ||
816 | // create directory | |
817 | if (mkdir(dirname, 0700)) | |
818 | errExit("mkdir"); | |
819 | if (chmod(dirname, 0700) == -1) | |
820 | errExit("chmod"); | |
821 | ASSERT_PERMS(dirname, getuid(), getgid(), 0700); | |
822 | _exit(0); | |
823 | } | |
824 | // wait for the child to finish | |
825 | waitpid(child, NULL, 0); | |
826 | if (stat(dirname, &s) == -1) { | |
827 | fprintf(stderr, "Error: cannot create ~/.firejail directory\n"); | |
828 | exit(1); | |
829 | } | |
830 | } | |
831 | else if (s.st_uid != getuid()) { | |
808 | 832 | fprintf(stderr, "Error: invalid ~/.firejail directory\n"); |
809 | 833 | exit(1); |
810 | 834 | } |
1082 | 1106 | fs_var_lib(); |
1083 | 1107 | fs_var_cache(); |
1084 | 1108 | fs_var_utmp(); |
1109 | fs_machineid(); | |
1085 | 1110 | |
1086 | 1111 | // don't leak user information |
1087 | 1112 | restrict_users(); |
1101 | 1126 | |
1102 | 1127 | |
1103 | 1128 | #ifdef HAVE_CHROOT |
1104 | // return 1 if error | |
1105 | int fs_check_chroot_dir(const char *rootdir) { | |
1129 | void fs_check_chroot_dir(const char *rootdir) { | |
1106 | 1130 | EUID_ASSERT(); |
1107 | 1131 | assert(rootdir); |
1108 | 1132 | struct stat s; |
1109 | 1133 | char *name; |
1110 | 1134 | |
1135 | if (strcmp(rootdir, "/tmp") == 0 || strcmp(rootdir, "/var/tmp") == 0) { | |
1136 | fprintf(stderr, "Error: invalid chroot directory\n"); | |
1137 | exit(1); | |
1138 | } | |
1139 | ||
1111 | 1140 | // rootdir has to be owned by root |
1112 | 1141 | if (stat(rootdir, &s) != 0) { |
1113 | 1142 | fprintf(stderr, "Error: cannot find chroot directory\n"); |
1114 | return 1; | |
1143 | exit(1); | |
1115 | 1144 | } |
1116 | 1145 | if (s.st_uid != 0) { |
1117 | 1146 | fprintf(stderr, "Error: chroot directory should be owned by root\n"); |
1118 | return 1; | |
1147 | exit(1); | |
1119 | 1148 | } |
1120 | 1149 | |
1121 | 1150 | // check /dev |
1123 | 1152 | errExit("asprintf"); |
1124 | 1153 | if (stat(name, &s) == -1) { |
1125 | 1154 | fprintf(stderr, "Error: cannot find /dev in chroot directory\n"); |
1126 | return 1; | |
1155 | exit(1); | |
1156 | } | |
1157 | if (s.st_uid != 0) { | |
1158 | fprintf(stderr, "Error: chroot /dev directory should be owned by root\n"); | |
1159 | exit(1); | |
1127 | 1160 | } |
1128 | 1161 | free(name); |
1129 | 1162 | |
1132 | 1165 | errExit("asprintf"); |
1133 | 1166 | if (stat(name, &s) == -1) { |
1134 | 1167 | fprintf(stderr, "Error: cannot find /var/tmp in chroot directory\n"); |
1135 | return 1; | |
1168 | exit(1); | |
1169 | } | |
1170 | if (s.st_uid != 0) { | |
1171 | fprintf(stderr, "Error: chroot /var/tmp directory should be owned by root\n"); | |
1172 | exit(1); | |
1136 | 1173 | } |
1137 | 1174 | free(name); |
1138 | 1175 | |
1141 | 1178 | errExit("asprintf"); |
1142 | 1179 | if (stat(name, &s) == -1) { |
1143 | 1180 | fprintf(stderr, "Error: cannot find /proc in chroot directory\n"); |
1144 | return 1; | |
1181 | exit(1); | |
1182 | } | |
1183 | if (s.st_uid != 0) { | |
1184 | fprintf(stderr, "Error: chroot /proc directory should be owned by root\n"); | |
1185 | exit(1); | |
1145 | 1186 | } |
1146 | 1187 | free(name); |
1147 | 1188 | |
1150 | 1191 | errExit("asprintf"); |
1151 | 1192 | if (stat(name, &s) == -1) { |
1152 | 1193 | fprintf(stderr, "Error: cannot find /tmp in chroot directory\n"); |
1153 | return 1; | |
1194 | exit(1); | |
1195 | } | |
1196 | if (s.st_uid != 0) { | |
1197 | fprintf(stderr, "Error: chroot /tmp directory should be owned by root\n"); | |
1198 | exit(1); | |
1154 | 1199 | } |
1155 | 1200 | free(name); |
1156 | 1201 | |
1157 | // check /bin/bash | |
1158 | // if (asprintf(&name, "%s/bin/bash", rootdir) == -1) | |
1159 | // errExit("asprintf"); | |
1160 | // if (stat(name, &s) == -1) { | |
1161 | // fprintf(stderr, "Error: cannot find /bin/bash in chroot directory\n"); | |
1162 | // return 1; | |
1163 | // } | |
1164 | // free(name); | |
1202 | // check /etc | |
1203 | if (asprintf(&name, "%s/etc", rootdir) == -1) | |
1204 | errExit("asprintf"); | |
1205 | if (stat(name, &s) == -1) { | |
1206 | fprintf(stderr, "Error: cannot find /etc in chroot directory\n"); | |
1207 | exit(1); | |
1208 | } | |
1209 | if (s.st_uid != 0) { | |
1210 | fprintf(stderr, "Error: chroot /etc directory should be owned by root\n"); | |
1211 | exit(1); | |
1212 | } | |
1213 | free(name); | |
1214 | ||
1215 | // check /etc/resolv.conf | |
1216 | if (asprintf(&name, "%s/etc/resolv.conf", rootdir) == -1) | |
1217 | errExit("asprintf"); | |
1218 | if (stat(name, &s) == 0) { | |
1219 | if (s.st_uid != 0) { | |
1220 | fprintf(stderr, "Error: chroot /etc/resolv.conf should be owned by root\n"); | |
1221 | exit(1); | |
1222 | } | |
1223 | } | |
1224 | if (is_link(name)) { | |
1225 | fprintf(stderr, "Error: invalid %s file\n", name); | |
1226 | exit(1); | |
1227 | } | |
1228 | free(name); | |
1165 | 1229 | |
1166 | 1230 | // check x11 socket directory |
1167 | 1231 | if (getenv("FIREJAIL_X11")) { |
1171 | 1235 | errExit("asprintf"); |
1172 | 1236 | if (stat(name, &s) == -1) { |
1173 | 1237 | fprintf(stderr, "Error: cannot find /tmp/.X11-unix in chroot directory\n"); |
1174 | return 1; | |
1238 | exit(1); | |
1239 | } | |
1240 | if (s.st_uid != 0) { | |
1241 | fprintf(stderr, "Error: chroot /tmp/.X11-unix directory should be owned by root\n"); | |
1242 | exit(1); | |
1175 | 1243 | } |
1176 | 1244 | free(name); |
1177 | 1245 | } |
1178 | ||
1179 | return 0; | |
1180 | 1246 | } |
1181 | 1247 | |
1182 | 1248 | // chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf |
1213 | 1279 | char *rundir; |
1214 | 1280 | if (asprintf(&rundir, "%s/run", rootdir) == -1) |
1215 | 1281 | errExit("asprintf"); |
1282 | if (is_link(rundir)) { | |
1283 | fprintf(stderr, "Error: invalid run directory inside chroot\n"); | |
1284 | exit(1); | |
1285 | } | |
1216 | 1286 | if (!is_dir(rundir)) { |
1217 | 1287 | int rv = mkdir(rundir, 0755); |
1218 | 1288 | (void) rv; |
1232 | 1302 | fprintf(stderr, "Error: invalid %s file\n", fname); |
1233 | 1303 | exit(1); |
1234 | 1304 | } |
1235 | if (copy_file("/etc/resolv.conf", fname, 0, 0, 0644) == -1) | |
1305 | if (copy_file("/etc/resolv.conf", fname, 0, 0, 0644) == -1) // root needed | |
1236 | 1306 | fprintf(stderr, "Warning: /etc/resolv.conf not initialized\n"); |
1237 | 1307 | } |
1238 | 1308 | |
1254 | 1324 | fs_var_lib(); |
1255 | 1325 | fs_var_cache(); |
1256 | 1326 | fs_var_utmp(); |
1327 | fs_machineid(); | |
1257 | 1328 | |
1258 | 1329 | // don't leak user information |
1259 | 1330 | restrict_users(); |
27 | 27 | #ifndef _BSD_SOURCE |
28 | 28 | #define _BSD_SOURCE |
29 | 29 | #endif |
30 | #include <sys/sysmacros.h> | |
30 | 31 | #include <sys/types.h> |
31 | 32 | |
32 | 33 | typedef struct { |
50 | 51 | {"/dev/nvidia8", RUN_DEV_DIR "/nvidia8", 0, 1}, |
51 | 52 | {"/dev/nvidia9", RUN_DEV_DIR "/nvidia9", 0, 1}, |
52 | 53 | {"/dev/nvidiactl", RUN_DEV_DIR "/nvidiactl", 0, 1}, |
53 | {"/dev/nvidia-modset", RUN_DEV_DIR "/nvidia-modset", 0, 1}, | |
54 | {"/dev/nvidia-modeset", RUN_DEV_DIR "/nvidia-modeset", 0, 1}, | |
54 | 55 | {"/dev/nvidia-uvm", RUN_DEV_DIR "/nvidia-uvm", 0, 1}, |
55 | 56 | {NULL, NULL, 0, 0} |
56 | 57 | }; |
22 | 22 | #include <sys/types.h> |
23 | 23 | #include <sys/wait.h> |
24 | 24 | #include <unistd.h> |
25 | #include <time.h> | |
26 | ||
27 | // spoof /etc/machine_id | |
28 | void fs_machineid(void) { | |
29 | union machineid_t { | |
30 | uint8_t u8[16]; | |
31 | uint32_t u32[4]; | |
32 | } mid; | |
33 | ||
34 | // if --machine-id flag is active, do nothing | |
35 | if (arg_machineid) | |
36 | return; | |
37 | ||
38 | // init random number generator | |
39 | srand(time(NULL)); | |
40 | ||
41 | // generate random id | |
42 | mid.u32[0] = rand(); | |
43 | mid.u32[1] = rand(); | |
44 | mid.u32[2] = rand(); | |
45 | mid.u32[3] = rand(); | |
46 | ||
47 | // UUID version 4 and DCE variant | |
48 | mid.u8[6] = (mid.u8[6] & 0x0F) | 0x40; | |
49 | mid.u8[8] = (mid.u8[8] & 0x3F) | 0x80; | |
50 | ||
51 | // write it in a file | |
52 | FILE *fp = fopen(RUN_MACHINEID, "w"); | |
53 | if (!fp) | |
54 | errExit("fopen"); | |
55 | fprintf(fp, "%08x%08x%08x%08x\n", mid.u32[0], mid.u32[1], mid.u32[2], mid.u32[3]); | |
56 | fclose(fp); | |
57 | if (set_perms(RUN_MACHINEID, 0, 0, 0444)) | |
58 | errExit("set_perms"); | |
59 | ||
60 | ||
61 | struct stat s; | |
62 | if (stat("/etc/machine-id", &s) == 0) { | |
63 | if (arg_debug) | |
64 | printf("installing a new /etc/machine-id\n"); | |
65 | ||
66 | if (mount(RUN_MACHINEID, "/etc/machine-id", "none", MS_BIND, "mode=444,gid=0")) | |
67 | errExit("mount"); | |
68 | } | |
69 | if (stat("/var/lib/dbus/machine-id", &s) == 0) { | |
70 | if (mount(RUN_MACHINEID, "/var/lib/dbus/machine-id", "none", MS_BIND, "mode=444,gid=0")) | |
71 | errExit("mount"); | |
72 | } | |
73 | } | |
25 | 74 | |
26 | 75 | // return 0 if file not found, 1 if found |
27 | 76 | static int check_dir_or_file(const char *name) { |
41 | 41 | // don't copy it if we already have the file |
42 | 42 | if (stat(fname, &s) == 0) |
43 | 43 | return; |
44 | if (is_link(fname)) { // stat on dangling symlinks fails, try again using lstat | |
45 | fprintf(stderr, "Error: invalid %s file\n", fname); | |
46 | exit(1); | |
47 | } | |
44 | 48 | if (stat("/etc/skel/.zshrc", &s) == 0) { |
45 | if (copy_file("/etc/skel/.zshrc", fname, u, g, 0644) == 0) { | |
46 | fs_logger("clone /etc/skel/.zshrc"); | |
47 | } | |
48 | } | |
49 | else { // | |
50 | FILE *fp = fopen(fname, "w"); | |
51 | if (fp) { | |
52 | fprintf(fp, "\n"); | |
53 | SET_PERMS_STREAM(fp, u, g, S_IRUSR | S_IWUSR); | |
54 | fclose(fp); | |
55 | fs_logger2("touch", fname); | |
56 | } | |
49 | copy_file_as_user("/etc/skel/.zshrc", fname, u, g, 0644); // regular user | |
50 | fs_logger("clone /etc/skel/.zshrc"); | |
51 | } | |
52 | else { | |
53 | touch_file_as_user(fname, u, g, 0644); | |
54 | fs_logger2("touch", fname); | |
57 | 55 | } |
58 | 56 | free(fname); |
59 | 57 | } |
66 | 64 | // don't copy it if we already have the file |
67 | 65 | if (stat(fname, &s) == 0) |
68 | 66 | return; |
67 | if (is_link(fname)) { // stat on dangling symlinks fails, try again using lstat | |
68 | fprintf(stderr, "Error: invalid %s file\n", fname); | |
69 | exit(1); | |
70 | } | |
69 | 71 | if (stat("/etc/skel/.cshrc", &s) == 0) { |
70 | if (copy_file("/etc/skel/.cshrc", fname, u, g, 0644) == 0) { | |
71 | fs_logger("clone /etc/skel/.cshrc"); | |
72 | } | |
73 | } | |
74 | else { // | |
75 | /* coverity[toctou] */ | |
76 | FILE *fp = fopen(fname, "w"); | |
77 | if (fp) { | |
78 | fprintf(fp, "\n"); | |
79 | SET_PERMS_STREAM(fp, u, g, S_IRUSR | S_IWUSR); | |
80 | fclose(fp); | |
81 | fs_logger2("touch", fname); | |
82 | } | |
72 | copy_file_as_user("/etc/skel/.cshrc", fname, u, g, 0644); // regular user | |
73 | fs_logger("clone /etc/skel/.cshrc"); | |
74 | } | |
75 | else { | |
76 | touch_file_as_user(fname, u, g, 0644); | |
77 | fs_logger2("touch", fname); | |
83 | 78 | } |
84 | 79 | free(fname); |
85 | 80 | } |
92 | 87 | // don't copy it if we already have the file |
93 | 88 | if (stat(fname, &s) == 0) |
94 | 89 | return; |
90 | if (is_link(fname)) { // stat on dangling symlinks fails, try again using lstat | |
91 | fprintf(stderr, "Error: invalid %s file\n", fname); | |
92 | exit(1); | |
93 | } | |
95 | 94 | if (stat("/etc/skel/.bashrc", &s) == 0) { |
96 | if (copy_file("/etc/skel/.bashrc", fname, u, g, 0644) == 0) { | |
97 | fs_logger("clone /etc/skel/.bashrc"); | |
98 | } | |
95 | copy_file_as_user("/etc/skel/.bashrc", fname, u, g, 0644); // regular user | |
96 | fs_logger("clone /etc/skel/.bashrc"); | |
99 | 97 | } |
100 | 98 | free(fname); |
101 | 99 | } |
107 | 105 | |
108 | 106 | char *src; |
109 | 107 | char *dest = RUN_XAUTHORITY_FILE; |
110 | // create an empty file | |
108 | // create an empty file as root, and change ownership to user | |
111 | 109 | FILE *fp = fopen(dest, "w"); |
112 | 110 | if (fp) { |
113 | 111 | fprintf(fp, "\n"); |
125 | 123 | return 0; |
126 | 124 | } |
127 | 125 | |
128 | pid_t child = fork(); | |
129 | if (child < 0) | |
130 | errExit("fork"); | |
131 | if (child == 0) { | |
132 | // drop privileges | |
133 | drop_privs(0); | |
134 | ||
135 | // copy, set permissions and ownership | |
136 | int rv = copy_file(src, dest, getuid(), getgid(), 0600); | |
137 | if (rv) | |
138 | fprintf(stderr, "Warning: cannot transfer .Xauthority in private home directory\n"); | |
139 | else { | |
140 | fs_logger2("clone", dest); | |
141 | } | |
142 | _exit(0); | |
143 | } | |
144 | // wait for the child to finish | |
145 | waitpid(child, NULL, 0); | |
126 | copy_file_as_user(src, dest, getuid(), getgid(), 0600); // regular user | |
127 | fs_logger2("clone", dest); | |
146 | 128 | return 1; // file copied |
147 | 129 | } |
148 | 130 | |
155 | 137 | |
156 | 138 | char *src; |
157 | 139 | char *dest = RUN_ASOUNDRC_FILE; |
158 | // create an empty file | |
140 | // create an empty file as root, and change ownership to user | |
159 | 141 | FILE *fp = fopen(dest, "w"); |
160 | 142 | if (fp) { |
161 | 143 | fprintf(fp, "\n"); |
183 | 165 | free(rp); |
184 | 166 | } |
185 | 167 | |
186 | pid_t child = fork(); | |
187 | if (child < 0) | |
188 | errExit("fork"); | |
189 | if (child == 0) { | |
190 | // drop privileges | |
191 | drop_privs(0); | |
192 | ||
193 | // copy, set permissions and ownership | |
194 | int rv = copy_file(src, dest, getuid(), getgid(), 0644); | |
195 | if (rv) | |
196 | fprintf(stderr, "Warning: cannot transfer .asoundrc in private home directory\n"); | |
197 | else { | |
198 | fs_logger2("clone", dest); | |
199 | } | |
200 | _exit(0); | |
201 | } | |
202 | // wait for the child to finish | |
203 | waitpid(child, NULL, 0); | |
168 | copy_file_as_user(src, dest, getuid(), getgid(), 0644); // regular user | |
169 | fs_logger2("clone", dest); | |
204 | 170 | return 1; // file copied |
205 | 171 | } |
206 | 172 | |
220 | 186 | exit(1); |
221 | 187 | } |
222 | 188 | |
223 | pid_t child = fork(); | |
224 | if (child < 0) | |
225 | errExit("fork"); | |
226 | if (child == 0) { | |
227 | // drop privileges | |
228 | drop_privs(0); | |
229 | ||
230 | // copy, set permissions and ownership | |
231 | int rv = copy_file(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR); | |
232 | if (rv) | |
233 | fprintf(stderr, "Warning: cannot transfer .Xauthority in private home directory\n"); | |
234 | else { | |
235 | fs_logger2("clone", dest); | |
236 | } | |
237 | _exit(0); | |
238 | } | |
239 | // wait for the child to finish | |
240 | waitpid(child, NULL, 0); | |
189 | copy_file_as_user(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR); // regular user | |
190 | fs_logger2("clone", dest); | |
241 | 191 | |
242 | 192 | // delete the temporary file |
243 | 193 | unlink(src); |
256 | 206 | exit(1); |
257 | 207 | } |
258 | 208 | |
259 | pid_t child = fork(); | |
260 | if (child < 0) | |
261 | errExit("fork"); | |
262 | if (child == 0) { | |
263 | // drop privileges | |
264 | drop_privs(0); | |
265 | ||
266 | // copy, set permissions and ownership | |
267 | int rv = copy_file(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR); | |
268 | if (rv) | |
269 | fprintf(stderr, "Warning: cannot transfer .asoundrc in private home directory\n"); | |
270 | else { | |
271 | fs_logger2("clone", dest); | |
272 | } | |
273 | _exit(0); | |
274 | } | |
275 | // wait for the child to finish | |
276 | waitpid(child, NULL, 0); | |
209 | copy_file_as_user(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR); // regular user | |
210 | fs_logger2("clone", dest); | |
277 | 211 | |
278 | 212 | // delete the temporary file |
279 | 213 | unlink(src); |
478 | 412 | size_cnt += s.st_size; |
479 | 413 | |
480 | 414 | if(ftype == FTW_F) |
481 | copy_file(path, dest, firejail_uid, firejail_gid, s.st_mode); | |
415 | copy_file(path, dest, firejail_uid, firejail_gid, s.st_mode); // already a regular user | |
482 | 416 | else if (ftype == FTW_D) { |
483 | 417 | if (mkdir(dest, s.st_mode) == -1) |
484 | 418 | errExit("mkdir"); |
107 | 107 | } |
108 | 108 | |
109 | 109 | // create file |
110 | pid_t child = fork(); | |
111 | if (child < 0) | |
112 | errExit("fork"); | |
113 | if (child == 0) { | |
114 | // drop privileges | |
115 | drop_privs(0); | |
116 | ||
117 | FILE *fp = fopen(expanded, "w"); | |
118 | if (!fp) | |
119 | fprintf(stderr, "Warning: cannot create %s file\n", expanded); | |
120 | else { | |
121 | int fd = fileno(fp); | |
122 | if (fd == -1) | |
123 | errExit("fileno"); | |
124 | int rv = fchmod(fd, 0600); | |
125 | (void) rv; | |
126 | fclose(fp); | |
127 | } | |
128 | _exit(0); | |
129 | } | |
130 | // wait for the child to finish | |
131 | waitpid(child, NULL, 0); | |
110 | touch_file_as_user(expanded, getuid(), getgid(), 0600); | |
132 | 111 | |
133 | 112 | doexit: |
134 | 113 | free(expanded); |
355 | 355 | drop_privs(0); |
356 | 356 | |
357 | 357 | // copy the file |
358 | if (copy_file(src_fname, tmp_fname, getuid(), getgid(), 0600)) | |
358 | if (copy_file(src_fname, tmp_fname, getuid(), getgid(), 0600)) // already a regular user | |
359 | 359 | _exit(1); |
360 | 360 | _exit(0); |
361 | 361 | } |
378 | 378 | drop_privs(0); |
379 | 379 | |
380 | 380 | // copy the file |
381 | if (copy_file(tmp_fname, dest_fname, getuid(), getgid(), 0600)) | |
381 | if (copy_file(tmp_fname, dest_fname, getuid(), getgid(), 0600)) // aleady a regular user | |
382 | 382 | _exit(1); |
383 | 383 | _exit(0); |
384 | 384 | } |
421 | 421 | drop_privs(0); |
422 | 422 | |
423 | 423 | // copy the file |
424 | if (copy_file(src_fname, tmp_fname, getuid(), getgid(), 0600)) | |
424 | if (copy_file(src_fname, tmp_fname, getuid(), getgid(), 0600)) // already regular user | |
425 | 425 | _exit(1); |
426 | 426 | _exit(0); |
427 | 427 | } |
450 | 450 | drop_privs(0); |
451 | 451 | |
452 | 452 | // copy the file |
453 | if (copy_file(tmp_fname, dest_fname, getuid(), getgid(), 0600)) | |
453 | if (copy_file(tmp_fname, dest_fname, getuid(), getgid(), 0600)) // already a regular user | |
454 | 454 | _exit(1); |
455 | 455 | _exit(0); |
456 | 456 | } |
109 | 109 | int arg_x11_block = 0; // block X11 |
110 | 110 | int arg_x11_xorg = 0; // use X11 security extention |
111 | 111 | int arg_allusers = 0; // all user home directories visible |
112 | int arg_machineid = 0; // preserve /etc/machine-id | |
112 | 113 | |
113 | 114 | int login_shell = 0; |
114 | 115 | |
1629 | 1630 | fprintf(stderr, "Error: invalid chroot directory\n"); |
1630 | 1631 | exit(1); |
1631 | 1632 | } |
1632 | free(rpath); | |
1633 | cfg.chrootdir = rpath; | |
1633 | 1634 | |
1634 | 1635 | // check chroot directory structure |
1635 | if (fs_check_chroot_dir(cfg.chrootdir)) { | |
1636 | fprintf(stderr, "Error: invalid chroot\n"); | |
1637 | exit(1); | |
1638 | } | |
1636 | fs_check_chroot_dir(cfg.chrootdir); | |
1639 | 1637 | } |
1640 | 1638 | else { |
1641 | 1639 | fprintf(stderr, "Error: --chroot feature is disabled in Firejail configuration file\n"); |
1652 | 1650 | } |
1653 | 1651 | else if (strcmp(argv[i], "--writable-var") == 0) { |
1654 | 1652 | arg_writable_var = 1; |
1653 | } | |
1654 | else if (strcmp(argv[i], "--machine-id") == 0) { | |
1655 | arg_machineid = 1; | |
1655 | 1656 | } |
1656 | 1657 | else if (strcmp(argv[i], "--private") == 0) { |
1657 | 1658 | arg_private = 1; |
641 | 641 | return 0; |
642 | 642 | } |
643 | 643 | |
644 | if (strcmp(ptr, "machine-id") == 0) { | |
645 | arg_machineid = 1; | |
646 | return 0; | |
647 | } | |
644 | 648 | // writable-var |
645 | 649 | if (strcmp(ptr, "writable-var") == 0) { |
646 | 650 | arg_writable_var = 1; |
965 | 969 | // open profile file: |
966 | 970 | FILE *fp = fopen(fname, "r"); |
967 | 971 | if (fp == NULL) { |
972 | // if the file ends in ".local", do not exit | |
973 | char *ptr = strstr(fname, ".local"); | |
974 | if (ptr && strlen(ptr) == 6) | |
975 | return; | |
976 | ||
968 | 977 | fprintf(stderr, "Error: cannot open profile file %s\n", fname); |
969 | 978 | exit(1); |
970 | 979 | } |
116 | 116 | char *pulsecfg = NULL; |
117 | 117 | if (asprintf(&pulsecfg, "%s/client.conf", RUN_PULSE_DIR) == -1) |
118 | 118 | errExit("asprintf"); |
119 | if (copy_file("/etc/pulse/client.conf", pulsecfg, -1, -1, 0644)) | |
119 | if (copy_file("/etc/pulse/client.conf", pulsecfg, -1, -1, 0644)) // root needed | |
120 | 120 | errExit("copy_file"); |
121 | 121 | FILE *fp = fopen(pulsecfg, "a+"); |
122 | 122 | if (!fp) |
121 | 121 | printf(" --ls=name|pid dir_or_filename - list files in sandbox container.\n\n"); |
122 | 122 | #ifdef HAVE_NETWORK |
123 | 123 | printf(" --mac=xx:xx:xx:xx:xx:xx - set interface MAC address.\n\n"); |
124 | #endif | |
125 | printf(" --machine-id - preserve /etc/machine-id\n"); | |
126 | #ifdef HAVE_NETWORK | |
124 | 127 | printf(" --mtu=number - set interface MTU.\n\n"); |
125 | 128 | #endif |
126 | 129 | printf(" --name=name - set sandbox name.\n\n"); |
27 | 27 | #include <grp.h> |
28 | 28 | #include <sys/ioctl.h> |
29 | 29 | #include <termios.h> |
30 | #include <sys/wait.h> | |
30 | 31 | |
31 | 32 | #define MAX_GROUPS 1024 |
32 | 33 | // drop privileges |
218 | 219 | return 0; |
219 | 220 | } |
220 | 221 | |
222 | // return -1 if error, 0 if no error | |
223 | void copy_file_as_user(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode) { | |
224 | pid_t child = fork(); | |
225 | if (child < 0) | |
226 | errExit("fork"); | |
227 | if (child == 0) { | |
228 | // drop privileges | |
229 | drop_privs(0); | |
230 | ||
231 | // copy, set permissions and ownership | |
232 | int rv = copy_file(srcname, destname, uid, gid, mode); // already a regular user | |
233 | if (rv) | |
234 | fprintf(stderr, "Warning: cannot copy %s\n", srcname); | |
235 | _exit(0); | |
236 | } | |
237 | // wait for the child to finish | |
238 | waitpid(child, NULL, 0); | |
239 | } | |
240 | ||
241 | // return -1 if error, 0 if no error | |
242 | void touch_file_as_user(const char *fname, uid_t uid, gid_t gid, mode_t mode) { | |
243 | pid_t child = fork(); | |
244 | if (child < 0) | |
245 | errExit("fork"); | |
246 | if (child == 0) { | |
247 | // drop privileges | |
248 | drop_privs(0); | |
249 | ||
250 | FILE *fp = fopen(fname, "w"); | |
251 | if (fp) { | |
252 | fprintf(fp, "\n"); | |
253 | SET_PERMS_STREAM(fp, uid, gid, mode); | |
254 | fclose(fp); | |
255 | } | |
256 | _exit(0); | |
257 | } | |
258 | // wait for the child to finish | |
259 | waitpid(child, NULL, 0); | |
260 | } | |
221 | 261 | |
222 | 262 | // return 1 if the file is a directory |
223 | 263 | int is_dir(const char *fname) { |
650 | 650 | struct stat s; |
651 | 651 | if (stat(dest, &s) == -1) { |
652 | 652 | // create an .Xauthority file |
653 | FILE *fp = fopen(dest, "w"); | |
654 | if (!fp) | |
655 | errExit("fopen"); | |
656 | SET_PERMS_STREAM(fp, getuid(), getgid(), 0600); | |
657 | fclose(fp); | |
653 | touch_file_as_user(dest, getuid(), getgid(), 0600); | |
658 | 654 | } |
659 | 655 | |
660 | 656 | // check xauth utility is present in the system |
662 | 658 | fprintf(stderr, "Error: cannot find /usr/bin/xauth executable\n"); |
663 | 659 | exit(1); |
664 | 660 | } |
661 | ||
662 | // temporarily mount a tempfs on top of /tmp directory | |
663 | if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) | |
664 | errExit("mounting /tmp"); | |
665 | 665 | |
666 | 666 | // create a temporary .Xauthority file |
667 | 667 | char tmpfname[] = "/tmp/.tmpXauth-XXXXXX"; |
670 | 670 | fprintf(stderr, "Error: cannot create .Xauthority file\n"); |
671 | 671 | exit(1); |
672 | 672 | } |
673 | if (fchown(fd, getuid(), getgid()) == -1) | |
674 | errExit("chown"); | |
673 | 675 | close(fd); |
674 | if (chown(tmpfname, getuid(), getgid()) == -1) | |
675 | errExit("chown"); | |
676 | 676 | |
677 | 677 | pid_t child = fork(); |
678 | 678 | if (child < 0) |
709 | 709 | |
710 | 710 | // move the temporary file in RUN_XAUTHORITY_SEC_FILE in order to have it deleted |
711 | 711 | // automatically when the sandbox is closed |
712 | if (copy_file(tmpfname, RUN_XAUTHORITY_SEC_FILE, getuid(), getgid(), 0600)) { | |
712 | if (copy_file(tmpfname, RUN_XAUTHORITY_SEC_FILE, getuid(), getgid(), 0600)) { // root needed | |
713 | 713 | fprintf(stderr, "asdfdsfError: cannot create the new .Xauthority file\n"); |
714 | 714 | exit(1); |
715 | 715 | } |
729 | 729 | if (chmod(dest, 0600) == -1) |
730 | 730 | errExit("chmod"); |
731 | 731 | free(dest); |
732 | ||
733 | // unmount /tmp | |
734 | umount("/tmp"); | |
732 | 735 | #endif |
733 | 736 | } |
84 | 84 | file in user home directory. |
85 | 85 | |
86 | 86 | Example: "include ${HOME}/myprofiles/profile1" will load "~/myprofiles/profile1" file. |
87 | ||
88 | If the file is not found, and the file name does not end in ".local", the sandbox exist immediately | |
89 | with an error printed on stderr. ".local" files can be used to customize the global configuration | |
90 | in /etc/firejail directory. These files are not overwritten during software install. | |
87 | 91 | |
88 | 92 | .TP |
89 | 93 | \fBnoblacklist file_name |
434 | 438 | .TP |
435 | 439 | \fBmac address |
436 | 440 | Assign MAC addresses to the last network interface defined by a net command. |
441 | ||
442 | .TP | |
443 | \fBmachine-id | |
444 | Preserve id number in /etc/machine-id file. By default a new random id is generated inside the sandbox. | |
437 | 445 | |
438 | 446 | .TP |
439 | 447 | \fBmtu number |
667 | 667 | $ firejail \-\-net=eth0 \-\-mac=00:11:22:33:44:55 firefox |
668 | 668 | |
669 | 669 | .TP |
670 | \fB\-\-machine-id | |
671 | Preserve id number in /etc/machine-id file. By default a new random id is generated inside the sandbox. | |
672 | .br | |
673 | ||
674 | .br | |
675 | Example: | |
676 | .br | |
677 | $ firejail \-\-machine-id | |
678 | ||
679 | .TP | |
670 | 680 | \fB\-\-mtu=number |
671 | 681 | Assign a MTU value to the last network interface defined by a \-\-net option. |
672 | 682 | .br |