From 1379851360349d6617ad32944a25ee5e2bb74fc2 Mon Sep 17 00:00:00 2001 From: netblue30 Date: Sat, 8 Aug 2015 19:12:30 -0400 Subject: [PATCH] Baseline firejail 0.9.28 --- COPYING | 280 ++ Makefile.in | 156 + README | 28 + RELNOTES | 215 ++ configure | 4723 +++++++++++++++++++++++++++++ configure.ac | 52 + etc/audacious.profile | 8 + etc/chromium-browser.profile | 3 + etc/chromium.profile | 7 + etc/clementine.profile | 7 + etc/deadbeef.profile | 8 + etc/deluge.profile | 9 + etc/disable-common.inc | 10 + etc/disable-mgmt.inc | 12 + etc/disable-secret.inc | 9 + etc/dropbox.profile | 7 + etc/empathy.profile | 6 + etc/evince.profile | 8 + etc/filezilla.profile | 10 + etc/firefox.profile | 9 + etc/firejail.bash_completion | 86 + etc/firemon.bash_completion | 39 + etc/generic.profile | 41 + etc/gnome-mplayer.profile | 7 + etc/icecat.profile | 2 + etc/icedove.profile | 3 + etc/iceweasel.profile | 2 + etc/login.users | 14 + etc/midori.profile | 9 + etc/opera.profile | 8 + etc/pidgin.profile | 7 + etc/qbittorrent.profile | 9 + etc/quassel.profile | 7 + etc/rhythmbox.profile | 7 + etc/server.profile | 6 + etc/thunderbird.profile | 9 + etc/totem.profile | 7 + etc/transmission-gtk.profile | 9 + etc/transmission-qt.profile | 9 + etc/vlc.profile | 7 + etc/xchat.profile | 7 + install.sh | 2 + mkdeb.sh | 96 + mkman.sh | 7 + platform/debian/conffiles | 33 + platform/debian/control | 20 + platform/debian/copyright | 30 + platform/rpm/mkrpm.sh | 256 ++ src/firejail/Makefile.in | 28 + src/firejail/arg-checking.txt | 85 + src/firejail/arp.c | 474 +++ src/firejail/bandwidth.c | 483 +++ src/firejail/caps.c | 453 +++ src/firejail/cgroup.c | 118 + src/firejail/cpu.c | 141 + src/firejail/firejail.h | 354 +++ src/firejail/fs.c | 825 ++++++ src/firejail/fs_dev.c | 163 + src/firejail/fs_home.c | 494 +++ src/firejail/fs_hostname.c | 157 + src/firejail/fs_trace.c | 76 + src/firejail/fs_var.c | 388 +++ src/firejail/join.c | 364 +++ src/firejail/list.c | 65 + src/firejail/main.c | 1168 ++++++++ src/firejail/netfilter.c | 164 + src/firejail/network.c | 362 +++ src/firejail/network.txt | 95 + src/firejail/network_main.c | 268 ++ src/firejail/output.c | 84 + src/firejail/profile.c | 444 +++ src/firejail/restricted_shell.c | 96 + src/firejail/rlimit.c | 62 + src/firejail/sandbox.c | 490 +++ src/firejail/seccomp.c | 658 ++++ src/firejail/shutdown.c | 98 + src/firejail/syscall.c | 4942 +++++++++++++++++++++++++++++++ src/firejail/usage.c | 312 ++ src/firejail/util.c | 480 +++ src/firejail/veth.c | 191 ++ src/firemon/Makefile.in | 24 + src/firemon/arp.c | 99 + src/firemon/caps.c | 69 + src/firemon/cgroup.c | 64 + src/firemon/cpu.c | 68 + src/firemon/firemon.c | 222 ++ src/firemon/firemon.h | 84 + src/firemon/interface.c | 176 ++ src/firemon/list.c | 35 + src/firemon/netstats.c | 214 ++ src/firemon/procevent.c | 377 +++ src/firemon/route.c | 213 ++ src/firemon/seccomp.c | 69 + src/firemon/top.c | 297 ++ src/firemon/tree.c | 36 + src/firemon/usage.c | 77 + src/fshaper/fshaper.sh | 69 + src/ftee/Makefile.in | 24 + src/ftee/ftee.h | 24 + src/ftee/main.c | 228 ++ src/include/common.h | 115 + src/include/libnetlink.h | 163 + src/include/pid.h | 58 + src/lib/Makefile.in | 20 + src/lib/common.c | 192 ++ src/lib/libnetlink.c | 803 +++++ src/lib/pid.c | 392 +++ src/libtrace/Makefile.in | 25 + src/libtrace/libtrace.c | 609 ++++ src/man/firejail-login.txt | 36 + src/man/firejail-profile.txt | 181 ++ src/man/firejail.txt | 1196 ++++++++ src/man/firemon.txt | 107 + src/tools/check-caps.sh | 46 + src/tools/extract_caps.c | 83 + src/tools/extract_syscalls.c | 91 + src/tools/mkcoverit.sh | 45 + src/tools/rvtest.c | 144 + src/tools/ttytest.c | 36 + test/4bridges_arp.exp | 175 ++ test/4bridges_ip.exp | 175 ++ test/auto/autotest.sh | 202 ++ test/caps1.profile | 1 + test/caps2.profile | 1 + test/chk_config.exp | 86 + test/chromium.exp | 72 + test/configure | 42 + test/dns.exp | 69 + test/doubledash.exp | 60 + test/evince.exp | 72 + test/extract_command.exp | 23 + test/firefox.exp | 74 + test/firejail-in-firejail.exp | 37 + test/firemon-arp.exp | 34 + test/firemon-caps.exp | 135 + test/firemon-cgroup.exp | 40 + test/firemon-interface.exp | 34 + test/firemon-route.exp | 32 + test/firemon-seccomp.exp | 45 + test/fs_chroot.exp | 54 + test/fs_dev_shm.exp | 87 + test/fs_home_sanitize.exp | 33 + test/fs_overlay.exp | 64 + test/fs_sys.exp | 34 + test/fs_var_lock.exp | 87 + test/fs_var_tmp.exp | 87 + test/fscheck-bindnoroot.exp | 14 + test/fscheck-blacklist.exp | 14 + test/fscheck-chroot.exp | 77 + test/fscheck-netfilter.exp | 69 + test/fscheck-output.exp | 104 + test/fscheck-private.exp | 77 + test/fscheck-privatekeep.exp | 93 + test/fscheck-profile.exp | 69 + test/fscheck-readonly.exp | 14 + test/fscheck-shell.exp | 69 + test/fscheck-tmpfs.exp | 14 + test/fscheck.sh | 39 + test/login_ssh.exp | 59 + test/midori.exp | 73 + test/name.exp | 25 + test/net_arp.exp | 71 + test/net_badip.exp | 16 + test/net_defaultgw.exp | 65 + test/net_defaultgw2.exp | 65 + test/net_defaultgw3.exp | 17 + test/net_ip.exp | 91 + test/net_local.exp | 49 + test/net_mac.exp | 36 + test/net_macvlan.exp | 88 + test/net_netfilter.exp | 88 + test/net_noip.exp | 41 + test/net_noip2.exp | 41 + test/net_none.exp | 36 + test/netfilter.filter | 6 + test/netfilter.profile | 1 + test/noroot.exp | 124 + test/opera.exp | 72 + test/option-join.exp | 43 + test/option-shutdown.exp | 30 + test/option-trace.exp | 31 + test/option_bind_directory.exp | 26 + test/option_bind_file.exp | 26 + test/option_bind_user.exp | 15 + test/option_blacklist.exp | 35 + test/option_blacklist_file.exp | 26 + test/option_chroot_overlay.exp | 21 + test/option_help.exp | 22 + test/option_list.exp | 48 + test/option_man.exp | 17 + test/option_readonly.exp | 26 + test/option_rlimit.exp | 36 + test/option_tmpfs.exp | 26 + test/option_tree.exp | 60 + test/option_version.exp | 15 + test/output.exp | 66 + test/output.sh | 9 + test/pid.exp | 48 + test/private-keep.exp | 66 + test/private-keep.profile | 1 + test/private.exp | 95 + test/private.profile | 1 + test/private_dir.exp | 53 + test/private_dir_profile.exp | 54 + test/profile_apps.exp | 48 + test/profile_followlnk.exp | 68 + test/profile_noperm.exp | 13 + test/profile_readonly.exp | 64 + test/profile_rlimit.exp | 36 + test/profile_syntax.exp | 69 + test/profile_syntax2.exp | 47 + test/profile_tmpfs.exp | 37 + test/readonly-lnk.profile | 2 + test/readonly.profile | 2 + test/rlimit.profile | 4 + test/seccomp-bad-empty.exp | 38 + test/seccomp-bad-empty.profile | 1 + test/seccomp-bad-empty2.profile | 1 + test/seccomp-chmod-profile.exp | 46 + test/seccomp-chmod.exp | 46 + test/seccomp-chown.exp | 46 + test/seccomp-debug.exp | 32 + test/seccomp-empty.exp | 145 + test/seccomp-empty.profile | 1 + test/seccomp-ptrace.exp | 23 + test/seccomp-su.exp | 34 + test/seccomp-umount.exp | 28 + test/seccomp.profile | 1 + test/servers.exp | 40 + test/servers2.exp | 31 + test/servers3.exp | 31 + test/servers4.exp | 32 + test/shell_csh.exp | 40 + test/shell_dash.exp | 41 + test/shell_zsh.exp | 40 + test/sysrq-trigger.exp | 21 + test/test-nonet.sh | 44 + test/test-root.sh | 56 + test/test.profile | 6 + test/test.rv | 49 + test/test.sh | 329 ++ test/test2.profile | 4 + test/tmpfs.profile | 1 + test/trace.exp | 95 + test/transmission-gtk.exp | 68 + test/transmission-qt.exp | 72 + 246 files changed, 33999 insertions(+) create mode 100644 COPYING create mode 100644 Makefile.in create mode 100644 README create mode 100644 RELNOTES create mode 100755 configure create mode 100644 configure.ac create mode 100644 etc/audacious.profile create mode 100644 etc/chromium-browser.profile create mode 100644 etc/chromium.profile create mode 100644 etc/clementine.profile create mode 100644 etc/deadbeef.profile create mode 100644 etc/deluge.profile create mode 100644 etc/disable-common.inc create mode 100644 etc/disable-mgmt.inc create mode 100644 etc/disable-secret.inc create mode 100644 etc/dropbox.profile create mode 100644 etc/empathy.profile create mode 100644 etc/evince.profile create mode 100644 etc/filezilla.profile create mode 100644 etc/firefox.profile create mode 100644 etc/firejail.bash_completion create mode 100644 etc/firemon.bash_completion create mode 100644 etc/generic.profile create mode 100644 etc/gnome-mplayer.profile create mode 100644 etc/icecat.profile create mode 100644 etc/icedove.profile create mode 100644 etc/iceweasel.profile create mode 100644 etc/login.users create mode 100644 etc/midori.profile create mode 100644 etc/opera.profile create mode 100644 etc/pidgin.profile create mode 100644 etc/qbittorrent.profile create mode 100644 etc/quassel.profile create mode 100644 etc/rhythmbox.profile create mode 100644 etc/server.profile create mode 100644 etc/thunderbird.profile create mode 100644 etc/totem.profile create mode 100644 etc/transmission-gtk.profile create mode 100644 etc/transmission-qt.profile create mode 100644 etc/vlc.profile create mode 100644 etc/xchat.profile create mode 100755 install.sh create mode 100755 mkdeb.sh create mode 100755 mkman.sh create mode 100644 platform/debian/conffiles create mode 100644 platform/debian/control create mode 100644 platform/debian/copyright create mode 100755 platform/rpm/mkrpm.sh create mode 100644 src/firejail/Makefile.in create mode 100644 src/firejail/arg-checking.txt create mode 100644 src/firejail/arp.c create mode 100644 src/firejail/bandwidth.c create mode 100644 src/firejail/caps.c create mode 100644 src/firejail/cgroup.c create mode 100644 src/firejail/cpu.c create mode 100644 src/firejail/firejail.h create mode 100644 src/firejail/fs.c create mode 100644 src/firejail/fs_dev.c create mode 100644 src/firejail/fs_home.c create mode 100644 src/firejail/fs_hostname.c create mode 100644 src/firejail/fs_trace.c create mode 100644 src/firejail/fs_var.c create mode 100644 src/firejail/join.c create mode 100644 src/firejail/list.c create mode 100644 src/firejail/main.c create mode 100644 src/firejail/netfilter.c create mode 100644 src/firejail/network.c create mode 100644 src/firejail/network.txt create mode 100644 src/firejail/network_main.c create mode 100644 src/firejail/output.c create mode 100644 src/firejail/profile.c create mode 100644 src/firejail/restricted_shell.c create mode 100644 src/firejail/rlimit.c create mode 100644 src/firejail/sandbox.c create mode 100644 src/firejail/seccomp.c create mode 100644 src/firejail/shutdown.c create mode 100644 src/firejail/syscall.c create mode 100644 src/firejail/usage.c create mode 100644 src/firejail/util.c create mode 100644 src/firejail/veth.c create mode 100644 src/firemon/Makefile.in create mode 100644 src/firemon/arp.c create mode 100644 src/firemon/caps.c create mode 100644 src/firemon/cgroup.c create mode 100644 src/firemon/cpu.c create mode 100644 src/firemon/firemon.c create mode 100644 src/firemon/firemon.h create mode 100644 src/firemon/interface.c create mode 100644 src/firemon/list.c create mode 100644 src/firemon/netstats.c create mode 100644 src/firemon/procevent.c create mode 100644 src/firemon/route.c create mode 100644 src/firemon/seccomp.c create mode 100644 src/firemon/top.c create mode 100644 src/firemon/tree.c create mode 100644 src/firemon/usage.c create mode 100755 src/fshaper/fshaper.sh create mode 100644 src/ftee/Makefile.in create mode 100644 src/ftee/ftee.h create mode 100644 src/ftee/main.c create mode 100644 src/include/common.h create mode 100644 src/include/libnetlink.h create mode 100644 src/include/pid.h create mode 100644 src/lib/Makefile.in create mode 100644 src/lib/common.c create mode 100644 src/lib/libnetlink.c create mode 100644 src/lib/pid.c create mode 100644 src/libtrace/Makefile.in create mode 100644 src/libtrace/libtrace.c create mode 100644 src/man/firejail-login.txt create mode 100644 src/man/firejail-profile.txt create mode 100644 src/man/firejail.txt create mode 100644 src/man/firemon.txt create mode 100755 src/tools/check-caps.sh create mode 100644 src/tools/extract_caps.c create mode 100644 src/tools/extract_syscalls.c create mode 100755 src/tools/mkcoverit.sh create mode 100644 src/tools/rvtest.c create mode 100644 src/tools/ttytest.c create mode 100755 test/4bridges_arp.exp create mode 100755 test/4bridges_ip.exp create mode 100755 test/auto/autotest.sh create mode 100644 test/caps1.profile create mode 100644 test/caps2.profile create mode 100755 test/chk_config.exp create mode 100755 test/chromium.exp create mode 100755 test/configure create mode 100755 test/dns.exp create mode 100755 test/doubledash.exp create mode 100755 test/evince.exp create mode 100755 test/extract_command.exp create mode 100755 test/firefox.exp create mode 100755 test/firejail-in-firejail.exp create mode 100755 test/firemon-arp.exp create mode 100755 test/firemon-caps.exp create mode 100755 test/firemon-cgroup.exp create mode 100755 test/firemon-interface.exp create mode 100755 test/firemon-route.exp create mode 100755 test/firemon-seccomp.exp create mode 100755 test/fs_chroot.exp create mode 100755 test/fs_dev_shm.exp create mode 100755 test/fs_home_sanitize.exp create mode 100755 test/fs_overlay.exp create mode 100755 test/fs_sys.exp create mode 100755 test/fs_var_lock.exp create mode 100755 test/fs_var_tmp.exp create mode 100755 test/fscheck-bindnoroot.exp create mode 100755 test/fscheck-blacklist.exp create mode 100755 test/fscheck-chroot.exp create mode 100755 test/fscheck-netfilter.exp create mode 100755 test/fscheck-output.exp create mode 100755 test/fscheck-private.exp create mode 100755 test/fscheck-privatekeep.exp create mode 100755 test/fscheck-profile.exp create mode 100755 test/fscheck-readonly.exp create mode 100755 test/fscheck-shell.exp create mode 100755 test/fscheck-tmpfs.exp create mode 100755 test/fscheck.sh create mode 100755 test/login_ssh.exp create mode 100755 test/midori.exp create mode 100755 test/name.exp create mode 100755 test/net_arp.exp create mode 100755 test/net_badip.exp create mode 100755 test/net_defaultgw.exp create mode 100755 test/net_defaultgw2.exp create mode 100755 test/net_defaultgw3.exp create mode 100755 test/net_ip.exp create mode 100755 test/net_local.exp create mode 100755 test/net_mac.exp create mode 100755 test/net_macvlan.exp create mode 100755 test/net_netfilter.exp create mode 100755 test/net_noip.exp create mode 100755 test/net_noip2.exp create mode 100755 test/net_none.exp create mode 100644 test/netfilter.filter create mode 100644 test/netfilter.profile create mode 100755 test/noroot.exp create mode 100755 test/opera.exp create mode 100755 test/option-join.exp create mode 100755 test/option-shutdown.exp create mode 100755 test/option-trace.exp create mode 100755 test/option_bind_directory.exp create mode 100755 test/option_bind_file.exp create mode 100755 test/option_bind_user.exp create mode 100755 test/option_blacklist.exp create mode 100755 test/option_blacklist_file.exp create mode 100755 test/option_chroot_overlay.exp create mode 100755 test/option_help.exp create mode 100755 test/option_list.exp create mode 100755 test/option_man.exp create mode 100755 test/option_readonly.exp create mode 100755 test/option_rlimit.exp create mode 100755 test/option_tmpfs.exp create mode 100755 test/option_tree.exp create mode 100755 test/option_version.exp create mode 100755 test/output.exp create mode 100755 test/output.sh create mode 100755 test/pid.exp create mode 100755 test/private-keep.exp create mode 100644 test/private-keep.profile create mode 100755 test/private.exp create mode 100644 test/private.profile create mode 100755 test/private_dir.exp create mode 100755 test/private_dir_profile.exp create mode 100755 test/profile_apps.exp create mode 100755 test/profile_followlnk.exp create mode 100755 test/profile_noperm.exp create mode 100755 test/profile_readonly.exp create mode 100755 test/profile_rlimit.exp create mode 100755 test/profile_syntax.exp create mode 100755 test/profile_syntax2.exp create mode 100755 test/profile_tmpfs.exp create mode 100644 test/readonly-lnk.profile create mode 100644 test/readonly.profile create mode 100644 test/rlimit.profile create mode 100755 test/seccomp-bad-empty.exp create mode 100644 test/seccomp-bad-empty.profile create mode 100644 test/seccomp-bad-empty2.profile create mode 100755 test/seccomp-chmod-profile.exp create mode 100755 test/seccomp-chmod.exp create mode 100755 test/seccomp-chown.exp create mode 100755 test/seccomp-debug.exp create mode 100755 test/seccomp-empty.exp create mode 100644 test/seccomp-empty.profile create mode 100755 test/seccomp-ptrace.exp create mode 100755 test/seccomp-su.exp create mode 100755 test/seccomp-umount.exp create mode 100644 test/seccomp.profile create mode 100755 test/servers.exp create mode 100755 test/servers2.exp create mode 100755 test/servers3.exp create mode 100755 test/servers4.exp create mode 100755 test/shell_csh.exp create mode 100755 test/shell_dash.exp create mode 100755 test/shell_zsh.exp create mode 100755 test/sysrq-trigger.exp create mode 100755 test/test-nonet.sh create mode 100755 test/test-root.sh create mode 100644 test/test.profile create mode 100644 test/test.rv create mode 100755 test/test.sh create mode 100644 test/test2.profile create mode 100644 test/tmpfs.profile create mode 100755 test/trace.exp create mode 100755 test/transmission-gtk.exp create mode 100755 test/transmission-qt.exp diff --git a/COPYING b/COPYING new file mode 100644 index 00000000000..b6e1c33e049 --- /dev/null +++ b/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 00000000000..6b973952421 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,156 @@ +all: apps firejail.1 firemon.1 firejail-profile.5 firejail-login.5 +MYLIBS = src/lib +APPS = src/firejail src/firemon src/libtrace src/ftee + +datarootdir=@datarootdir@ +PREFIX=@prefix@ +prefix=@prefix@ +VERSION=@PACKAGE_VERSION@ +NAME=@PACKAGE_NAME@ +PACKAGE_TARNAME=@PACKAGE_TARNAME@ +DOCDIR=@docdir@ + + +.PHONY: mylibs $(MYLIBS) +mylibs: $(MYLIBS) +$(MYLIBS): + $(MAKE) -C $@ + +.PHONY: apps $(APPS) +apps: $(APPS) +$(APPS): $(MYLIBS) + $(MAKE) -C $@ + +firemon.1: src/man/firemon.txt + ./mkman.sh $(VERSION) src/man/firemon.txt firemon.1 +firejail.1: src/man/firejail.txt + ./mkman.sh $(VERSION) src/man/firejail.txt firejail.1 +firejail-profile.5: src/man/firejail-profile.txt + ./mkman.sh $(VERSION) src/man/firejail-profile.txt firejail-profile.5 +firejail-login.5: src/man/firejail-login.txt + ./mkman.sh $(VERSION) src/man/firejail-login.txt firejail-login.5 + +clean:; + for dir in $(APPS); do \ + $(MAKE) -C $$dir clean; \ + done + for dir in $(MYLIBS); do \ + $(MAKE) -C $$dir clean; \ + done + rm -f firejail.1 firejail.1.gz firemon.1 firemon.1.gz firejail-profile.5 firejail-profile.5.gz firejail-login.5 firejail-login.5.gz + +distclean: clean + for dir in $(APPS); do \ + $(MAKE) -C $$dir distclean; \ + done + for dir in $(MYLIBS); do \ + $(MAKE) -C $$dir distclean; \ + done + rm -fr Makefile autom4te.cache config.log config.status config.h + +install: all + # firejail executable + strip src/firejail/firejail + mkdir -p $(DESTDIR)/$(PREFIX)/bin + install -c -m 0755 src/firejail/firejail $(DESTDIR)/$(PREFIX)/bin/. + chmod u+s $(DESTDIR)/$(PREFIX)/bin/firejail + # firemon executable + strip src/firemon/firemon + install -c -m 0755 src/firemon/firemon $(DESTDIR)/$(PREFIX)/bin/. + # libraries and plugins + strip src/libtrace/libtrace.so + mkdir -p $(DESTDIR)/$(PREFIX)/lib/firejail + install -c -m 0644 src/libtrace/libtrace.so $(DESTDIR)/$(PREFIX)/lib/firejail/. + strip src/ftee/ftee + install -c -m 0755 src/ftee/ftee $(DESTDIR)/$(PREFIX)/lib/firejail/. + install -c -m 0755 src/fshaper/fshaper.sh $(DESTDIR)/$(PREFIX)/lib/firejail/. + # documents + mkdir -p $(DESTDIR)/$(DOCDIR) + install -c -m 0644 COPYING $(DESTDIR)/$(DOCDIR)/. + install -c -m 0644 README $(DESTDIR)/$(DOCDIR)/. + install -c -m 0644 RELNOTES $(DESTDIR)/$(DOCDIR)/. + # etc files + mkdir -p $(DESTDIR)/etc/firejail + install -c -m 0644 etc/audacious.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/clementine.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/gnome-mplayer.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/rhythmbox.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/totem.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/firefox.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/icedove.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/iceweasel.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/midori.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/evince.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/chromium-browser.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/chromium.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/disable-mgmt.inc $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/disable-secret.inc $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/disable-common.inc $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/dropbox.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/opera.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/thunderbird.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/transmission-gtk.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/transmission-qt.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/vlc.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/deluge.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/qbittorrent.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/generic.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/pidgin.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/xchat.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/empathy.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/server.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/icecat.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/quassel.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/deadbeef.profile $(DESTDIR)/etc/firejail/. + install -c -m 0644 etc/filezilla.profile $(DESTDIR)/etc/firejail/. + bash -c "if [ ! -f /etc/firejail/login.users ]; then install -c -m 0644 etc/login.users $(DESTDIR)/etc/firejail/.; fi;" + # man pages + rm -f firejail.1.gz + gzip -9n firejail.1 + rm -f firemon.1.gz + gzip -9n firemon.1 + rm -f firejail-profile.5.gz + gzip -9n firejail-profile.5 + rm -f firejail-login.5.gz + gzip -9n firejail-login.5 + mkdir -p $(DESTDIR)/$(PREFIX)/share/man/man1 + install -c -m 0644 firejail.1.gz $(DESTDIR)/$(PREFIX)/share/man/man1/. + install -c -m 0644 firemon.1.gz $(DESTDIR)/$(PREFIX)/share/man/man1/. + mkdir -p $(DESTDIR)/$(PREFIX)/share/man/man5 + install -c -m 0644 firejail-profile.5.gz $(DESTDIR)/$(PREFIX)/share/man/man5/. + install -c -m 0644 firejail-login.5.gz $(DESTDIR)/$(PREFIX)/share/man/man5/. + rm -f firejail.1.gz firemon.1.gz firejail-profile.5.gz firejail-login.5.gz + # bash completion + mkdir -p $(DESTDIR)/$(PREFIX)/share/bash-completion/completions + install -c -m 0644 etc/firejail.bash_completion $(DESTDIR)/$(PREFIX)/share/bash-completion/completions/firejail + install -c -m 0644 etc/firemon.bash_completion $(DESTDIR)/$(PREFIX)/share/bash-completion/completions/firemon + +uninstall:; + rm -f $(DESTDIR)/$(PREFIX)/bin/firejail + rm -f $(DESTDIR)/$(PREFIX)/bin/firemon + rm -fr $(DESTDIR)/$(PREFIX)/lib/firejail + rm -fr $(DESTDIR)/$(PREFIX)/share/doc/firejail + rm -f $(DESTDIR)/$(PREFIX)/share/man/man1/firejail.1* + rm -f $(DESTDIR)/$(PREFIX)/share/man/man1/firemon.1* + rm -f $(DESTDIR)/$(PREFIX)/share/man/man5/firejail-profile.5* + rm -f $(DESTDIR)/$(PREFIX)/share/man/man5/firejail-login.5* + rm -f $(DESTDIR)/$(PREFIX)/share/bash-completion/completions/firejail + rm -f $(DESTDIR)/$(PREFIX)/share/bash-completion/completions/firemon + +dist: + make distclean + rm -fr $(NAME)-$(VERSION) $(NAME)-$(VERSION).tar.bz2 + mkdir $(NAME)-$(VERSION) + cd $(NAME)-$(VERSION); cp -a ../src .; cp -a ../etc .; cp -a ../platform .; cp -a ../test .; rm -f src/tools/rvtest; rm -fr src/art; cd .. + cd $(NAME)-$(VERSION); cp -a ../configure .; cp -a ../configure.ac .; cp -a ../Makefile.in .; cp -a ../install.sh .; cp -a ../mkman.sh .; cp -a ../mkdeb.sh .;cd .. + cd $(NAME)-$(VERSION); cp -a ../COPYING .; cp -a ../README .; cp -a ../RELNOTES .; cd .. + cd $(NAME)-$(VERSION); rm -fr `find . -name .svn`; rm -fr $(NAME)-$(VERSION); cd .. + tar -cjvf $(NAME)-$(VERSION).tar.bz2 $(NAME)-$(VERSION) + rm -fr $(NAME)-$(VERSION) + +deb: dist + ./mkdeb.sh $(NAME) $(VERSION) + +extras: all + $(MAKE) -C extras/firetools + \ No newline at end of file diff --git a/README b/README new file mode 100644 index 00000000000..dde1bfcbbe5 --- /dev/null +++ b/README @@ -0,0 +1,28 @@ +Firejail is a SUID sandbox program that reduces the risk of security +breaches by restricting the running environment of untrusted applications +using Linux namespaces and seccomp-bpf. It includes sandbox profiles for +Iceweasel/Mozilla Firefox, Chromium, Midori, Opera, Evince, Transmission, +VLC, Audoacious, Clementine, Rhythmbox, Totem, Deluge and qBittorrent. + +Firejail also expands the restricted shell facility found in bash by adding +Linux namespace support. It supports sandboxing specific users upon login. + +Download: http://sourceforge.net/projects/firejail/files/ +Build and install: ./configure && make && sudo make install +Documentation and support: http://firejail.sourceforge.net +License: GPL v2 + +Firejail Authors: + +netblue30 (netblue30@yahoo.com) +Patrick Toomey (http://sourceforge.net/u/ptoomey/profile/) + - user namespace implementation, ticket 10 +Reiner Herrmann - a number of build patches, man page fixes (tickets 11, 12, 13, 19) +sshirokov (http://sourceforge.net/u/yshirokov/profile/) + - Patch to output "Reading profile" to stderr instead of stdout (ticket 15) +Alexey Kuznetsov, + - src/lib/libnetlink.c extracted from iproute2 software package +G4JC (http://sourceforge.net/u/gaming4jc/profile/) + - ARM support (ticket 17) + +Copyright (C) 2014, 2015 Firejail Authors diff --git a/RELNOTES b/RELNOTES new file mode 100644 index 00000000000..379c8f1c334 --- /dev/null +++ b/RELNOTES @@ -0,0 +1,215 @@ +firejail (0.9.28) baseline; urgency=low + * network scanning, --scan option + * interface MAC address support, --mac option + * IP address range, --iprange option + * traffic shaping, --bandwidth option + * reworked printing of network status at startup + * man pages rework + * added firejail-login man page + * added GNU Icecat, FileZilla, Pidgin, XChat, Empathy, DeaDBeeF default + profiles + * added an /etc/firejail/disable-common.inc file to hold common directory + blacklists + * blacklist Opera and Chrome/Chromium config directories in profile files + * support noroot option for profile files + * enabled noroot in default profile files + * bugfixes + -- netblue30 Sat, 1 Aug 2015 08:00:00 -0500 + +firejail (0.9.26) baseline; urgency=low + * private dev directory + * private.keep option for whitelisting home files in a new private directory + * user namespaces support, noroot option + * added Deluge and qBittorent profiles + * bugfixes + -- netblue30 Thu, 30 Apr 2015 08:00:00 -0500 + + +firejail (0.9.24) baseline; urgency=low + * whitelist and blacklist seccomp filters + * doubledash option + * --shell=none support + * netfilter file support in profile files + * dns server support in profile files + * added --dns.print option + * added default profiles for Audacious, Clementine, Gnome-MPlayer, Rhythmbox and Totem. + * added --caps.drop=all in default profiles + * new syscalls in default seccomp filter: sysfs, sysctl, adjtimex, kcmp + * clock_adjtime, lookup_dcookie, perf_event_open, fanotify_init + * Bugfix: using /proc/sys/kernel/pid_max for the max number of pids + * two build patches from Reiner Herman (tickets 11, 12) + * man page patch from Reiner Herman (ticket 13) + * output patch (ticket 15) from sshirokov + + -- netblue30 Sun, 5 Apr 2015 08:00:00 -0500 + +firejail (0.9.22) baseline; urgency=low + * Replaced --noip option with --ip=none + * Container stdout logging and log rotation + * Added process_vm_readv, process_vm_writev and mknod to + * default seccomp blacklist + * Added CAP_MKNOD to default caps blacklist + * Blacklist and whitelist custom Linux capabilities filters + * macvlan device driver support for --net option + * DNS server support, --dns option + * Netfilter support + * Monitor network statistics, --netstats option + * Added profile for Mozilla Thunderbird/Icedove + * - --overlay support for Linux kernels 3.18+ + * Bugfix: preserve .Xauthority file in private mode (test with ssh -X) + * Bugfix: check uid/gid for cgroup + + -- netblue30 Mon, 9 Mar 2015 09:00:00 -0500 + +firejail (0.9.20) baseline; urgency=low + * utmp, btmp and wtmp enhancements + * create empty /var/log/wtmp and /var/log/btmp files in sandbox + * generate a new /var/run/utmp file in sandbox + * CPU affinity, --cpu option + * Linux control groups support, --cgroup option + * Opera web browser support + * VLC support + * Added "empty" attribute to seccomp command to remove the default + * syscall list form seccomp blacklist + * Added --nogroups option to disable supplementary groups for regular + * users. root user always runs without supplementary groups. + * firemon enhancements + * display the command that started the sandbox + * added --caps option to display capabilities for all sandboxes + * added --cgroup option to display the control groups for all sandboxes + * added --cpu option to display CPU affinity for all sandboxes + * added --seccomp option to display seccomp setting for all sandboxes + * New compile time options: --disable-chroot, --disable-bind + * bugfixes + + -- netblue30 Mon, 02 Feb 2015 08:00:00 -0500 + +firejail (0.9.18) baseline; urgency=low + * Support for tracing system, setuid, setgid, setfsuid, setfsgid syscalls + * Support for tracing setreuid, setregid, setresuid, setresguid syscalls + * Added profiles for transmission-gtk and transmission-qt + * bugfixes + + -- netblue30 Fri, 25 Dec 2014 10:00:00 -0500 + +firejail (0.9.16) baseline; urgency=low + * Configurable private home directory + * Configurable default user shell + * Software configuration support for --docdir and DESTDIR + * Profile file support for include, caps, seccomp and private keywords + * Dropbox profile file + * Linux capabilities and seccomp filters enabled by default for Firefox, + Midori, Evince and Dropbox + * bugfixes + + -- netblue30 Tue, 4 Nov 2014 10:00:00 -0500 + +firejail (0.9.14) baseline; urgency=low + * Linux capabilities and seccomp filters are automatically enabled in + chroot mode (--chroot option) if the sandbox is started as regular user + * Added support for user defined seccomp blacklists + * Added syscall trace support + * Added --tmpfs option + * Added --balcklist option + * Added --read-only option + * Added --bind option + * Logging enhancements + * --overlay option was reactivated + * Added firemon support to print the ARP table for each sandbox + * Added firemon support to print the route table for each sandbox + * Added firemon support to print interface information for each sandbox + * bugfixes + + -- netblue30 Tue, 15 Oct 2014 10:00:00 -0500 + +firejail (0.9.12.2) baseline; urgency=low + * Fix for pulseaudio problems + * --overlay option was temporarily disabled in this build + + -- netblue30 Mon, 29 Sept 2014 07:00:00 -0500 + +firejail (0.9.12.1) baseline; urgency=low + * Fix for pulseaudio problems + * --overlay option was temporarily disabled in this build + + -- netblue30 Mon, 22 Sept 2014 09:00:00 -0500 + +firejail (0.9.12) baseline; urgency=low + * Added capabilities support + * Added support for CentOS 7 + * bugfixes + + -- netblue30 Mon, 15 Sept 2014 10:00:00 -0500 + +firejail (0.9.10) baseline; urgency=low + * Disable /proc/kcore, /proc/kallsyms, /dev/port, /boot + * Fixed --top option CPU utilization calculation + * Implemented --tree option in firejail and firemon + * Implemented --join=name option + * Implemented --shutdown option + * Preserve the current working directory if possible + * Cppcheck and clang errors cleanup + * Added a Chromium web browser profile + + -- netblue30 Thu, 28 Aug 2014 07:00:00 -0500 + +firejail (0.9.8.1) baseline; urgency=low + * FIxed a number of bugs introduced in 0.9.8 + + -- netblue30 Fri, 25 Jul 2014 07:25:00 -0500 + +firejail (0.9.8) baseline; urgency=low + * Implemented nowrap mode for firejail --list command option + * Added --top option in both firejail and firemon + * seccomp filter support + * Added pid support for firemon + * bugfixes + + -- netblue30 Tue, 24 Jul 2014 08:51:00 -0500 + +firejail (0.9.6) baseline; urgency=low + + * Mounting tmpfs on top of /var/log, required by several server programs + * Server fixes for /var/lib and /var/cache + * Private mode fixes + * csh and zsh default shell support + * Chroot mode fixes + * Added support for lighttpd, isc-dhcp-server, apache2, nginx, snmpd, + + -- netblue30 Sat, 7 Jun 2014 09:00:00 -0500 + +firejail (0.9.4) baseline; urgency=low + + * Fixed resolv.conf on Ubuntu systems using DHCP + * Fixed resolv.conf on Debian systems using resolvconf package + * Fixed /var/lock directory + * Fixed /var/tmp directory + * Fixed symbolic links in profile files + * Added profiles for evince, midori + + -- netblue30 Sun, 4 May 2014 08:00:00 -0500 + +firejail (0.9.2) baseline; urgency=low + + * Checking IP address passed with --ip option using ARP; exit if the address + is already present + * Using a lock file during ARP address assignment in order to removed a race + condition. + * Several fixes to --private option; it also mounts a tmpfs filesystem on top + of /tmp + * Added user access check for profile file + * Added --defaultgw option + * Added support of --noip option; it is necessary for DHCP setups + * Added syslog support + * Added support for "tmpfs" and "read-only" profile commands + * Added an expect-based testing framework for the project + * Added bash completion support + * Added support for multiple networks + + -- netblue30 Fri, 25 Apr 2014 08:00:00 -0500 + +firejail (0.9) baseline; urgency=low + + * First beta version + + -- netblue30 Sat, 12 Apr 2014 09:00:00 -0500 diff --git a/configure b/configure new file mode 100755 index 00000000000..50abe97c2b2 --- /dev/null +++ b/configure @@ -0,0 +1,4723 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for firejail 0.9.28. +# +# Report bugs to . +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org and +$0: netblue30@yahoo.com about your system, including any +$0: error possibly output before this message. Then install +$0: a modern shell, or manually run the script under such a +$0: shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='firejail' +PACKAGE_TARNAME='firejail' +PACKAGE_VERSION='0.9.28' +PACKAGE_STRING='firejail 0.9.28' +PACKAGE_BUGREPORT='netblue30@yahoo.com' +PACKAGE_URL='http://firejail.sourceforge.net' + +ac_unique_file="src/firejail/main.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='LTLIBOBJS +LIBOBJS +HAVE_SECCOMP_H +EGREP +GREP +CPP +HAVE_BIND +HAVE_CHROOT +HAVE_SECCOMP +RANLIB +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_seccomp +enable_chroot +enable_bind +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures firejail 0.9.28 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/firejail] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of firejail 0.9.28:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-seccomp Disable seccomp + --disable-chroot Disable chroot + --disable-bind Disable bind + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +firejail home page: . +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +firejail configure 0.9.28 +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} +( $as_echo "## ---------------------------------- ## +## Report this to netblue30@yahoo.com ## +## ---------------------------------- ##" + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by firejail $as_me 0.9.28, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +#AC_CONFIG_HEADERS([config.h]) + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +#AC_PROG_CXX +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + +HAVE_SECCOMP="" +# Check whether --enable-seccomp was given. +if test "${enable_seccomp+set}" = set; then : + enableval=$enable_seccomp; +fi + +if test "x$enable_seccomp" != "xno"; then : + + HAVE_SECCOMP="-DHAVE_SECCOMP" + + +fi + +HAVE_CHROOT="" +# Check whether --enable-chroot was given. +if test "${enable_chroot+set}" = set; then : + enableval=$enable_chroot; +fi + +if test "x$enable_chroot" != "xno"; then : + + HAVE_CHROOT="-DHAVE_CHROOT" + + +fi + +HAVE_BIND="" +# Check whether --enable-bind was given. +if test "${enable_bind+set}" = set; then : + enableval=$enable_bind; +fi + +if test "x$enable_bind" != "xno"; then : + + HAVE_BIND="-DHAVE_BIND" + + +fi + + +# checking pthread library + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lpthread" >&5 +$as_echo_n "checking for main in -lpthread... " >&6; } +if ${ac_cv_lib_pthread_main+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +int +main () +{ +return main (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_pthread_main=yes +else + ac_cv_lib_pthread_main=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_main" >&5 +$as_echo "$ac_cv_lib_pthread_main" >&6; } +if test "x$ac_cv_lib_pthread_main" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBPTHREAD 1 +_ACEOF + + LIBS="-lpthread $LIBS" + +else + as_fn_error $? "*** POSIX thread support not installed ***" "$LINENO" 5 +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +ac_fn_c_check_header_mongrel "$LINENO" "pthread.h" "ac_cv_header_pthread_h" "$ac_includes_default" +if test "x$ac_cv_header_pthread_h" = xyes; then : + +else + as_fn_error $? "*** POSIX thread support not installed ***" "$LINENO" 5 +fi + + +ac_fn_c_check_header_mongrel "$LINENO" "linux/seccomp.h" "ac_cv_header_linux_seccomp_h" "$ac_includes_default" +if test "x$ac_cv_header_linux_seccomp_h" = xyes; then : + HAVE_SECCOMP_H="-DHAVE_SECCOMP_H" +else + HAVE_SECCOMP_H="" +fi + + + + +ac_config_files="$ac_config_files Makefile src/lib/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/ftee/Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by firejail $as_me 0.9.28, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Report bugs to . +firejail home page: ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +firejail config.status 0.9.28 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "src/lib/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib/Makefile" ;; + "src/firejail/Makefile") CONFIG_FILES="$CONFIG_FILES src/firejail/Makefile" ;; + "src/firemon/Makefile") CONFIG_FILES="$CONFIG_FILES src/firemon/Makefile" ;; + "src/libtrace/Makefile") CONFIG_FILES="$CONFIG_FILES src/libtrace/Makefile" ;; + "src/ftee/Makefile") CONFIG_FILES="$CONFIG_FILES src/ftee/Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + + +eval set X " :F $CONFIG_FILES " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + + + + esac + +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + + +echo +echo "Configuration options:" +echo " prefix: $prefix" +echo " seccomp: $HAVE_SECCOMP" +echo " : $HAVE_SECCOMP_H" +echo " chroot: $HAVE_CHROOT" +echo " bind: $HAVE_BIND" +echo diff --git a/configure.ac b/configure.ac new file mode 100644 index 00000000000..9e34aec2093 --- /dev/null +++ b/configure.ac @@ -0,0 +1,52 @@ +AC_PREREQ([2.68]) +AC_INIT(firejail, 0.9.28, netblue30@yahoo.com, , http://firejail.sourceforge.net) +AC_CONFIG_SRCDIR([src/firejail/main.c]) +#AC_CONFIG_HEADERS([config.h]) + + +AC_PROG_CC +#AC_PROG_CXX +AC_PROG_INSTALL +AC_PROG_RANLIB + +HAVE_SECCOMP="" +AC_ARG_ENABLE([seccomp], + AS_HELP_STRING([--disable-seccomp], [Disable seccomp])) +AS_IF([test "x$enable_seccomp" != "xno"], [ + HAVE_SECCOMP="-DHAVE_SECCOMP" + AC_SUBST(HAVE_SECCOMP) +]) + +HAVE_CHROOT="" +AC_ARG_ENABLE([chroot], + AS_HELP_STRING([--disable-chroot], [Disable chroot])) +AS_IF([test "x$enable_chroot" != "xno"], [ + HAVE_CHROOT="-DHAVE_CHROOT" + AC_SUBST(HAVE_CHROOT) +]) + +HAVE_BIND="" +AC_ARG_ENABLE([bind], + AS_HELP_STRING([--disable-bind], [Disable bind])) +AS_IF([test "x$enable_bind" != "xno"], [ + HAVE_BIND="-DHAVE_BIND" + AC_SUBST(HAVE_BIND) +]) + + +# checking pthread library +AC_CHECK_LIB([pthread], [main], [], AC_MSG_ERROR([*** POSIX thread support not installed ***])) +AC_CHECK_HEADER(pthread.h,,AC_MSG_ERROR([*** POSIX thread support not installed ***])) +AC_CHECK_HEADER([linux/seccomp.h], HAVE_SECCOMP_H="-DHAVE_SECCOMP_H", HAVE_SECCOMP_H="") +AC_SUBST(HAVE_SECCOMP_H) + +AC_OUTPUT(Makefile src/lib/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/ftee/Makefile) + +echo +echo "Configuration options:" +echo " prefix: $prefix" +echo " seccomp: $HAVE_SECCOMP" +echo " : $HAVE_SECCOMP_H" +echo " chroot: $HAVE_CHROOT" +echo " bind: $HAVE_BIND" +echo diff --git a/etc/audacious.profile b/etc/audacious.profile new file mode 100644 index 00000000000..23f223a29e8 --- /dev/null +++ b/etc/audacious.profile @@ -0,0 +1,8 @@ +# Audacious profile +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc +caps.drop all +seccomp +noroot + diff --git a/etc/chromium-browser.profile b/etc/chromium-browser.profile new file mode 100644 index 00000000000..4cdc098d195 --- /dev/null +++ b/etc/chromium-browser.profile @@ -0,0 +1,3 @@ +# Chromium browser profile +include /etc/firejail/chromium.profile + diff --git a/etc/chromium.profile b/etc/chromium.profile new file mode 100644 index 00000000000..4f6e7e4506f --- /dev/null +++ b/etc/chromium.profile @@ -0,0 +1,7 @@ +# Chromium browser profile +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc chromium +netfilter + + diff --git a/etc/clementine.profile b/etc/clementine.profile new file mode 100644 index 00000000000..dd855cc62b1 --- /dev/null +++ b/etc/clementine.profile @@ -0,0 +1,7 @@ +# Clementine profile +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc +caps.drop all +seccomp +noroot diff --git a/etc/deadbeef.profile b/etc/deadbeef.profile new file mode 100644 index 00000000000..e2f5787cc9b --- /dev/null +++ b/etc/deadbeef.profile @@ -0,0 +1,8 @@ +# DeaDBeeF profile +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc +caps.drop all +seccomp +noroot + diff --git a/etc/deluge.profile b/etc/deluge.profile new file mode 100644 index 00000000000..138d0a13397 --- /dev/null +++ b/etc/deluge.profile @@ -0,0 +1,9 @@ +# deluge profile +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc +caps.drop all +seccomp +netfilter +noroot + diff --git a/etc/disable-common.inc b/etc/disable-common.inc new file mode 100644 index 00000000000..9260004113b --- /dev/null +++ b/etc/disable-common.inc @@ -0,0 +1,10 @@ +blacklist ${HOME}/.adobe +blacklist ${HOME}/.macromedia +blacklist ${HOME}/.mozilla +blacklist ${HOME}/.icedove +blacklist ${HOME}/.thunderbird +blacklist ${HOME}/.config/midori +blacklist ${HOME}/.config/opera +blacklist ${HOME}/.config/chromium +blacklist ${HOME}/.config/google-chrome +blacklist ${HOME}/.filezilla diff --git a/etc/disable-mgmt.inc b/etc/disable-mgmt.inc new file mode 100644 index 00000000000..f04619ea0d8 --- /dev/null +++ b/etc/disable-mgmt.inc @@ -0,0 +1,12 @@ +# system directories +blacklist /sbin +blacklist /usr/sbin + +# system management +blacklist ${PATH}/umount +blacklist ${PATH}/mount +blacklist ${PATH}/fusermount +blacklist ${PATH}/su +blacklist ${PATH}/sudo +blacklist ${PATH}/xinput +blacklist ${PATH}/strace diff --git a/etc/disable-secret.inc b/etc/disable-secret.inc new file mode 100644 index 00000000000..8ac1b3792f3 --- /dev/null +++ b/etc/disable-secret.inc @@ -0,0 +1,9 @@ +# HOME directory +blacklist ${HOME}/.ssh +tmpfs ${HOME}/.gnome2_private +blacklist ${HOME}/.gnome2/keyrings +blacklist ${HOME}/kde4/share/apps/kwallet +blacklist ${HOME}/kde/share/apps/kwallet +blacklist ${HOME}/.pki/nssdb +blacklist ${HOME}/.gnupg +blacklist ${HOME}/.local/share/recently-used.xbel diff --git a/etc/dropbox.profile b/etc/dropbox.profile new file mode 100644 index 00000000000..82b54adb11b --- /dev/null +++ b/etc/dropbox.profile @@ -0,0 +1,7 @@ +# dropbox profile +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc +caps +seccomp +noroot diff --git a/etc/empathy.profile b/etc/empathy.profile new file mode 100644 index 00000000000..d24cae528f3 --- /dev/null +++ b/etc/empathy.profile @@ -0,0 +1,6 @@ +# Empathy profile +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc +caps.drop all +seccomp diff --git a/etc/evince.profile b/etc/evince.profile new file mode 100644 index 00000000000..4d96d5904f4 --- /dev/null +++ b/etc/evince.profile @@ -0,0 +1,8 @@ +# evince profile +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc +caps.drop all +seccomp +netfilter +noroot diff --git a/etc/filezilla.profile b/etc/filezilla.profile new file mode 100644 index 00000000000..a54b5a734d6 --- /dev/null +++ b/etc/filezilla.profile @@ -0,0 +1,10 @@ +# FileZilla profile +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc .filezilla +caps.drop all +seccomp +noroot +netfilter + + diff --git a/etc/firefox.profile b/etc/firefox.profile new file mode 100644 index 00000000000..dc3489d35f3 --- /dev/null +++ b/etc/firefox.profile @@ -0,0 +1,9 @@ +# Firejail profile for Mozilla Firefox (Iceweasel in Debian) +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc .mozilla +caps.drop all +seccomp +netfilter +noroot + diff --git a/etc/firejail.bash_completion b/etc/firejail.bash_completion new file mode 100644 index 00000000000..50eccf5366e --- /dev/null +++ b/etc/firejail.bash_completion @@ -0,0 +1,86 @@ +# bash completion for firejail -*- shell-script -*- +#******************************************************************** +# Script based on completions/configure script in bash-completion package in +# Debian. The original package is release under GPL v2 license, the webpage is +# http://bash-completion.alioth.debian.org +#******************************************************************* + +__interfaces(){ + cut -f 1 -d ':' /proc/net/dev | tail -n +3 | grep -v lo | xargs +} + + +_firejail() +{ + local cur prev words cword split + _init_completion -s || return + + case $prev in + --help|--version|-debug-caps|--debug-syscalls|--list|--tree|--top|--join|--shutdown) + return 0 + ;; + --profile) + _filedir + return 0 + ;; + --chroot) + _filedir -d + return 0 + ;; + --cgroup) + _filedir -d + return 0 + ;; + --tmpfs) + _filedir + return 0 + ;; + --blacklist) + _filedir + return 0 + ;; + --read-only) + _filedir + return 0 + ;; + --bind) + _filedir + return 0 + ;; + --private) + _filedir + return 0 + ;; + --shell) + _filedir + return 0 + ;; + --net) + comps=$(__interfaces) + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 + ;; + esac + + $split && return 0 + + # if $COMP_CONFIGURE_HINTS is not null, then completions of the form + # --option=SETTING will include 'SETTING' as a contextual hint + [[ "$cur" != -* ]] && _filedir && return 0 + + if [[ -n $COMP_CONFIGURE_HINTS ]]; then + COMPREPLY=( $( compgen -W "$( $1 --help 2>&1 | \ + awk '/^ --[A-Za-z]/ { print $1; \ + if ($2 ~ /--[A-Za-z]/) print $2 }' | sed -e 's/[[,].*//g' )" \ + -- "$cur" ) ) + [[ $COMPREPLY == *=* ]] && compopt -o nospace + else + COMPREPLY=( $( compgen -W '$( _parse_help "$1" )' -- "$cur" ) ) + [[ $COMPREPLY == *= ]] && compopt -o nospace + fi + +} && +complete -F _firejail firejail + + + diff --git a/etc/firemon.bash_completion b/etc/firemon.bash_completion new file mode 100644 index 00000000000..befbf23880a --- /dev/null +++ b/etc/firemon.bash_completion @@ -0,0 +1,39 @@ +# bash completion for firemon -*- shell-script -*- +#******************************************************************** +# Script based on completions/configure script in bash-completion package in +# Debian. The original package is release under GPL v2 license, the webpage is +# http://bash-completion.alioth.debian.org +#******************************************************************* + +_firemon() +{ + local cur prev words cword split + _init_completion -s || return + + case $prev in + --help|--version) + return + ;; + esac + + $split && return 0 + + # if $COMP_CONFIGURE_HINTS is not null, then completions of the form + # --option=SETTING will include 'SETTING' as a contextual hint + [[ "$cur" != -* ]] && return 0 + + if [[ -n $COMP_CONFIGURE_HINTS ]]; then + COMPREPLY=( $( compgen -W "$( $1 --help 2>&1 | \ + awk '/^ --[A-Za-z]/ { print $1; \ + if ($2 ~ /--[A-Za-z]/) print $2 }' | sed -e 's/[[,].*//g' )" \ + -- "$cur" ) ) + [[ $COMPREPLY == *=* ]] && compopt -o nospace + else + COMPREPLY=( $( compgen -W '$( _parse_help "$1" )' -- "$cur" ) ) + [[ $COMPREPLY == *= ]] && compopt -o nospace + fi +} && +complete -F _firemon firemon + + + diff --git a/etc/generic.profile b/etc/generic.profile new file mode 100644 index 00000000000..83bf59e0a53 --- /dev/null +++ b/etc/generic.profile @@ -0,0 +1,41 @@ +################################ +# Generic profile based on Firefox profile +################################ +#include /etc/firejail/disable-mgmt.inc +# system directories +blacklist /sbin +blacklist /usr/sbin +# system management +blacklist ${PATH}/umount +blacklist ${PATH}/mount +blacklist ${PATH}/fusermount +blacklist ${PATH}/su +blacklist ${PATH}/sudo +blacklist ${PATH}/xinput +blacklist ${PATH}/strace + +#include /etc/firejail/disable-secret.inc +# HOME directory +blacklist ${HOME}/.ssh +tmpfs ${HOME}/.gnome2_private +blacklist ${HOME}/.gnome2/keyrings +blacklist ${HOME}/kde4/share/apps/kwallet +blacklist ${HOME}/kde/share/apps/kwallet +blacklist ${HOME}/.pki/nssdb +blacklist ${HOME}/.gnupg +blacklist ${HOME}/.local/share/recently-used.xbel + +blacklist ${HOME}/.adobe +blacklist ${HOME}/.macromedia +blacklist ${HOME}/.mozilla +blacklist ${HOME}/.icedove +blacklist ${HOME}/.thunderbird +blacklist ${HOME}/.config/opera +blacklist ${HOME}/.config/chromium +blacklist ${HOME}/.config/google-chrome + +caps.drop all +seccomp +netfilter +noroot + diff --git a/etc/gnome-mplayer.profile b/etc/gnome-mplayer.profile new file mode 100644 index 00000000000..b69cf3a57d4 --- /dev/null +++ b/etc/gnome-mplayer.profile @@ -0,0 +1,7 @@ +# GNOME MPlayer profile +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc +caps.drop all +seccomp +noroot diff --git a/etc/icecat.profile b/etc/icecat.profile new file mode 100644 index 00000000000..25d426ad2f2 --- /dev/null +++ b/etc/icecat.profile @@ -0,0 +1,2 @@ +# Firejail profile for GNU Icecat +include /etc/firejail/firefox.profile diff --git a/etc/icedove.profile b/etc/icedove.profile new file mode 100644 index 00000000000..057e0c9efd5 --- /dev/null +++ b/etc/icedove.profile @@ -0,0 +1,3 @@ +# Firejail profile for Mozilla Thunderbird (Icedove in Debian) +include /etc/firejail/thunderbird.profile + diff --git a/etc/iceweasel.profile b/etc/iceweasel.profile new file mode 100644 index 00000000000..e9b32846aa3 --- /dev/null +++ b/etc/iceweasel.profile @@ -0,0 +1,2 @@ +# Firejail profile for Mozilla Firefox (Iceweasel in Debian) +include /etc/firejail/firefox.profile diff --git a/etc/login.users b/etc/login.users new file mode 100644 index 00000000000..5d596909135 --- /dev/null +++ b/etc/login.users @@ -0,0 +1,14 @@ +# /etc/firejail/login.users - restricted user shell configuration +# +# Each user entry consists of a user name and firejail +# program arguments: +# +# user name: arguments +# +# For example: +# +# netblue:--debug --net=none +# +# The extra arguments are inserted into program command line if firejail +# was started as a login shell. + diff --git a/etc/midori.profile b/etc/midori.profile new file mode 100644 index 00000000000..5479ba17207 --- /dev/null +++ b/etc/midori.profile @@ -0,0 +1,9 @@ +# Midory browser profile +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc midori +caps.drop all +seccomp +netfilter +noroot + diff --git a/etc/opera.profile b/etc/opera.profile new file mode 100644 index 00000000000..852f10719ef --- /dev/null +++ b/etc/opera.profile @@ -0,0 +1,8 @@ +# Chromium browser profile +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc opera +netfilter +noroot + + diff --git a/etc/pidgin.profile b/etc/pidgin.profile new file mode 100644 index 00000000000..6f559491925 --- /dev/null +++ b/etc/pidgin.profile @@ -0,0 +1,7 @@ +# Pidgin profile +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc +caps.drop all +seccomp +noroot diff --git a/etc/qbittorrent.profile b/etc/qbittorrent.profile new file mode 100644 index 00000000000..f85dfc994cb --- /dev/null +++ b/etc/qbittorrent.profile @@ -0,0 +1,9 @@ +# abittorrent profile +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc +caps.drop all +seccomp +netfilter +noroot + diff --git a/etc/quassel.profile b/etc/quassel.profile new file mode 100644 index 00000000000..a2057ad01c5 --- /dev/null +++ b/etc/quassel.profile @@ -0,0 +1,7 @@ +# Quassel IRC profile +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc +caps.drop all +seccomp +noroot diff --git a/etc/rhythmbox.profile b/etc/rhythmbox.profile new file mode 100644 index 00000000000..42d4dc0fa47 --- /dev/null +++ b/etc/rhythmbox.profile @@ -0,0 +1,7 @@ +# Rhythmbox profile +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc +caps.drop all +seccomp +noroot diff --git a/etc/server.profile b/etc/server.profile new file mode 100644 index 00000000000..bb15774fa26 --- /dev/null +++ b/etc/server.profile @@ -0,0 +1,6 @@ +# generic server profile +include /etc/firejail/disable-mgmt.inc sbin +private +private-dev +seccomp + diff --git a/etc/thunderbird.profile b/etc/thunderbird.profile new file mode 100644 index 00000000000..8b63a6ec55e --- /dev/null +++ b/etc/thunderbird.profile @@ -0,0 +1,9 @@ +# Firejail profile for Mozilla Thunderbird (Icedove in Debian) +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc thunderbird icedove +caps.drop all +seccomp +netfilter +noroot + diff --git a/etc/totem.profile b/etc/totem.profile new file mode 100644 index 00000000000..50115deb530 --- /dev/null +++ b/etc/totem.profile @@ -0,0 +1,7 @@ +# Totem profile +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc +caps.drop all +seccomp +noroot diff --git a/etc/transmission-gtk.profile b/etc/transmission-gtk.profile new file mode 100644 index 00000000000..9ccece2850a --- /dev/null +++ b/etc/transmission-gtk.profile @@ -0,0 +1,9 @@ +# transmission-gtk profile +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc +caps.drop all +seccomp +netfilter +noroot + diff --git a/etc/transmission-qt.profile b/etc/transmission-qt.profile new file mode 100644 index 00000000000..65a045f8e41 --- /dev/null +++ b/etc/transmission-qt.profile @@ -0,0 +1,9 @@ +# transmission-qt profile +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc +caps.drop all +seccomp +netfilter +noroot + diff --git a/etc/vlc.profile b/etc/vlc.profile new file mode 100644 index 00000000000..76e1395f90a --- /dev/null +++ b/etc/vlc.profile @@ -0,0 +1,7 @@ +# VLC profile +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc +caps.drop all +seccomp +noroot diff --git a/etc/xchat.profile b/etc/xchat.profile new file mode 100644 index 00000000000..b8d8cb1e214 --- /dev/null +++ b/etc/xchat.profile @@ -0,0 +1,7 @@ +# XChat profile +include /etc/firejail/disable-mgmt.inc +include /etc/firejail/disable-secret.inc +include /etc/firejail/disable-common.inc +caps.drop all +seccomp +noroot diff --git a/install.sh b/install.sh new file mode 100755 index 00000000000..b3ddf0423c4 --- /dev/null +++ b/install.sh @@ -0,0 +1,2 @@ +#!/bin/bash +echo "installing..." diff --git a/mkdeb.sh b/mkdeb.sh new file mode 100755 index 00000000000..15964997549 --- /dev/null +++ b/mkdeb.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +# a code archive should already be available + +TOP=`pwd` +CODE_ARCHIVE="$1-$2.tar.bz2" +CODE_DIR="$1-$2" +INSTALL_DIR=$TOP +INSTALL_DIR+="/debian/usr" +DEBIAN_CTRL_DIR=$TOP +DEBIAN_CTRL_DIR+="/debian/DEBIAN" + +echo "*****************************************" +echo "code archive: $CODE_ARCHIVE" +echo "code directory: $CODE_DIR" +echo "install directory: $INSTALL_DIR" +echo "debian control directory: $DEBIAN_CTRL_DIR" +echo "*****************************************" +tar -xjvf $CODE_ARCHIVE +mkdir -p $INSTALL_DIR +cd $CODE_DIR +./configure --prefix=$INSTALL_DIR +make && make install + +# second compilation - the path to libtrace.so is hardcoded in firejail executable +# pointing according to --prefix=$INSTALL_DIR. We need it to point to /usr/lib +make distclean +./configure --prefix=/usr +make +# install firejail executable in $TOP/$INSTALL_DIR +strip src/firejail/firejail +install -c -m 0755 src/firejail/firejail $INSTALL_DIR/bin/. +chmod u+s $INSTALL_DIR/bin/firejail + + +cd .. +echo "*****************************************" +SIZE=`du -s debian/usr` +echo "install size $SIZE" +echo "*****************************************" + +mv $INSTALL_DIR/share/doc/firejail/RELNOTES $INSTALL_DIR/share/doc/firejail/changelog.Debian +gzip -9 $INSTALL_DIR/share/doc/firejail/changelog.Debian +rm $INSTALL_DIR/share/doc/firejail/COPYING +cp platform/debian/copyright $INSTALL_DIR/share/doc/firejail/. +mkdir -p $DEBIAN_CTRL_DIR +sed "s/FIREJAILVER/$2/g" platform/debian/control > $DEBIAN_CTRL_DIR/control +mkdir -p debian/etc/firejail +cp etc/chromium.profile debian/etc/firejail/. +cp etc/chromium-browser.profile debian/etc/firejail/. +cp etc/disable-mgmt.inc debian/etc/firejail/. +cp etc/disable-secret.inc debian/etc/firejail/. +cp etc/dropbox.profile debian/etc/firejail/. +cp etc/evince.profile debian/etc/firejail/. +cp etc/firefox.profile debian/etc/firejail/. +cp etc/iceweasel.profile debian/etc/firejail/. +cp etc/icedove.profile debian/etc/firejail/. +cp etc/login* debian/etc/firejail/. +cp etc/midori.profile debian/etc/firejail/. +cp etc/opera.profile debian/etc/firejail/. +cp etc/thunderbird.profile debian/etc/firejail/. +cp etc/transmission-gtk.profile debian/etc/firejail/. +cp etc/transmission-qt.profile debian/etc/firejail/. +cp etc/vlc.profile debian/etc/firejail/. +cp etc/audacious.profile debian/etc/firejail/. +cp etc/clementine.profile debian/etc/firejail/. +cp etc/gnome-mplayer.profile debian/etc/firejail/. +cp etc/rhythmbox.profile debian/etc/firejail/. +cp etc/totem.profile debian/etc/firejail/. +cp etc/deluge.profile debian/etc/firejail/. +cp etc/qbittorrent.profile debian/etc/firejail/. +cp etc/generic.profile debian/etc/firejail/. +cp etc/xchat.profile debian/etc/firejail/. +cp etc/server.profile debian/etc/firejail/. +cp etc/quassel.profile debian/etc/firejail/. +cp etc/pidgin.profile debian/etc/firejail/. +cp etc/filezilla.profile debian/etc/firejail/. +cp etc/empathy.profile debian/etc/firejail/. +cp etc/disable-common.inc debian/etc/firejail/. +cp etc/deadbeef.profile debian/etc/firejail/. +cp etc/icecat.profile debian/etc/firejail/. +cp platform/debian/conffiles $DEBIAN_CTRL_DIR/. +find ./debian -type d | xargs chmod 755 +dpkg-deb --build debian +lintian debian.deb +mv debian.deb firejail_$2_1_amd64.deb +echo "if building a 32bit package, rename the deb file manually" +rm -fr debian +rm -fr $CODE_DIR + + + + + + + diff --git a/mkman.sh b/mkman.sh new file mode 100755 index 00000000000..f2a5ef3c6ad --- /dev/null +++ b/mkman.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +sed "s/VERSION/$1/g" $2 > $3 +MONTH=`date +%b` +sed -i "s/MONTH/$MONTH/g" $3 +YEAR=`date +%Y` +sed -i "s/YEAR/$YEAR/g" $3 diff --git a/platform/debian/conffiles b/platform/debian/conffiles new file mode 100644 index 00000000000..6f55cc0215e --- /dev/null +++ b/platform/debian/conffiles @@ -0,0 +1,33 @@ +/etc/firejail/evince.profile +/etc/firejail/disable-secret.inc +/etc/firejail/chromium.profile +/etc/firejail/midori.profile +/etc/firejail/icedove.profile +/etc/firejail/iceweasel.profile +/etc/firejail/dropbox.profile +/etc/firejail/login.users +/etc/firejail/chromium-browser.profile +/etc/firejail/disable-mgmt.inc +/etc/firejail/firefox.profile +/etc/firejail/opera.profile +/etc/firejail/thunderbird.profile +/etc/firejail/transmission-gtk.profile +/etc/firejail/transmission-qt.profile +/etc/firejail/vlc.profile +/etc/firejail/audacious.profile +/etc/firejail/clementine.profile +/etc/firejail/gnome-mplayer.profile +/etc/firejail/rhythmbox.profile +/etc/firejail/totem.profile +/etc/firejail/deluge.profile +/etc/firejail/qbittorrent.profile +/etc/firejail/generic.profile +/etc/firejail/xchat.profile +/etc/firejail/server.profile +/etc/firejail/quassel.profile +/etc/firejail/pidgin.profile +/etc/firejail/filezilla.profile +/etc/firejail/empathy.profile +/etc/firejail/disable-common.inc +/etc/firejail/deadbeef.profile +/etc/firejail/icecat.profile diff --git a/platform/debian/control b/platform/debian/control new file mode 100644 index 00000000000..18d857c36a2 --- /dev/null +++ b/platform/debian/control @@ -0,0 +1,20 @@ +Package: firejail +Version: FIREJAILVER-1 +Architecture: amd64 +Maintainer: netblue30 +Installed-Size: 272 +Depends: libc6 +Section: admin +Priority: extra +Homepage: http://firejail.sourceforge.net +Description: Linux namepaces sandbox program. + Firejail is a SUID sandbox program that reduces the risk of security + breaches by restricting the running environment of untrusted applications + using Linux namespaces and seccmp-bpf. It includes sandbox profiles for + Iceweasel/Mozilla Firefox, Chromium, Midori, Opera, Evince, Transmission + and VLC. + . + Firejail also expands the restricted shell facility found in bash by + adding Linux namespace support. It also supports sandboxing SSH users + upon login. + diff --git a/platform/debian/copyright b/platform/debian/copyright new file mode 100644 index 00000000000..7d8d0a2c775 --- /dev/null +++ b/platform/debian/copyright @@ -0,0 +1,30 @@ + +This is the Debian/Ubuntu prepackaged version of firejail. + + Firejail is a sandbox program that reduces the risk of security breaches + by restricting the running environment of untrusted applications using + Linux namespaces. It currently implements hostname, filesystem, PID, IPC + and networking stack isolation, and it runs on any recent Linux system. It + includes a sandbox profile for Mozilla Firefox. + + Copyright (C) 2014,2015 Firejail Authors (see README file for more details) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., 51 + Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + +The complete text of the GNU General Public License can be found +in /usr/share/common-licenses/GPL-2. + +Homepage: http://firejail.sourceforge.net. + diff --git a/platform/rpm/mkrpm.sh b/platform/rpm/mkrpm.sh new file mode 100755 index 00000000000..adac1de469f --- /dev/null +++ b/platform/rpm/mkrpm.sh @@ -0,0 +1,256 @@ +#!/bin/bash +VERSION="0.9.26" +rm -fr ~/rpmbuild +rm -f firejail-$VERSION-1.x86_64.rpm + +mkdir -p ~/rpmbuild/{RPMS,SRPMS,BUILD,SOURCES,SPECS,tmp} +cat <~/.rpmmacros +%_topdir %(echo $HOME)/rpmbuild +%_tmppath %{_topdir}/tmp +EOF + +cd ~/rpmbuild +echo "building directory tree" + +mkdir -p firejail-$VERSION/usr/bin +install -m 755 /usr/bin/firejail firejail-$VERSION/usr/bin/. +install -m 755 /usr/bin/firemon firejail-$VERSION/usr/bin/. + +mkdir -p firejail-$VERSION/usr/lib/firejail +install -m 644 /usr/lib/firejail/libtrace.so firejail-$VERSION/usr/lib/firejail/. +install -m 755 /usr/lib/firejail/ftee firejail-$VERSION/usr/lib/firejail/. + +mkdir -p firejail-$VERSION/usr/share/man/man1 +install -m 644 /usr/share/man/man1/firejail.1.gz firejail-$VERSION/usr/share/man/man1/. +install -m 644 /usr/share/man/man1/firemon.1.gz firejail-$VERSION/usr/share/man/man1/. + +mkdir -p firejail-$VERSION/usr/share/man/man5 +install -m 644 /usr/share/man/man5/firejail-profile.5.gz firejail-$VERSION/usr/share/man/man5/. + +mkdir -p firejail-$VERSION/usr/share/doc/packages/firejail +install -m 644 /usr/share/doc/firejail/COPYING firejail-$VERSION/usr/share/doc/packages/firejail/. +install -m 644 /usr/share/doc/firejail/README firejail-$VERSION/usr/share/doc/packages/firejail/. +install -m 644 /usr/share/doc/firejail/RELNOTES firejail-$VERSION/usr/share/doc/packages/firejail/. + +mkdir -p firejail-$VERSION/etc/firejail +install -m 644 /etc/firejail/chromium-browser.profile firejail-$VERSION/etc/firejail/chromium-browser.profile +install -m 644 /etc/firejail/chromium.profile firejail-$VERSION/etc/firejail/chromium.profile +install -m 644 /etc/firejail/dropbox.profile firejail-$VERSION/etc/firejail/dropbox.profile +install -m 644 /etc/firejail/disable-secret.inc firejail-$VERSION/etc/firejail/disable-secret.inc +install -m 644 /etc/firejail/disable-mgmt.inc firejail-$VERSION/etc/firejail/disable-mgmt.inc +install -m 644 /etc/firejail/evince.profile firejail-$VERSION/etc/firejail/evince.profile +install -m 644 /etc/firejail/firefox.profile firejail-$VERSION/etc/firejail/firefox.profile +install -m 644 /etc/firejail/icedove.profile firejail-$VERSION/etc/firejail/icedove.profile +install -m 644 /etc/firejail/iceweasel.profile firejail-$VERSION/etc/firejail/iceweasel.profile +install -m 644 /etc/firejail/midori.profile firejail-$VERSION/etc/firejail/midori.profile +install -m 644 /etc/firejail/thunderbird.profile firejail-$VERSION/etc/firejail/thunderbird.profile +install -m 644 /etc/firejail/opera.profile firejail-$VERSION/etc/firejail/opera.profile +install -m 644 /etc/firejail/transmission-gtk.profile firejail-$VERSION/etc/firejail/transmission-gtk.profile +install -m 644 /etc/firejail/transmission-qt.profile firejail-$VERSION/etc/firejail/transmission-qt.profile +install -m 644 /etc/firejail/vlc.profile firejail-$VERSION/etc/firejail/vlc.profile +install -m 644 /etc/firejail/audacious.profile firejail-$VERSION/etc/firejail/audacious.profile +install -m 644 /etc/firejail/clementine.profile firejail-$VERSION/etc/firejail/clementine.profile +install -m 644 /etc/firejail/gnome-mplayer.profile firejail-$VERSION/etc/firejail/gnome-mplayer.profile +install -m 644 /etc/firejail/rhythmbox.profile firejail-$VERSION/etc/firejail/rhythmbox.profile +install -m 644 /etc/firejail/totem.profile firejail-$VERSION/etc/firejail/totem.profile +install -m 644 /etc/firejail/deluge.profile firejail-$VERSION/etc/firejail/deluge.profile +install -m 644 /etc/firejail/qbittorrent.profile firejail-$VERSION/etc/firejail/qbittorrent.profile +install -m 644 /etc/firejail/generic.profile firejail-$VERSION/etc/firejail/generic.profile +install -m 644 /etc/firejail/login.users firejail-$VERSION/etc/firejail/login.users + +mkdir -p firejail-$VERSION/usr/share/bash-completion/completions +install -m 644 /usr/share/bash-completion/completions/firejail firejail-$VERSION/usr/share/bash-completion/completions/. + +echo "building tar.gz archive" +tar -czvf firejail-$VERSION.tar.gz firejail-$VERSION + +cp firejail-$VERSION.tar.gz SOURCES/. + +echo "building config spec" +cat < SPECS/firejail.spec +%define __spec_install_post %{nil} +%define debug_package %{nil} +%define __os_install_post %{_dbpath}/brp-compress + +Summary: Linux namepaces sandbox program +Name: firejail +Version: $VERSION +Release: 1 +License: GPL+ +Group: Development/Tools +SOURCE0 : %{name}-%{version}.tar.gz +URL: http://firejail.sourceforege.net + +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root + +%description +Firejail is a SUID sandbox program that reduces the risk of security +breaches by restricting the running environment of untrusted applications +using Linux namespaces. It includes a sandbox profile for Mozilla Firefox. + +%prep +%setup -q + +%build + +%install +rm -rf %{buildroot} +mkdir -p %{buildroot} + +cp -a * %{buildroot} + + +%clean +rm -rf %{buildroot} + + +%files +%defattr(-,root,root,-) +%config(noreplace) %{_sysconfdir}/%{name}/chromium-browser.profile +%config(noreplace) %{_sysconfdir}/%{name}/chromium.profile +%config(noreplace) %{_sysconfdir}/%{name}/disable-mgmt.inc +%config(noreplace) %{_sysconfdir}/%{name}/disable-secret.inc +%config(noreplace) %{_sysconfdir}/%{name}/dropbox.profile +%config(noreplace) %{_sysconfdir}/%{name}/evince.profile +%config(noreplace) %{_sysconfdir}/%{name}/firefox.profile +%config(noreplace) %{_sysconfdir}/%{name}/icedove.profile +%config(noreplace) %{_sysconfdir}/%{name}/iceweasel.profile +%config(noreplace) %{_sysconfdir}/%{name}/login.users +%config(noreplace) %{_sysconfdir}/%{name}/midori.profile +%config(noreplace) %{_sysconfdir}/%{name}/opera.profile +%config(noreplace) %{_sysconfdir}/%{name}/thunderbird.profile +%config(noreplace) %{_sysconfdir}/%{name}/transmission-gtk.profile +%config(noreplace) %{_sysconfdir}/%{name}/transmission-qt.profile +%config(noreplace) %{_sysconfdir}/%{name}/vlc.profile +%config(noreplace) %{_sysconfdir}/%{name}/audacious.profile +%config(noreplace) %{_sysconfdir}/%{name}/clementine.profile +%config(noreplace) %{_sysconfdir}/%{name}/gnome-mplayer.profile +%config(noreplace) %{_sysconfdir}/%{name}/rhythmbox.profile +%config(noreplace) %{_sysconfdir}/%{name}/totem.profile +%config(noreplace) %{_sysconfdir}/%{name}/deluge.profile +%config(noreplace) %{_sysconfdir}/%{name}/qbittorrent.profile +%config(noreplace) %{_sysconfdir}/%{name}/generic.profile + +/usr/bin/firejail +/usr/bin/firemon +/usr/lib/firejail/libtrace.so +/usr/lib/firejail/ftee +/usr/share/doc/packages/firejail/COPYING +/usr/share/doc/packages/firejail/README +/usr/share/doc/packages/firejail/RELNOTES +/usr/share/man/man1/firejail.1.gz +/usr/share/man/man1/firemon.1.gz +/usr/share/man/man5/firejail-profile.5.gz +/usr/share/bash-completion/completions/firejail + +%post +chmod u+s /usr/bin/firejail + +%changelog +* Thu Apr 30 2015 netblue30 0.9.26-1 + - private dev directory + - private.keep option for whitelisting home files in a new private directory + - user namespaces support, noroot option + - added Deluge and qBittorent profiles + - bugfixes + +* Sun Apr 5 2015 netblue30 0.9.24-1 + - whitelist and blacklist seccomp filters + - doubledash option + - --shell=none support + - netfilter file support in profile files + - dns server support in profile files + - added --dns.print option + - added default profiles for Audoacious, Clementine, Rhythmbox and Totem. + - added --caps.drop=all in default profiles + - new syscalls in default seccomp filter: sysfs, sysctl, adjtimex, kcmp + - clock_adjtime, lookup_dcookie, perf_event_open, fanotify_init + - Bugfix: using /proc/sys/kernel/pid_max for the max number of pids + - two build patches from Reiner Herman (tickets 11, 12) + - man page patch from Reiner Herman (ticket 13) + - output patch (ticket 15) from sshirokov + +* Mon Mar 9 2015 netblue30 0.9.22-1 + - Replaced --noip option with --ip=none + - Container stdout logging and log rotation + - Added process_vm_readv, process_vm_writev and mknod to + default seccomp blacklist + - Added CAP_MKNOD to default caps blacklist + - Blacklist and whitelist custom Linux capabilities filters + - macvlan device driver support for --net option + - DNS server support, --dns option + - Netfilter support + - Monitor network statistics, --netstats option + - Added profile for Mozilla Thunderbird/Icedove + - --overlay support for Linux kernels 3.18+ + - Bugfix: preserve .Xauthority file in private mode (test with ssh -X) + - Bugfix: check uid/gid for cgroup + +* Fri Feb 6 2015 netblue30 0.9.20-1 + - utmp, btmp and wtmp enhancements + - create empty /var/log/wtmp and /var/log/btmp files in sandbox + - generate a new /var/run/utmp file in sandbox + - CPU affinity, --cpu option + - Linux control groups support, --cgroup option + - Opera web browser support + - VLC support + - Added "empty" attribute to seccomp command to remove the default + - syscall list form seccomp blacklist + - Added --nogroups option to disable supplementary groups for regular + - users. root user always runs without supplementary groups. + - firemon enhancements + - display the command that started the sandbox + - added --caps option to display capabilities for all sandboxes + - added --cgroup option to display the control groups for all sandboxes + - added --cpu option to display CPU affinity for all sandboxes + - added --seccomp option to display seccomp setting for all sandboxes + - New compile time options: --disable-chroot, --disable-bind + - bugfixes + +* Sat Dec 27 2014 netblue30 0.9.18-1 + - Support for tracing system, setuid, setgid, setfsuid, setfsgid syscalls + - Support for tracing setreuid, setregid, setresuid, setresguid syscalls + - Added profiles for transmission-gtk and transmission-qt + - bugfixes + +* Tue Nov 4 2014 netblue30 0.9.16-1 + - Configurable private home directory + - Configurable default user shell + - Software configuration support for --docdir and DESTDIR + - Profile file support for include, caps, seccomp and private keywords + - Dropbox profile file + - Linux capabilities and seccomp filters enabled by default for Firefox, + Midori, Evince and Dropbox + - bugfixes + +* Wed Oct 8 2014 netblue30 0.9.14-1 + - Linux capabilities and seccomp filters are automatically enabled in + chroot mode (--chroot option) if the sandbox is started as regular + user + - Added support for user defined seccomp blacklists + - Added syscall trace support + - Added --tmpfs option + - Added --balcklist option + - Added --read-only option + - Added --bind option + - Logging enhancements + - --overlay option was reactivated + - Added firemon support to print the ARP table for each sandbox + - Added firemon support to print the route table for each sandbox + - Added firemon support to print interface information for each sandbox + - bugfixes + +* Tue Sep 16 2014 netblue30 0.9.12-1 + - Added capabilities support + - Added support for CentOS 7 + - bugfixes + +EOF + +echo "building rpm" +rpmbuild -ba SPECS/firejail.spec +rpm -qpl RPMS/x86_64/firejail-$VERSION-1.x86_64.rpm +cd .. +rm -f firejail-$VERSION-1.x86_64.rpm +cp rpmbuild/RPMS/x86_64/firejail-$VERSION-1.x86_64.rpm . + diff --git a/src/firejail/Makefile.in b/src/firejail/Makefile.in new file mode 100644 index 00000000000..1f7b563c45c --- /dev/null +++ b/src/firejail/Makefile.in @@ -0,0 +1,28 @@ +all: firejail + +PREFIX=@prefix@ +VERSION=@PACKAGE_VERSION@ +NAME=@PACKAGE_NAME@ +HAVE_SECCOMP_H=@HAVE_SECCOMP_H@ +HAVE_SECCOMP=@HAVE_SECCOMP@ +HAVE_CHROOT=@HAVE_CHROOT@ +HAVE_BIND=@HAVE_BIND@ + +H_FILE_LIST = $(wildcard *.[h]) +C_FILE_LIST = $(wildcard *.c) +OBJS = $(C_FILE_LIST:.c=.o) +BINOBJS = $(foreach file, $(OBJS), $file) +CFLAGS += -ggdb -O2 -DVERSION='"$(VERSION)"' -DPREFIX='"$(PREFIX)"' $(HAVE_SECCOMP) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_BIND) -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security +LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread + +%.o : %.c $(H_FILE_LIST) + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +firejail: $(OBJS) ../lib/libnetlink.o ../lib/common.o + $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/libnetlink.o ../lib/common.o $(LIBS) + +clean:; rm -f *.o firejail firejail.1 firejail.1.gz + +distclean: clean + rm -fr Makefile + diff --git a/src/firejail/arg-checking.txt b/src/firejail/arg-checking.txt new file mode 100644 index 00000000000..c1ab2cb216c --- /dev/null +++ b/src/firejail/arg-checking.txt @@ -0,0 +1,85 @@ +arg checking: + +1. --output=filename + - not supported in profiles + - checking no "..", + - checking no link, + - checking no dir, + - checking same permissions, + - checking no hard links + - unit test + +2. --chroot=dirname + - not supported in profiles + - expand "~" + - checking no "..", + - checking is dir, + - checking no link + - checking directory structure + - unit test + +3. --bind=dirname1,dirname2, --bind=filename1,filenam2 + - supported in profiles + - accepted only when running as root + - checking string chars + - checking no ".." + - unit test non root + +4. --tmpfs=dirname + - supported in profiles + - checking string chars + - checking no ".." + - unit test + +5. --blacklist=filename, --blacklist=dirname + - supported in profiles + - checking string chars + - checking no ".." + - unit test + +6. --read-only=filename, --read-only=dirname + - supported in profiles + - checking string chars + - checking no ".." + - unit test + +7. --profile=filename + - check access as real GID/UID + - checking no dir + - checking no link + - checking no ".." + - unit test + +8. --private=dirname + - supported in profiles + - expand "~" + - check is dir + - check no link + - checking no ".." + - check same owner + - unit test + +9. --private.keep=filelist + - supported in profiles + - checking no ".." + - checking file found + - checking same owner + - checking no link + - unit test + +10. --netfilter=filename + - supported in profiles + - check access as real GID/UID + - checking no dir + - checking no link + - checking no ".." + - unit test + +11. --shell=filename + - not supported in profiles + - check access as real GID/UID + - checking no dir + - checking no link + - checking no ".." + - unit test + diff --git a/src/firejail/arp.c b/src/firejail/arp.c new file mode 100644 index 00000000000..37f8716e7f8 --- /dev/null +++ b/src/firejail/arp.c @@ -0,0 +1,474 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firejail.h" +#include +#include +#include //TCP/IP Protocol Suite for Linux +#include +#include +#include +#include +#include +#include + +typedef struct arp_hdr_t { + uint16_t htype; + uint16_t ptype; + uint8_t hlen; + uint8_t plen; + uint16_t opcode; + uint8_t sender_mac[6]; + uint8_t sender_ip[4]; + uint8_t target_mac[6]; + uint8_t target_ip[4]; +} ArpHdr; + +// returns 0 if the address is not in use, -1 otherwise +int arp_check(const char *dev, uint32_t destaddr, uint32_t srcaddr) { + if (strlen(dev) > IFNAMSIZ) { + fprintf(stderr, "Error: invalid network device name %s\n", dev); + exit(1); + } + + if (arg_debug) + printf("Trying %d.%d.%d.%d ...\n", PRINT_IP(destaddr)); + + // find interface address + int sock; + if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) + errExit("socket"); + + srcaddr = htonl(srcaddr); + destaddr = htonl(destaddr); + + // Find interface MAC address + struct ifreq ifr; + memset(&ifr, 0, sizeof (ifr)); + strncpy(ifr.ifr_name, dev, IFNAMSIZ); + if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) + errExit("ioctl"); + close(sock); + + // configure layer2 socket address information + struct sockaddr_ll addr; + memset(&addr, 0, sizeof(addr)); + if ((addr.sll_ifindex = if_nametoindex(dev)) == 0) + errExit("if_nametoindex"); + addr.sll_family = AF_PACKET; + memcpy (addr.sll_addr, ifr.ifr_hwaddr.sa_data, 6); + addr.sll_halen = htons(6); + + // build the arp packet header + ArpHdr hdr; + memset(&hdr, 0, sizeof(hdr)); + hdr.htype = htons(1); + hdr.ptype = htons(ETH_P_IP); + hdr.hlen = 6; + hdr.plen = 4; + hdr.opcode = htons(1); //ARPOP_REQUEST + memcpy(hdr.sender_mac, ifr.ifr_hwaddr.sa_data, 6); + memcpy(hdr.sender_ip, (uint8_t *)&srcaddr, 4); + memcpy(hdr.target_ip, (uint8_t *)&destaddr, 4); + + // buiild ethernet frame + uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc + memset(frame, 0, sizeof(frame)); + frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff; + memcpy(frame + 6, ifr.ifr_hwaddr.sa_data, 6); + frame[12] = ETH_P_ARP / 256; + frame[13] = ETH_P_ARP % 256; + memcpy (frame + 14, &hdr, sizeof(hdr)); + + // open layer2 socket + if ((sock = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) + errExit("socket"); + + int len; + if ((len = sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr))) <= 0) + errExit("send"); + fflush(0); + + // wait not more than one second for an answer + fd_set fds; + FD_ZERO(&fds); + FD_SET(sock, &fds); + int maxfd = sock; + struct timeval ts; + ts.tv_sec = 1; // 1 second wait time + ts.tv_usec = 0; + while (1) { + int nready = select(maxfd + 1, &fds, (fd_set *) 0, (fd_set *) 0, &ts); + if (nready < 0) + errExit("select"); + else if (nready == 0) { // timeout + close(sock); + return 0; + } + else { + // read the incoming packet + int len = recvfrom(sock, frame, ETH_FRAME_LEN, 0, NULL, NULL); + if (len < 0) { + perror("recvfrom"); + close(sock); + return -1; + } + + // parse the incomming packet + if (len < 14 + sizeof(ArpHdr)) + continue; + if (frame[12] != (ETH_P_ARP / 256) || frame[13] != (ETH_P_ARP % 256)) + continue; + memcpy(&hdr, frame + 14, sizeof(ArpHdr)); + if (hdr.opcode == htons(1)) + continue; + if (hdr.opcode == htons(2)) { + // check my mac and my address + if (memcmp(ifr.ifr_hwaddr.sa_data, hdr.target_mac, 6) != 0) + continue; + uint32_t ip; + memcpy(&ip, hdr.target_ip, 4); + if (ip != srcaddr) { + continue; + } + close(sock); + return -1; + } + } + } + + // it will never get here! + close(sock); + return -1; +} + +// assign a random IP address and check it +// the address needs to be in the range if it --iprange was specified +static uint32_t arp_random(const char *dev, Bridge *br) { + assert(dev); + assert(br); + uint32_t ifip = br->ip; + uint32_t ifmask = br->mask; + assert(ifip); + assert(ifmask); + + if (arg_debug) + printf("ARP-scan %s, %d.%d.%d.%d/%d\n", + dev, PRINT_IP(ifip), mask2bits(ifmask)); + + // determine the range based on network address + uint32_t range = ~ifmask + 1; // the number of potential addresses + // this software is not supported for /31 networks + if (range < 4) + return 0; // the user will have to set the IP address manually + range -= 2; // subtract the network address and the broadcast address + uint32_t start = (ifip & ifmask) + 1; + + // adjust range based on --iprange params + if (br->iprange_start && br->iprange_end) { + start = br->iprange_start; + range = br->iprange_end - br->iprange_start; + } + + if (arg_debug) + printf("IP address range from %d.%d.%d.%d to %d.%d.%d.%d\n", + PRINT_IP(start), PRINT_IP(start + range)); + + // generate a random address - 10 tries + uint32_t dest = 0; + int i = 0; + for (i = 0; i < 10; i++) { + dest = start + ((uint32_t) rand()) % range; + if (dest == ifip) // do not allow the interface address + continue; // try again + + // if we've made it up to here, we have a valid address + break; + } + if (i == 10) // we failed 10 times + return 0; + + // check address + uint32_t rv = arp_check(dev, dest, ifip); + if (!rv) + return dest; + return 0; +} + +// go sequentially trough all IP addresses and assign the first one not in use +static uint32_t arp_sequential(const char *dev, Bridge *br) { + assert(dev); + assert(br); + uint32_t ifip = br->ip; + uint32_t ifmask = br->mask; + assert(ifip); + assert(ifmask); + + // range based on network address + uint32_t range = ~ifmask + 1; // the number of potential addresses + // this software is not supported for /31 networks + if (range < 4) + return 0; // the user will have to set the IP address manually + range -= 2; // subtract the network address and the broadcast address + + // try all possible ip addresses in ascending order + // start address + uint32_t dest = (ifip & ifmask) + 1; + if (br->iprange_start) + dest = br->iprange_start; + // end address + uint32_t last = dest + range - 1; + if (br->iprange_end) + last = br->iprange_end; + + if (arg_debug) + printf("Trying IP address range from %d.%d.%d.%d to %d.%d.%d.%d\n", + PRINT_IP(dest), PRINT_IP(last)); + + // loop through addresses and stop as soon as you find an unused one + while (dest <= last) { + if (dest == ifip) { + dest++; + continue; + } + uint32_t rv = arp_check(dev, dest, ifip); + if (!rv) + return dest; + dest++; + } + + return 0; +} + +// assign an IP address first trying some random addresses, and if this fails +// by doing an arp scan. +// +// dev is the name of the device to use in scanning, +// br is bridge structure holding the ip address and mask to use in +// arp packets. It also holds values for for the range of addresses +// if --iprange was set by the user +uint32_t arp_assign(const char *dev, Bridge *br) { + assert(br); + uint32_t ip = 0; + + // try two random IP addresses + ip = arp_random(dev, br); + if (!ip) + ip = arp_random(dev, br); + + // try all possible IP addresses one by one + if (!ip) + ip = arp_sequential(dev, br); + + // print result + if (!ip) { + fprintf(stderr, "Error: cannot assign an IP address; it looks like all of them are in use.\n"); + logerr("Cannot assign an IP address; it looks like all of them are in use."); + exit(1); + } + + return ip; +} + +// scan interface (--scan option) +void arp_scan(const char *dev, uint32_t ifip, uint32_t ifmask) { + assert(dev); + assert(ifip); + +// printf("Scanning interface %s (%d.%d.%d.%d/%d)\n", +// dev, PRINT_IP(ifip & ifmask), mask2bits(ifmask)); + + if (strlen(dev) > IFNAMSIZ) { + fprintf(stderr, "Error: invalid network device name %s\n", dev); + exit(1); + } + + // find interface mac address + int sock; + if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) + errExit("socket"); + struct ifreq ifr; + memset(&ifr, 0, sizeof (ifr)); + strncpy(ifr.ifr_name, dev, IFNAMSIZ); + if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) + errExit("ioctl"); + close(sock); + uint8_t mac[6]; + memcpy (mac, ifr.ifr_hwaddr.sa_data, 6); + + // open layer2 socket + if ((sock = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) + errExit("socket"); + + // try all possible ip addresses in ascending order + uint32_t range = ~ifmask + 1; // the number of potential addresses + // this software is not supported for /31 networks + if (range < 4) { + fprintf(stderr, "Warning: this option is not supported for /31 networks\n"); + close(sock); + return; + } + + uint32_t dest = (ifip & ifmask) + 1; + uint32_t last = dest + range - 1; + uint32_t src = htonl(ifip); + + // wait not more than one second for an answer + int header_printed = 0; + int last_ip = 0; + struct timeval ts; + ts.tv_sec = 2; // 2 seconds receive timeout + ts.tv_usec = 0; + + while (1) { + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(sock, &rfds); + fd_set wfds; + FD_ZERO(&wfds); + FD_SET(sock, &wfds); + int maxfd = sock; + + uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc + memset(frame, 0, ETH_FRAME_LEN); + + int nready; + if (dest < last) + nready = select(maxfd + 1, &rfds, &wfds, (fd_set *) 0, NULL); + else + nready = select(maxfd + 1, &rfds, (fd_set *) 0, (fd_set *) 0, &ts); + + if (nready < 0) + errExit("select"); + + if (nready == 0) { // timeout + break; + } + + if (FD_ISSET(sock, &wfds) && dest < last) { + // configure layer2 socket address information + struct sockaddr_ll addr; + memset(&addr, 0, sizeof(addr)); + if ((addr.sll_ifindex = if_nametoindex(dev)) == 0) + errExit("if_nametoindex"); + addr.sll_family = AF_PACKET; + memcpy (addr.sll_addr, mac, 6); + addr.sll_halen = htons(6); + + // build the arp packet header + ArpHdr hdr; + memset(&hdr, 0, sizeof(hdr)); + hdr.htype = htons(1); + hdr.ptype = htons(ETH_P_IP); + hdr.hlen = 6; + hdr.plen = 4; + hdr.opcode = htons(1); //ARPOP_REQUEST + memcpy(hdr.sender_mac, mac, 6); + memcpy(hdr.sender_ip, (uint8_t *)&src, 4); + uint32_t dst = htonl(dest); + memcpy(hdr.target_ip, (uint8_t *)&dst, 4); + + // buiild ethernet frame + uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc + memset(frame, 0, sizeof(frame)); + frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff; + memcpy(frame + 6, mac, 6); + frame[12] = ETH_P_ARP / 256; + frame[13] = ETH_P_ARP % 256; + memcpy (frame + 14, &hdr, sizeof(hdr)); + + // send packet + int len; + if ((len = sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr))) <= 0) + errExit("send"); +//printf("send %d bytes to %d.%d.%d.%d\n", len, PRINT_IP(dest)); + fflush(0); + dest++; + } + + if (FD_ISSET(sock, &rfds)) { + // read the incoming packet + int len = recvfrom(sock, frame, ETH_FRAME_LEN, 0, NULL, NULL); + if (len < 0) { + perror("recvfrom"); + } + + // parse the incomming packet + if (len < 14 + sizeof(ArpHdr)) + continue; + + // look only at ARP packets + if (frame[12] != (ETH_P_ARP / 256) || frame[13] != (ETH_P_ARP % 256)) + continue; + + ArpHdr hdr; + memcpy(&hdr, frame + 14, sizeof(ArpHdr)); + + if (hdr.opcode == htons(2)) { + // check my mac and my address + if (memcmp(mac, hdr.target_mac, 6) != 0) + continue; + uint32_t ip; + memcpy(&ip, hdr.target_ip, 4); + if (ip != src) + continue; + memcpy(&ip, hdr.sender_ip, 4); + ip = ntohl(ip); + + if (ip == last_ip) // filter duplicates + continue; + last_ip = ip; + + // printing + if (header_printed == 0) { + printf(" Network scan:\n"); + + // print parent interface + if (cfg.bridge0.configured && cfg.bridge0.ip && cfg.bridge0.macvlan && + (cfg.bridge0.ip & cfg.bridge0.mask) == (ifip & cfg.bridge0.mask)) + printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n", + PRINT_MAC(cfg.bridge0.mac), PRINT_IP(cfg.bridge0.ip)); + + if (cfg.bridge1.configured && cfg.bridge1.ip && cfg.bridge1.macvlan && + (cfg.bridge1.ip & cfg.bridge1.mask) == (ifip & cfg.bridge1.mask)) + printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n", + PRINT_MAC(cfg.bridge1.mac), PRINT_IP(cfg.bridge1.ip)); + + if (cfg.bridge2.configured && cfg.bridge2.ip && cfg.bridge2.macvlan && + (cfg.bridge2.ip & cfg.bridge2.mask) == (ifip & cfg.bridge2.mask)) + printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n", + PRINT_MAC(cfg.bridge2.mac), PRINT_IP(cfg.bridge2.ip)); + + if (cfg.bridge3.configured && cfg.bridge3.ip && cfg.bridge3.macvlan && + (cfg.bridge3.ip & cfg.bridge3.mask) == (ifip & cfg.bridge3.mask)) + printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n", + PRINT_MAC(cfg.bridge3.mac), PRINT_IP(cfg.bridge3.ip)); + + header_printed = 1; + } + printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n", + PRINT_MAC(hdr.sender_mac), PRINT_IP(ip)); + } + } + } + + close(sock); +} + + diff --git a/src/firejail/bandwidth.c b/src/firejail/bandwidth.c new file mode 100644 index 00000000000..25dd7a0fb77 --- /dev/null +++ b/src/firejail/bandwidth.c @@ -0,0 +1,483 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include "firejail.h" + +//*********************************** +// interface bandwidth linked list +//*********************************** +typedef struct ifbw_t { + struct ifbw_t *next; + char *txt; +} IFBW; +IFBW *ifbw = NULL; + + +#if 0 +static void ifbw_print(void) { + IFBW *ptr = ifbw; + while (ptr) { + printf("#%s#\n", ptr->txt); + ptr = ptr->next; + } +} +#endif + +static void ifbw_add(IFBW *ptr) { + assert(ptr); + + if (ifbw != NULL) + ptr->next = ifbw; + ifbw = ptr; +} + + +IFBW *ifbw_find(const char *dev) { + assert(dev); + int len = strlen(dev); + assert(len); + + if (ifbw == NULL) + return NULL; + + IFBW *ptr = ifbw; + while (ptr) { + if (strncmp(ptr->txt, dev, len) == 0 && ptr->txt[len] == ':') + return ptr; + ptr = ptr->next; + } + + return NULL; +} + +void ifbw_remove(IFBW *r) { + if (ifbw == NULL) + return; + + // remove the first element + if (ifbw == r) { + ifbw = ifbw->next; + return; + } + + // walk the list + IFBW *ptr = ifbw->next; + IFBW *prev = ifbw; + while (ptr) { + if (ptr == r) { + prev->next = ptr->next; + return; + } + + prev = ptr; + ptr = ptr->next; + } + + return; +} + +int fibw_count(viod) { + int rv = 0; + IFBW *ptr = ifbw; + + while (ptr) { + rv++; + ptr = ptr->next; + } + + return rv; +} + + +//*********************************** +// shm file handling +//*********************************** +void shm_create_firejail_dir(void) { + struct stat s; + if (stat("/dev/shm/firejail", &s) == -1) { + /* coverity[toctou] */ + if (mkdir("/dev/shm/firejail", 0777) == -1) + errExit("mkdir"); + if (chown("/dev/shm/firejail", 0, 0) == -1) + errExit("chown"); + } + else { // check /dev/shm/firejail directory belongs to root end exit if doesn't! + if (s.st_uid != 0 || s.st_gid != 0) { + fprintf(stderr, "Error: non-root %s directory, exiting...\n", "/dev/shm/firejail"); + exit(1); + } + } +} + +static void shm_create_bandwidth_file(pid_t pid) { + char *fname; + if (asprintf(&fname, "/dev/shm/firejail/%d-bandwidth", (int) pid) == -1) + errExit("asprintf"); + + // if the file already exists, do nothing + struct stat s; + if (stat(fname, &s) == 0) { + free(fname); + return; + } + + // create an empty file and set mod and ownership + /* coverity[toctou] */ + FILE *fp = fopen(fname, "w"); + if (fp) { + fclose(fp); + + /* coverity[toctou] */ + if (chmod(fname, 0644) == -1) + errExit("chmod"); + /* coverity[toctou] */ + if (chown(fname, 0, 0) == -1) + errExit("chown"); + } + else { + fprintf(stderr, "Error: cannot create bandwidth file in /dev/shm/firejail directory\n"); + exit(1); + } + + free(fname); +} + +// delete shm bandwidth file +void bandwidth_shm_del_file(pid_t pid) { + char *fname; + if (asprintf(&fname, "/dev/shm/firejail/%d-bandwidth", (int) pid) == -1) + errExit("asprintf"); + unlink(fname); + free(fname); +} + +void network_shm_del_file(pid_t pid) { + char *fname; + if (asprintf(&fname, "/dev/shm/firejail/%d-netmap", (int) pid) == -1) + errExit("asprintf"); + unlink(fname); + free(fname); +} + +void network_shm_set_file(pid_t pid) { + char *fname; + if (asprintf(&fname, "/dev/shm/firejail/%d-netmap", (int) pid) == -1) + errExit("asprintf"); + + // create an empty file and set mod and ownership + FILE *fp = fopen(fname, "w"); + if (fp) { + if (cfg.bridge0.configured) + fprintf(fp, "%s:%s\n", cfg.bridge0.dev, cfg.bridge0.devsandbox); + if (cfg.bridge1.configured) + fprintf(fp, "%s:%s\n", cfg.bridge1.dev, cfg.bridge1.devsandbox); + if (cfg.bridge2.configured) + fprintf(fp, "%s:%s\n", cfg.bridge2.dev, cfg.bridge2.devsandbox); + if (cfg.bridge3.configured) + fprintf(fp, "%s:%s\n", cfg.bridge3.dev, cfg.bridge3.devsandbox); + fclose(fp); + + if (chmod(fname, 0644) == -1) + errExit("chmod"); + if (chown(fname, 0, 0) == -1) + errExit("chown"); + } + else { + fprintf(stderr, "Error: cannot create network map file in /dev/shm/firejail directory\n"); + exit(1); + } + + free(fname); +} + + +void shm_read_bandwidth_file(pid_t pid) { + assert(ifbw == NULL); + + char *fname; + if (asprintf(&fname, "/dev/shm/firejail/%d-bandwidth", (int) pid) == -1) + errExit("asprintf"); + + FILE *fp = fopen(fname, "r"); + if (fp) { + char buf[1024]; + while (fgets(buf, 1024,fp)) { + // remove '\n' + char *ptr = strchr(buf, '\n'); + if (ptr) + *ptr = '\0'; + if (strlen(buf) == 0) + continue; + + // create a new IFBW entry + IFBW *ifbw_new = malloc(sizeof(IFBW)); + if (!ifbw_new) + errExit("malloc"); + memset(ifbw_new, 0, sizeof(IFBW)); + ifbw_new->txt = strdup(buf); + if (!ifbw_new->txt) + errExit("strdup"); + + // add it to the linked list + ifbw_add(ifbw_new); + } + + fclose(fp); + } +} + +void shm_write_bandwidth_file(pid_t pid) { + if (ifbw == NULL) + return; // nothing to do + + char *fname; + if (asprintf(&fname, "/dev/shm/firejail/%d-bandwidth", (int) pid) == -1) + errExit("asprintf"); + + FILE *fp = fopen(fname, "w"); + if (fp) { + IFBW *ptr = ifbw; + while (ptr) { + fprintf(fp, "%s\n", ptr->txt); + ptr = ptr->next; + } + fclose(fp); + } + else { + fprintf(stderr, "Error: cannot write bandwidht file %s\n", fname); + exit(1); + } +} + +//*********************************** +// add or remove interfaces +//*********************************** + +// remove interface from shm file +void bandwidth_shm_remove(pid_t pid, const char *dev) { + // create bandwidth directory & file in case they are not in the filesystem yet + shm_create_firejail_dir(); + shm_create_bandwidth_file(pid); + + // read bandwidth file + shm_read_bandwidth_file(pid); + + // find the element and remove it + IFBW *elem = ifbw_find(dev); + if (elem) { + ifbw_remove(elem); + shm_write_bandwidth_file(pid) ; + } + + // remove the file if there are no entries in the list + if (ifbw == NULL) { + bandwidth_shm_del_file(pid); + } +} + +// add interface to shm file +void bandwidth_shm_set(pid_t pid, const char *dev, int down, int up) { + // create bandwidth directory & file in case they are not in the filesystem yet + shm_create_firejail_dir(); + shm_create_bandwidth_file(pid); + + // create the new text entry + char *txt; + if (asprintf(&txt, "%s: RX %dKB/s, TX %dKB/s", dev, down, up) == -1) + errExit("asprintf"); + + // read bandwidth file + shm_read_bandwidth_file(pid); + + // look for an existing entry and replace the text + IFBW *ptr = ifbw_find(dev); + if (ptr) { + assert(ptr->txt); + free(ptr->txt); + ptr->txt = txt; + } + // ... or add a new entry + else { + IFBW *ifbw_new = malloc(sizeof(IFBW)); + if (!ifbw_new) + errExit("malloc"); + memset(ifbw_new, 0, sizeof(IFBW)); + ifbw_new->txt = txt; + + // add it to the linked list + ifbw_add(ifbw_new); + } + shm_write_bandwidth_file(pid) ; +} + + +//*********************************** +// command execution +//*********************************** +void bandwidth_name(const char *name, const char *command, const char *dev, int down, int up) { + if (!name || strlen(name) == 0) { + fprintf(stderr, "Error: invalid sandbox name\n"); + exit(1); + } + pid_t pid; + if (name2pid(name, &pid)) { + fprintf(stderr, "Error: cannot find sandbox %s\n", name); + exit(1); + } + + bandwidth_pid(pid, command, dev, down, up); +} + +void bandwidth_pid(pid_t pid, const char *command, const char *dev, int down, int up) { + //************************ + // verify sandbox + //************************ + char *comm = pid_proc_comm(pid); + if (!comm) { + fprintf(stderr, "Error: cannot find sandbox\n"); + exit(1); + } + + // remove \n and check for firejail sandbox + char *ptr = strchr(comm, '\n'); + if (ptr) + *ptr = '\0'; + if (strcmp(comm, "firejail") != 0) { + fprintf(stderr, "Error: cannot find sandbox\n"); + exit(1); + } + free(comm); + + // check network namespace + char *cmd = pid_proc_cmdline(pid); + if (!cmd || strstr(cmd, "--net") == NULL) { + fprintf(stderr, "Error: the sandbox doesn't use a new network namespace\n"); + exit(1); + } + free(cmd); + + + //************************ + // join the network namespace + //************************ + pid_t child; + if (find_child(pid, &child) == -1) { + fprintf(stderr, "Error: cannot join the network namespace\n"); + exit(1); + } + if (join_namespace(child, "net")) { + fprintf(stderr, "Error: cannot join the network namespace\n"); + exit(1); + } + + // set shm file + if (strcmp(command, "set") == 0) + bandwidth_shm_set(pid, dev, down, up); + else if (strcmp(command, "clear") == 0) + bandwidth_shm_remove(pid, dev); + + //************************ + // build command + //************************ + char *devname = NULL; + if (dev) { + // read shm network map file + char *fname; + if (asprintf(&fname, "/dev/shm/firejail/%d-netmap", (int) pid) == -1) + errExit("asprintf"); + FILE *fp = fopen(fname, "r"); + if (!fp) { + fprintf(stderr, "Error: cannot read netowk map filel %s\n", fname); + exit(1); + } + + char buf[1024]; + int len = strlen(dev); + while (fgets(buf, 1024, fp)) { + // remove '\n' + char *ptr = strchr(buf, '\n'); + if (ptr) + *ptr = '\0'; + if (*buf == '\0') + break; + + if (strncmp(buf, dev, len) == 0 && buf[len] == ':') { + devname = strdup(buf + len + 1); + if (!devname) + errExit("strdup"); + // check device in namespace + if (if_nametoindex(devname) == 0) { + fprintf(stderr, "Error: cannot find network device %s\n", devname); + exit(1); + } + break; + } + } + free(fname); + fclose(fp); + } + + // build fshaper.sh command + cmd = NULL; + if (devname) { + if (strcmp(command, "set") == 0) { + if (asprintf(&cmd, "%s/lib/firejail/fshaper.sh --%s %s %d %d", + PREFIX, command, devname, down, up) == -1) + errExit("asprintf"); + } + else { + if (asprintf(&cmd, "%s/lib/firejail/fshaper.sh --%s %s", + PREFIX, command, devname) == -1) + errExit("asprintf"); + } + } + else { + if (asprintf(&cmd, "%s/lib/firejail/fshaper.sh --%s", PREFIX, command) == -1) + errExit("asprintf"); + } + assert(cmd); + + // wipe out environment variables + environ = NULL; + + //************************ + // build command + //************************ + // elevate privileges + if (setreuid(0, 0)) + errExit("setreuid"); + if (setregid(0, 0)) + errExit("setregid"); + + char *arg[4]; + arg[0] = "/bin/bash"; + arg[1] = "-c"; + arg[2] = cmd; + arg[3] = NULL; + execvp("/bin/bash", arg); + + // it will never get here + exit(0); +} diff --git a/src/firejail/caps.c b/src/firejail/caps.c new file mode 100644 index 00000000000..d8777c0dbd6 --- /dev/null +++ b/src/firejail/caps.c @@ -0,0 +1,453 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "firejail.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int capget(cap_user_header_t hdrp, cap_user_data_t datap); +extern int capset(cap_user_header_t hdrp, const cap_user_data_t datap); + + +typedef struct { + char *name; + int nr; +} CapsEntry; + +static CapsEntry capslist[] = { +// +// code generated using tools/extract-caps +// updated manually based on kernel 3.18/include/linux/capability.h (added block suspend and audit_read +// +#ifdef CAP_CHOWN + {"chown", CAP_CHOWN }, +#endif +#ifdef CAP_DAC_OVERRIDE + {"dac_override", CAP_DAC_OVERRIDE }, +#endif +#ifdef CAP_DAC_READ_SEARCH + {"dac_read_search", CAP_DAC_READ_SEARCH }, +#endif +#ifdef CAP_FOWNER + {"fowner", CAP_FOWNER }, +#endif +#ifdef CAP_FSETID + {"fsetid", CAP_FSETID }, +#endif +#ifdef CAP_KILL + {"kill", CAP_KILL }, +#endif +#ifdef CAP_SETGID + {"setgid", CAP_SETGID }, +#endif +#ifdef CAP_SETUID + {"setuid", CAP_SETUID }, +#endif +#ifdef CAP_SETPCAP + {"setpcap", CAP_SETPCAP }, +#endif +#ifdef CAP_LINUX_IMMUTABLE + {"linux_immutable", CAP_LINUX_IMMUTABLE }, +#endif +#ifdef CAP_NET_BIND_SERVICE + {"net_bind_service", CAP_NET_BIND_SERVICE }, +#endif +#ifdef CAP_NET_BROADCAST + {"net_broadcast", CAP_NET_BROADCAST }, +#endif +#ifdef CAP_NET_ADMIN + {"net_admin", CAP_NET_ADMIN }, +#endif +#ifdef CAP_NET_RAW + {"net_raw", CAP_NET_RAW }, +#endif +#ifdef CAP_IPC_LOCK + {"ipc_lock", CAP_IPC_LOCK }, +#endif +#ifdef CAP_IPC_OWNER + {"ipc_owner", CAP_IPC_OWNER }, +#endif +#ifdef CAP_SYS_MODULE + {"sys_module", CAP_SYS_MODULE }, +#endif +#ifdef CAP_SYS_RAWIO + {"sys_rawio", CAP_SYS_RAWIO }, +#endif +#ifdef CAP_SYS_CHROOT + {"sys_chroot", CAP_SYS_CHROOT }, +#endif +#ifdef CAP_SYS_PTRACE + {"sys_ptrace", CAP_SYS_PTRACE }, +#endif +#ifdef CAP_SYS_PACCT + {"sys_pacct", CAP_SYS_PACCT }, +#endif +#ifdef CAP_SYS_ADMIN + {"sys_admin", CAP_SYS_ADMIN }, +#endif +#ifdef CAP_SYS_BOOT + {"sys_boot", CAP_SYS_BOOT }, +#endif +#ifdef CAP_SYS_NICE + {"sys_nice", CAP_SYS_NICE }, +#endif +#ifdef CAP_SYS_RESOURCE + {"sys_resource", CAP_SYS_RESOURCE }, +#endif +#ifdef CAP_SYS_TIME + {"sys_time", CAP_SYS_TIME }, +#endif +#ifdef CAP_SYS_TTY_CONFIG + {"sys_tty_config", CAP_SYS_TTY_CONFIG }, +#endif +#ifdef CAP_MKNOD + {"mknod", CAP_MKNOD }, +#endif +#ifdef CAP_LEASE + {"lease", CAP_LEASE }, +#endif +#ifdef CAP_AUDIT_WRITE + {"audit_write", CAP_AUDIT_WRITE }, +#endif +#ifdef CAP_AUDIT_CONTROL + {"audit_control", CAP_AUDIT_CONTROL }, +#endif +#ifdef CAP_SETFCAP + {"setfcap", CAP_SETFCAP }, +#endif +#ifdef CAP_MAC_OVERRIDE + {"mac_override", CAP_MAC_OVERRIDE }, +#endif +#ifdef CAP_MAC_ADMIN + {"mac_admin", CAP_MAC_ADMIN }, +#endif +#ifdef CAP_SYSLOG + {"syslog", CAP_SYSLOG }, +#endif +#ifdef CAP_WAKE_ALARM + {"wake_alarm", CAP_WAKE_ALARM }, +#endif +// not in Debian 7 +#ifdef CAP_BLOCK_SUSPEND + {"block_suspend", CAP_BLOCK_SUSPEND }, +#else + {"block_suspend", 36 }, +#endif +#ifdef CAP_AUDIT_READ + {"audit_read", CAP_AUDIT_READ }, +#else + {"audit_read", 37 }, +#endif + +// +// end of generated code +// +}; // end of capslist + +const char *caps_find_nr(int nr) { + int i; + int elems = sizeof(capslist) / sizeof(capslist[0]); + for (i = 0; i < elems; i++) { + if (nr == capslist[i].nr) + return capslist[i].name; + } + + return "unknown"; +} + +// return -1 if error, or syscall number +static int caps_find_name(const char *name) { + int i; + int elems = sizeof(capslist) / sizeof(capslist[0]); + for (i = 0; i < elems; i++) { + if (strcmp(name, capslist[i].name) == 0) + return capslist[i].nr; + } + + return -1; +} + +// return 1 if error, 0 if OK +int caps_check_list(const char *clist, void (*callback)(int)) { + // don't allow empty lists + if (clist == NULL || *clist == '\0') { + fprintf(stderr, "Error: empty capabilities lists are not allowed\n"); + return -1; + } + + // work on a copy of the string + char *str = strdup(clist); + if (!str) + errExit("strdup"); + + char *ptr = str; + char *start = str; + while (*ptr != '\0') { + if (islower(*ptr) || isdigit(*ptr) || *ptr == '_') + ; + else if (*ptr == ',') { + *ptr = '\0'; + int nr = caps_find_name(start); + if (nr == -1) { + fprintf(stderr, "Error: capability %s not found\n", start); + free(str); + return -1; + } + else if (callback != NULL) + callback(nr); + + start = ptr + 1; + } + ptr++; + } + if (*start != '\0') { + int nr = caps_find_name(start); + if (nr == -1) { + fprintf(stderr, "Error: capability %s not found\n", start); + free(str); + return -1; + } + else if (callback != NULL) + callback(nr); + } + + free(str); + return 0; +} + +void caps_print(void) { + int i; + int elems = sizeof(capslist) / sizeof(capslist[0]); + + // check current caps supported by the kernel + int cnt = 0; + unsigned long cap; + for (cap=0; cap <= 63; cap++) { + int code = prctl(PR_CAPBSET_DROP, cap, 0, 0, 0); + if (code == 0) + cnt++; + } + printf("Your kernel supports %d capabilities.\n", cnt); + + for (i = 0; i < elems; i++) { + printf("%d\t- %s\n", capslist[i].nr, capslist[i].name); + } +} + + + + +// enabled by default +int caps_default_filter(void) { + // drop capabilities + if (prctl(PR_CAPBSET_DROP, CAP_SYS_MODULE, 0, 0, 0) && arg_debug) + fprintf(stderr, "Warning: cannot drop CAP_SYS_MODULE"); + else if (arg_debug) + printf("Drop CAP_SYS_MODULE\n"); + + if (prctl(PR_CAPBSET_DROP, CAP_SYS_RAWIO, 0, 0, 0) && arg_debug) + fprintf(stderr, "Warning: cannot drop CAP_SYS_RAWIO"); + else if (arg_debug) + printf("Drop CAP_SYS_RAWIO\n"); + + if (prctl(PR_CAPBSET_DROP, CAP_SYS_BOOT, 0, 0, 0) && arg_debug) + fprintf(stderr, "Warning: cannot drop CAP_SYS_BOOT"); + else if (arg_debug) + printf("Drop CAP_SYS_BOOT\n"); + + if (prctl(PR_CAPBSET_DROP, CAP_SYS_NICE, 0, 0, 0) && arg_debug) + fprintf(stderr, "Warning: cannot drop CAP_SYS_NICE"); + else if (arg_debug) + printf("Drop CAP_SYS_NICE\n"); + + if (prctl(PR_CAPBSET_DROP, CAP_SYS_TTY_CONFIG, 0, 0, 0) && arg_debug) + fprintf(stderr, "Warning: cannot drop CAP_SYS_TTY_CONFIG"); + else if (arg_debug) + printf("Drop CAP_SYS_TTY_CONFIG\n"); + + if (prctl(PR_CAPBSET_DROP, CAP_SYSLOG, 0, 0, 0) && arg_debug) + fprintf(stderr, "Warning: cannot drop CAP_SYSLOG"); + else if (arg_debug) + printf("Drop CAP_SYSLOG\n"); + + if (prctl(PR_CAPBSET_DROP, CAP_MKNOD, 0, 0, 0) && arg_debug) + fprintf(stderr, "Warning: cannot drop CAP_MKNOD"); + else if (arg_debug) + printf("Drop CAP_MKNOD\n"); + + if (prctl(PR_CAPBSET_DROP, CAP_SYS_ADMIN, 0, 0, 0) && arg_debug) + fprintf(stderr, "Warning: cannot drop CAP_SYS_ADMIN"); + else if (arg_debug) + printf("Drop CAP_SYS_ADMIN\n"); + + return 0; +} + +void caps_drop_all(void) { + if (arg_debug) + printf("Droping all capabilities\n"); + + unsigned long cap; + for (cap=0; cap <= 63; cap++) { + int code = prctl(PR_CAPBSET_DROP, cap, 0, 0, 0); + if (code == -1 && errno != EINVAL) + errExit("PR_CAPBSET_DROP"); + } +} + + +void caps_set(uint64_t caps) { + if (arg_debug) + printf("Set caps filter %llx\n", (unsigned long long) caps); + + unsigned long i; + uint64_t mask = 1LLU; + for (i = 0; i < 64; i++, mask <<= 1) { + if ((mask & caps) == 0) { + int code = prctl(PR_CAPBSET_DROP, i, 0, 0, 0); + if (code == -1 && errno != EINVAL) + errExit("PR_CAPBSET_DROP"); + } + } +} + + +static uint64_t filter; + +static void caps_set_bit(int nr) { + uint64_t mask = 1LLU << nr; + filter |= mask; +} +static void caps_reset_bit(int nr) { + uint64_t mask = 1LLU << nr; + filter &= ~mask; +} + +void caps_drop_list(const char *clist) { + filter = 0; + filter--; + caps_check_list(clist, caps_reset_bit); + caps_set(filter); +} + +void caps_keep_list(const char *clist) { + filter = 0; + caps_check_list(clist, caps_set_bit); + caps_set(filter); +} + +#define MAXBUF 4098 +static uint64_t extract_caps(int pid) { + char *file; + if (asprintf(&file, "/proc/%d/status", pid) == -1) { + errExit("asprintf"); + exit(1); + } + + FILE *fp = fopen(file, "r"); + if (!fp) { + printf("Error: cannot open %s\n", file); + free(file); + exit(1); + } + + char buf[MAXBUF]; + while (fgets(buf, MAXBUF, fp)) { + if (strncmp(buf, "CapBnd:", 7) == 0) { + char *ptr = buf + 8; + unsigned long long val; + sscanf(ptr, "%llx", &val); + free(file); + fclose(fp); + return val; + } + } + fclose(fp); + free(file); + printf("Error: cannot read caps configuration\n"); + exit(1); +} + + +void caps_print_filter_name(const char *name) { + if (!name || strlen(name) == 0) { + fprintf(stderr, "Error: invalid sandbox name\n"); + exit(1); + } + pid_t pid; + if (name2pid(name, &pid)) { + fprintf(stderr, "Error: cannot find sandbox %s\n", name); + exit(1); + } + + caps_print_filter(pid); +} + +void caps_print_filter(pid_t pid) { + // if the pid is that of a firejail process, use the pid of the first child process + char *comm = pid_proc_comm(pid); + if (comm) { + // remove \n + char *ptr = strchr(comm, '\n'); + if (ptr) + *ptr = '\0'; + if (strcmp(comm, "firejail") == 0) { + pid_t child; + if (find_child(pid, &child) == 0) { + pid = child; + } + } + free(comm); + } + + // check privileges for non-root users + uid_t uid = getuid(); + if (uid != 0) { + struct stat s; + char *dir; + if (asprintf(&dir, "/proc/%u/ns", pid) == -1) + errExit("asprintf"); + if (stat(dir, &s) < 0) + errExit("stat"); + if (s.st_uid != uid) { + printf("Error: permission denied.\n"); + exit(1); + } + } + + uint64_t caps = extract_caps(pid); + drop_privs(1); + + int i; + uint64_t mask; + int elems = sizeof(capslist) / sizeof(capslist[0]); + for (i = 0, mask = 1; i < elems; i++, mask <<= 1) { + printf("%-18.18s - %s\n", capslist[i].name, (mask & caps)? "enabled": "disabled"); + } + + exit(0); +} diff --git a/src/firejail/cgroup.c b/src/firejail/cgroup.c new file mode 100644 index 00000000000..7366a669952 --- /dev/null +++ b/src/firejail/cgroup.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firejail.h" +#include + +#define MAXBUF 4096 + +void save_cgroup(void) { + if (cfg.cgroup == NULL) + return; + + char *fname; + if (asprintf(&fname, "%s/cgroup", MNT_DIR) == -1) + errExit(fname); + + FILE *fp = fopen(fname, "w"); + if (fp) { + fprintf(fp, "%s", cfg.cgroup); + fflush(0); + fclose(fp); + if (chown(fname, 0, 0) < 0) + errExit("chown"); + } + else { + fprintf(stderr, "Error: cannot save cgroup\n"); + free(fname); + exit(1); + } + + free(fname); +} + +void load_cgroup(const char *fname) { + if (!fname) + return; + + FILE *fp = fopen(fname, "r"); + if (fp) { + char buf[MAXBUF]; + if (fgets(buf, MAXBUF, fp)) { + cfg.cgroup = strdup(buf); + if (!cfg.cgroup) + errExit("strdup"); + } + else + goto errout; + + fclose(fp); + return; + } +errout: + fprintf(stderr, "Warrning: cannot load control group\n"); + if (fp) + fclose(fp); +} + + +void set_cgroup(const char *path) { + // path starts with /sys/fs/cgroup + if (strncmp(path, "/sys/fs/cgroup", 14) != 0) + goto errout; + + // path ends in tasks + char *ptr = strstr(path, "tasks"); + if (!ptr) + goto errout; + if (*(ptr + 5) != '\0') + goto errout; + + // no .. traversal + ptr = strstr(path, ".."); + if (ptr) + goto errout; + + // tasks file exists + struct stat s; + if (stat(path, &s) == -1) + goto errout; + + // task file belongs to the user running the sandbox + if (s.st_uid != getuid() && s.st_gid != getgid()) + goto errout2; + + // add the task to cgroup + /* coverity[toctou] */ + FILE *fp = fopen(path, "a"); + if (!fp) + goto errout; + pid_t pid = getpid(); + int rv = fprintf(fp, "%d\n", pid); + (void) rv; + fclose(fp); + return; + +errout: + fprintf(stderr, "Error: invalid cgroup\n"); + exit(1); +errout2: + fprintf(stderr, "Error: you don't have permissions to use this control group\n"); + exit(1); +} diff --git a/src/firejail/cpu.c b/src/firejail/cpu.c new file mode 100644 index 00000000000..633081a3f77 --- /dev/null +++ b/src/firejail/cpu.c @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firejail.h" +#include + +// converts a numeric cpu value in the corresponding bit mask +static void set_cpu(const char *str) { + if (strlen(str) == 0) + return; + + int val = atoi(str); + if (val < 0 || val >= 32) { + fprintf(stderr, "Error: invalid cpu number. Accepted values are between 0 and 31.\n"); + exit(1); + } + + uint32_t mask = 1; + int i; + for (i = 0; i < val; i++, mask <<= 1); + cfg.cpus |= mask; +} + +void read_cpu_list(const char *str) { + char *tmp = strdup(str); + if (tmp == NULL) + errExit("strdup"); + + char *ptr = tmp; + while (*ptr != '\0') { + if (*ptr == ',' || isdigit(*ptr)) + ; + else { + fprintf(stderr, "Error: invalid cpu list\n"); + exit(1); + } + ptr++; + } + + char *start = tmp; + ptr = tmp; + while (*ptr != '\0') { + if (*ptr == ',') { + *ptr = '\0'; + set_cpu(start); + start = ptr + 1; + } + ptr++; + } + set_cpu(start); + free(tmp); +} + +void save_cpu(void) { + if (cfg.cpus == 0) + return; + + char *fname; + if (asprintf(&fname, "%s/cpu", MNT_DIR) == -1) + errExit("asprintf"); + FILE *fp = fopen(fname, "w"); + if (fp) { + fprintf(fp, "%x\n", cfg.cpus); + fclose(fp); + if (chown(fname, 0, 0) < 0) + errExit("chown"); + } + else { + fprintf(stderr, "Error: cannot save cpu affinity mask\n"); + free(fname); + exit(1); + } + + free(fname); +} + +void load_cpu(const char *fname) { + if (!fname) + return; + + FILE *fp = fopen(fname, "r"); + if (fp) { + unsigned tmp; + int rv = fscanf(fp, "%x", &tmp); + if (rv) + cfg.cpus = (uint32_t) tmp; + fclose(fp); + } + else + fprintf(stderr, "Warning: cannot load cpu affinity mask\n"); +} + +void set_cpu_affinity(void) { + // set cpu affinity + cpu_set_t mask; + CPU_ZERO(&mask); + + int i; + uint32_t m = 1; + for (i = 0; i < 32; i++, m <<= 1) { + if (cfg.cpus & m) + CPU_SET(i, &mask); + } + + if (sched_setaffinity(0, sizeof(mask), &mask) == -1) { + fprintf(stderr, "Warning: cannot set cpu affinity\n"); + fprintf(stderr, " "); + perror("sched_setaffinity"); + } + + // verify cpu affinity + cpu_set_t mask2; + CPU_ZERO(&mask2); + if (sched_getaffinity(0, sizeof(mask2), &mask2) == -1) { + fprintf(stderr, "Warning: cannot verify cpu affinity\n"); + fprintf(stderr, " "); + perror("sched_getaffinity"); + } + else { + if (CPU_EQUAL(&mask, &mask2)) + printf("CPU affinity set\n"); + else + printf("CPU affinity not set\n"); + } +} diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h new file mode 100644 index 00000000000..2ec6e54c99b --- /dev/null +++ b/src/firejail/firejail.h @@ -0,0 +1,354 @@ +/* + * Copyright (C) 2014, 2015 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef FIREJAIL_H +#define FIREJAIL_H +#include "../include/common.h" + +#define USELOCK +#define FIREJAIL_DIR "/tmp/firejail" +#define RO_DIR "/tmp/firejail/firejail.ro.dir" +#define RO_FILE "/tmp/firejail/firejail.ro.file" +#define MNT_DIR "/tmp/firejail/mnt" +#define OVERLAY_DIR "/tmp/firejail/overlay" +#define HOME_DIR "/tmp/firejail/mnt/home" +#define MAX_INCLUDE_LEVEL 6 + +// main.c +typedef struct bridge_t { + // on the host + char *dev; // interface device name: bridge or regular ethernet + uint32_t ip; // interface device IP address + uint32_t mask; // interface device mask + uint8_t mac[6]; // interface mac address + + // inside the sandbox + char *devsandbox; // name of the device inside the sandbox + uint32_t ipsandbox; // ip address inside the sandbox + uint8_t macsandbox[6]; // mac address inside the sandbox + uint32_t iprange_start;// iprange arp scan start range + uint32_t iprange_end; // iprange arp scan end range + + // flags + uint8_t arg_ip_none; // --ip=none + uint8_t macvlan; // set by --net=eth0 (or eth1, ...); reset by --net=br0 (or br1, ...) + uint8_t configured; + uint8_t scan; // set by --scan +} Bridge; + +typedef struct profile_entry_t { + struct profile_entry_t *next; + char *data; +}ProfileEntry; + +typedef struct config_t { + // user data + char *username; + char *homedir; + + // filesystem + ProfileEntry *profile; + char *chrootdir; // chroot directory + char *home_private; // private home directory + char *home_private_keep; // keep list for private home directory + char *cwd; // current working directory + + // networking + char *hostname; + uint32_t defaultgw; // default gateway + Bridge bridge0; + Bridge bridge1; + Bridge bridge2; + Bridge bridge3; + uint32_t dns1; // up to 3 IP addresses for dns servers + uint32_t dns2; + uint32_t dns3; + + // rlimits + unsigned rlimit_nofile; + unsigned rlimit_nproc; + unsigned rlimit_fsize; + unsigned rlimit_sigpending; + + // cpu affinity and control groups + uint32_t cpus; + char *cgroup; + + + // command line + char *command_line; + char *command_name; + char *shell; + char **original_argv; + int original_argc; + int original_program_index; +} Config; +extern Config cfg; + +static inline int any_bridge_configured(void) { + if (cfg.bridge3.configured || cfg.bridge2.configured || cfg.bridge1.configured || cfg.bridge0.configured) + return 1; + else + return 0; +} +extern int arg_private; // mount private /home and /tmp directory +extern int arg_debug; // print debug messages +extern int arg_nonetwork; // --net=none +extern int arg_command; // -c +extern int arg_overlay; // --overlay +extern int arg_zsh; // use zsh as default shell +extern int arg_csh; // use csh as default shell + +extern int arg_seccomp; // enable default seccomp filter +extern char *arg_seccomp_list;// optional seccomp list on top of default filter +extern char *arg_seccomp_list_drop; // seccomp drop list +extern char *arg_seccomp_list_keep; // seccomp keep list + +extern int arg_caps_default_filter; // enable default capabilities filter +extern int arg_caps_drop; // drop list +extern int arg_caps_drop_all; // drop all capabilities +extern int arg_caps_keep; // keep list +extern char *arg_caps_list; // optional caps list + +extern int arg_trace; // syscall tracing support +extern int arg_rlimit_nofile; // rlimit nofile +extern int arg_rlimit_nproc; // rlimit nproc +extern int arg_rlimit_fsize; // rlimit fsize +extern int arg_rlimit_sigpending;// rlimit sigpending +extern int arg_nox11; // kill the program if x11 unix domain socket is accessed +extern int arg_nodbus; // kill the program if D-Bus is accessed +extern int arg_nogroups; // disable supplementary groups +extern int arg_noroot; // create a new user namespace and disable root user +extern int arg_netfilter; // enable netfilter +extern char *arg_netfilter_file; // netfilter file +extern int arg_doubledash; // double dash +extern int arg_shell_none; // run the program directly without a shell +extern int arg_private_dev; // private dev directory +extern int arg_scan; // arp-scan all interfaces + +extern int parent_to_child_fds[2]; +extern int child_to_parent_fds[2]; +extern pid_t sandbox_pid; + + + +#define MAX_ARGS 128 // maximum number of command arguments (argc) +extern char *fullargv[MAX_ARGS]; +extern int fullargc; + +// main.c +void check_user_namespace(void); + +// sandbox.c +int sandbox(void* sandbox_arg); + +// network_main.c +void net_configure_bridge(Bridge *br, char *dev_name); +void net_configure_sandbox_ip(Bridge *br); +void net_configure_veth_pair(Bridge *br, const char *ifname, pid_t child); +void net_check_cfg(void); +void net_dns_print_name(const char *name); +void net_dns_print(pid_t pid); + +// network.c +void net_if_up(const char *ifname); +void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask); +int net_get_if_addr(const char *bridge, uint32_t *ip, uint32_t *mask, uint8_t mac[6]); +int net_add_route(uint32_t dest, uint32_t mask, uint32_t gw); +void net_ifprint(void); +void net_bridge_add_interface(const char *bridge, const char *dev); +uint32_t network_get_defaultgw(void); +int net_config_mac(const char *ifname, const unsigned char mac[6]); +int net_get_mac(const char *ifname, unsigned char mac[6]); + +// fs.c +// build /tmp/firejail directory +void fs_build_firejail_dir(void); +// build /tmp/firejail/mnt directory +void fs_build_mnt_dir(void); +// blacklist files or directoies by mounting empty files on top of them +void fs_blacklist(const char *homedir); +//void fs_blacklist(char **blacklist, const char *homedir); +// remount a directory read-only +void fs_rdonly(const char *dir); +// mount /proc and /sys directories +void fs_proc_sys_dev_boot(void); +// build a basic read-only filesystem +void fs_basic_fs(void); +// mount overlayfs on top of / directory +void fs_overlayfs(void); +// chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf +void fs_chroot(const char *rootdir); +int fs_check_chroot_dir(const char *rootdir); + +// profile.c +// find and read the profile specified by name from dir directory +int profile_find(const char *name, const char *dir); +// read a profile file +void profile_read(const char *fname, const char *skip1, const char *skip2); +// check profile line; if line == 0, this was generated from a command line option +// return 1 if the command is to be added to the linked list of profile commands +// return 0 if the command was already executed inside the function +int profile_check_line(char *ptr, int lineno); +// add a profile entry in cfg.profile list; use str to populate the list +void profile_add(char *str); + +// list.c +void list(void); +void tree(void); +void top(void); +void netstats(void); + +// usage.c +void usage(void); + +// join.c +void join(pid_t pid, const char *homedir, int argc, char **argv, int index); +void join_name(const char *name, const char *homedir, int argc, char **argv, int index); +void shut(pid_t pid); +void shut_name(const char *name); + +// restricted_shell.c +extern char *restricted_user; +int restricted_shell(const char *user); + +// arp.c +// returns 0 if the address is not in use, -1 otherwise +int arp_check(const char *dev, uint32_t destaddr, uint32_t srcaddr); +// assign an IP address using arp scanning +uint32_t arp_assign(const char *dev, Bridge *br); +// scan interface (--scan option) +void arp_scan(const char *dev, uint32_t srcaddr, uint32_t srcmask); + +// veth.c +int net_create_veth(const char *dev, const char *nsdev, unsigned pid); +int net_create_macvlan(const char *dev, const char *parent, unsigned pid); + +// util.c +void drop_privs(int nogroups); +void extract_command_name(const char *str); +void logsignal(int s); +void logmsg(const char *msg); +void logargs(int argc, char **argv) ; +void logerr(const char *msg); +int copy_file(const char *srcname, const char *destname); +char *get_link(const char *fname); +int is_dir(const char *fname); +int is_link(const char *fname); +char *line_remove_spaces(const char *buf); +char *split_comma(char *str); +int not_unsigned(const char *str); +int find_child(pid_t parent, pid_t *child); +void check_private_dir(void); +void update_map(char *mapping, char *map_file); +void wait_for_other(int fd); +void notify_other(int fd); + +// fs_var.c +void fs_var_log(void); // mounting /var/log +void fs_var_lib(void); // various other fixes for software in /var directory +void fs_var_cache(void); // various other fixes for software in /var/cache directory +void fs_var_run(void); +void fs_var_lock(void); +void fs_var_tmp(void); +void fs_var_utmp(void); +void dbg_test_dir(const char *dir); + +// fs_dev.c +void fs_dev_shm(void); +void fs_private_dev(void); + +// fs_home.c +// private mode (--private) +void fs_private(void); +// private mode (--private=homedir) +void fs_private_homedir(void); +// private mode (--private.keep=list) +void fs_private_home_list(void); +// check directory linst specified by user (--private.keep option) - exit if it fails +void fs_check_home_list(void); +// check new private home directory (--private= option) - exit if it fails +void fs_check_private_dir(void); + + +// seccomp.c +int seccomp_filter_drop(void); +int seccomp_filter_keep(void); +void seccomp_set(void); +void seccomp_print_filter_name(const char *name); +void seccomp_print_filter(pid_t pid); + +// caps.c +int caps_default_filter(void); +void caps_print(void); +void caps_drop_all(void); +void caps_set(uint64_t caps); +int caps_check_list(const char *clist, void (*callback)(int)); +void caps_drop_list(const char *clist); +void caps_keep_list(const char *clist); +void caps_print_filter(pid_t pid); +void caps_print_filter_name(const char *name); + +// syscall.c +const char *syscall_find_nr(int nr); +// return -1 if error, 0 if no error +int syscall_check_list(const char *slist, void (*callback)(int)); +// print all available syscalls +void syscall_print(void); + +// fs_trace.c +void fs_trace_preload(void); +void fs_trace(void); + +// fs_hostname.c +void fs_hostname(const char *hostname); +void fs_resolvconf(void); + +// rlimit.c +void set_rlimits(void); + +// cpu.c +void read_cpu_list(const char *str); +void set_cpu_affinity(void); +void load_cpu(const char *fname); +void save_cpu(void); + +// cgroup.c +void save_cgroup(void); +void load_cgroup(const char *fname); +void set_cgroup(const char *path); + +// output.c +void check_output(int argc, char **argv); + +// netfilter.c +void check_netfilter_file(const char *fname); +void netfilter(const char *fname); + +// bandwidth.c +void shm_create_firejail_dir(void); +void bandwidth_shm_del_file(pid_t pid); +void bandwidth_shm_set(pid_t pid, const char *dev, int down, int up); +void bandwidth_name(const char *name, const char *command, const char *dev, int down, int up); +void bandwidth_pid(pid_t pid, const char *command, const char *dev, int down, int up); +void network_shm_del_file(pid_t pid); +void network_shm_set_file(pid_t pid); + + +#endif \ No newline at end of file diff --git a/src/firejail/fs.c b/src/firejail/fs.c new file mode 100644 index 00000000000..1fc1c0942d8 --- /dev/null +++ b/src/firejail/fs.c @@ -0,0 +1,825 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firejail.h" +#include +#include +#include +#include +#include +#include +#include + +// build /tmp/firejail directory +void fs_build_firejail_dir(void) { + struct stat s; + + if (stat(FIREJAIL_DIR, &s)) { + if (arg_debug) + printf("Creating %s directory\n", FIREJAIL_DIR); + /* coverity[toctou] */ + int rv = mkdir(FIREJAIL_DIR, S_IRWXU | S_IRWXG | S_IRWXO); + if (rv == -1) + errExit("mkdir"); + if (chown(FIREJAIL_DIR, 0, 0) < 0) + errExit("chown"); + if (chmod(FIREJAIL_DIR, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) + errExit("chmod"); + } + else { // check /tmp/firejail directory belongs to root end exit if doesn't! + if (s.st_uid != 0 || s.st_gid != 0) { + fprintf(stderr, "Error: non-root %s directory, exiting...\n", FIREJAIL_DIR); + exit(1); + } + } +} + + +// build /tmp/firejail/mnt directory +static int tmpfs_mounted = 0; +void fs_build_mnt_dir(void) { + struct stat s; + fs_build_firejail_dir(); + + // create /tmp/firejail directory + if (stat(MNT_DIR, &s)) { + if (arg_debug) + printf("Creating %s directory\n", MNT_DIR); + /* coverity[toctou] */ + int rv = mkdir(MNT_DIR, S_IRWXU | S_IRWXG | S_IRWXO); + if (rv == -1) + errExit("mkdir"); + if (chown(MNT_DIR, 0, 0) < 0) + errExit("chown"); + if (chmod(MNT_DIR, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) + errExit("chmod"); + } + + // ... and mount tmpfs on top of it + if (!tmpfs_mounted) { + // mount tmpfs on top of /tmp/firejail/mnt + if (arg_debug) + printf("Mounting tmpfs on %s directory\n", MNT_DIR); + if (mount("tmpfs", MNT_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) + errExit("mounting /tmp/firejail/mnt"); + tmpfs_mounted = 1; + } +} + +// build /tmp/firejail/overlay directory +void fs_build_overlay_dir(void) { + struct stat s; + fs_build_firejail_dir(); + + // create /tmp/firejail directory + if (stat(OVERLAY_DIR, &s)) { + if (arg_debug) + printf("Creating %s directory\n", MNT_DIR); + /* coverity[toctou] */ + int rv = mkdir(OVERLAY_DIR, S_IRWXU | S_IRWXG | S_IRWXO); + if (rv == -1) + errExit("mkdir"); + if (chown(OVERLAY_DIR, 0, 0) < 0) + errExit("chown"); + if (chmod(OVERLAY_DIR, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) + errExit("chmod"); + } +} + + + + + +//*********************************************** +// process profile file +//*********************************************** +typedef enum { + BLACKLIST_FILE, + MOUNT_READONLY, + MOUNT_TMPFS, + OPERATION_MAX +} OPERATION; + + +static char *create_empty_dir(void) { + struct stat s; + fs_build_firejail_dir(); + + if (stat(RO_DIR, &s)) { + /* coverity[toctou] */ + int rv = mkdir(RO_DIR, S_IRUSR | S_IXUSR); + if (rv == -1) + errExit("mkdir"); + if (chown(RO_DIR, 0, 0) < 0) + errExit("chown"); + } + + return RO_DIR; +} + +static char *create_empty_file(void) { + struct stat s; + fs_build_firejail_dir(); + + if (stat(RO_FILE, &s)) { + /* coverity[toctou] */ + FILE *fp = fopen(RO_FILE, "w"); + if (!fp) + errExit("fopen"); + fclose(fp); + if (chown(RO_FILE, 0, 0) < 0) + errExit("chown"); + if (chmod(RO_FILE, S_IRUSR) < 0) + errExit("chown"); + } + + return RO_FILE; +} + +static void disable_file(OPERATION op, const char *fname, const char *emptydir, const char *emptyfile) { + assert(fname); + assert(emptydir); + assert(emptyfile); + assert(op data, "bind", 4) == 0) { + char *dname1 = entry->data + 5; + char *dname2 = split_comma(dname1); + if (dname2 == NULL) { + fprintf(stderr, "Error: second directory missing in bind command\n"); + entry = entry->next; + continue; + } + struct stat s; + if (stat(dname1, &s) == -1) { + fprintf(stderr, "Error: cannot find directories for bind command\n"); + entry = entry->next; + continue; + } + if (stat(dname2, &s) == -1) { + fprintf(stderr, "Error: cannot find directories for bind command\n"); + entry = entry->next; + continue; + } + + // mount --bind olddir newdir + if (arg_debug) + printf("Mount-bind %s on top of %s\n", dname1, dname2); + // preserve dname2 mode and ownership + if (mount(dname1, dname2, NULL, MS_BIND|MS_REC, NULL) < 0) + errExit("mount bind"); + /* coverity[toctou] */ + if (chown(dname2, s.st_uid, s.st_gid) == -1) + errExit("mount-bind chown"); + /* coverity[toctou] */ + if (chmod(dname2, s.st_mode) == -1) + errExit("mount-bind chmod"); + + entry = entry->next; + continue; + } + + // process blacklist command + if (strncmp(entry->data, "blacklist", 9) == 0) { + ptr = entry->data + 10; + op = BLACKLIST_FILE; + } + else if (strncmp(entry->data, "read-only", 9) == 0) { + ptr = entry->data + 10; + op = MOUNT_READONLY; + } + else if (strncmp(entry->data, "tmpfs", 5) == 0) { + ptr = entry->data + 6; + op = MOUNT_TMPFS; + } + else { + fprintf(stderr, "Error: invalid profile line %s\n", entry->data); + entry = entry->next; + continue; + } + + // replace home macro in blacklist array + char *new_name = NULL; + if (strncmp(ptr, "${HOME}", 7) == 0) { + if (asprintf(&new_name, "%s%s", homedir, ptr + 7) == -1) + errExit("asprintf"); + ptr = new_name; + } + + // expand path macro - look for the file in /bin, /usr/bin, /sbin and /usr/sbin directories + if (strncmp(ptr, "${PATH}", 7) == 0) { + expand_path(op, "/bin", ptr + 7, emptydir, emptyfile); + expand_path(op, "/sbin", ptr + 7, emptydir, emptyfile); + expand_path(op, "/usr/bin", ptr + 7, emptydir, emptyfile); + expand_path(op, "/usr/sbin", ptr + 7, emptydir, emptyfile); + } + else + globbing(op, ptr, emptydir, emptyfile); + + if (new_name) + free(new_name); + entry = entry->next; + } +} + +//*********************************************** +// mount namespace +//*********************************************** + +// remount a directory read-only +void fs_rdonly(const char *dir) { + assert(dir); + // check directory exists + struct stat s; + int rv = stat(dir, &s); + if (rv == 0) { + // mount --bind /bin /bin + if (mount(dir, dir, NULL, MS_BIND|MS_REC, NULL) < 0) + errExit("mount read-only"); + // mount --bind -o remount,ro /bin + if (mount(NULL, dir, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_REC, NULL) < 0) + errExit("mount read-only"); + } +} +void fs_rdonly_noexit(const char *dir) { + assert(dir); + // check directory exists + struct stat s; + int rv = stat(dir, &s); + if (rv == 0) { + int merr = 0; + // mount --bind /bin /bin + if (mount(dir, dir, NULL, MS_BIND|MS_REC, NULL) < 0) + merr = 1; + // mount --bind -o remount,ro /bin + if (mount(NULL, dir, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_REC, NULL) < 0) + merr = 1; + if (merr) + fprintf(stderr, "Warning: cannot mount %s read-only\n", dir); + } +} + +// mount /proc and /sys directories +void fs_proc_sys_dev_boot(void) { + struct stat s; + + if (arg_debug) + printf("Remounting /proc and /proc/sys filesystems\n"); + if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0) + errExit("mounting /proc"); + + // remount /proc/sys readonly + if (mount("/proc/sys", "/proc/sys", NULL, MS_BIND | MS_REC, NULL) < 0) + errExit("mounting /proc/sys"); + + if (mount(NULL, "/proc/sys", NULL, MS_BIND | MS_REMOUNT | MS_RDONLY | MS_REC, NULL) < 0) + errExit("mounting /proc/sys"); + + + /* Mount a version of /sys that describes the network namespace */ + if (arg_debug) + printf("Remounting /sys directory\n"); + if (umount2("/sys", MNT_DETACH) < 0) + fprintf(stderr, "Warning: failed to unmount /sys\n"); + if (mount("sysfs", "/sys", "sysfs", MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REC, NULL) < 0) + fprintf(stderr, "Warning: failed to mount /sys\n"); + +// if (mount("sysfs", "/sys", "sysfs", MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REC, NULL) < 0) +// errExit("mounting /sys"); + + + // mounting firejail kernel module files + if (stat("/proc/firejail-uptime", &s) == 0) { + errno = 0; + FILE *fp = fopen("/proc/firejail", "w"); + int cnt = 0; + while (errno == EBUSY && cnt < 10) { + if (!fp) { + int s = random(); + s /= 200000; + usleep(s); + fp = fopen("/proc/firejail", "w"); + } + else + break; + } + if (!fp) { + fprintf(stderr, "Error: cannot register sandbox with firejail-lkm\n"); + exit(1); + } + if (fp) { + // registration + fprintf(fp, "register\n"); + fflush(0); + // filtering x11 connect calls + if (arg_nox11) { + fprintf(fp, "no connect unix /tmp/.X11\n"); + fflush(0); + printf("X11 access disabled\n"); + } + if (arg_nodbus) { + fprintf(fp, "no connect unix /var/run/dbus/system_bus_socket\n"); + fflush(0); + fprintf(fp, "no connect unix /tmp/dbus\n"); + fflush(0); + printf("D-Bus access disabled\n"); + } + fclose(fp); + if (mount("/proc/firejail-uptime", "/proc/uptime", NULL, MS_BIND|MS_REC, NULL) < 0) + fprintf(stderr, "Warning: cannot mount /proc/firejail-uptime\n"); + } + } + + // Disable SysRq + // a linux box can be shut down easily using the following commands (as root): + // # echo 1 > /proc/sys/kernel/sysrq + // #echo b > /proc/sysrq-trigger + // for more information see https://www.kernel.org/doc/Documentation/sysrq.txt + if (arg_debug) + printf("Disable /proc/sysrq-trigger\n"); + fs_rdonly_noexit("/proc/sysrq-trigger"); + + // disable hotplug and uevent_helper + if (arg_debug) + printf("Disable /proc/sys/kernel/hotplug\n"); + fs_rdonly_noexit("/proc/sys/kernel/hotplug"); + if (arg_debug) + printf("Disable /sys/kernel/uevent_helper\n"); + fs_rdonly_noexit("/sys/kernel/uevent_helper"); + + // read-only /proc/irq and /proc/bus + if (arg_debug) + printf("Disable /proc/irq\n"); + fs_rdonly_noexit("/proc/irq"); + if (arg_debug) + printf("Disable /proc/bus\n"); + fs_rdonly_noexit("/proc/bus"); + + // disable /proc/kcore + disable_file(BLACKLIST_FILE, "/proc/kcore", "not used", "/dev/null"); + + // disable /proc/kallsyms + disable_file(BLACKLIST_FILE, "/proc/kallsyms", "not used", "/dev/null"); + + // disable /boot + if (stat("/boot", &s) == 0) { + if (arg_debug) + printf("Mounting a new /boot directory\n"); + if (mount("tmpfs", "/boot", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) + errExit("mounting /boot directory"); + } + + // disable /dev/port + if (stat("/dev/port", &s) == 0) { + disable_file(BLACKLIST_FILE, "/dev/port", "not used", "/dev/null"); + } +} + +static void sanitize_home(void) { + // extract current /home directory data + struct dirent *dir; + DIR *d = opendir("/home"); + if (d == NULL) + return; + + char *emptydir = create_empty_dir(); + while ((dir = readdir(d))) { + if(strcmp(dir->d_name, "." ) == 0 || strcmp(dir->d_name, ".." ) == 0) + continue; + + if (dir->d_type == DT_DIR ) { + // get properties + struct stat s; + char *name; + if (asprintf(&name, "/home/%s", dir->d_name) == -1) + continue; + if (stat(name, &s) == -1) + continue; + if (S_ISLNK(s.st_mode)) { + free(name); + continue; + } + + if (strcmp(name, cfg.homedir) == 0) + continue; + +// printf("directory %u %u:%u #%s#\n", +// s.st_mode, +// s.st_uid, +// s.st_gid, +// name); + + // disable directory + disable_file(BLACKLIST_FILE, name, emptydir, "not used"); + free(name); + } + } + closedir(d); +} + + + + + + +// build a basic read-only filesystem +void fs_basic_fs(void) { + if (arg_debug) + printf("Mounting read-only /bin, /sbin, /lib, /lib64, /usr, /etc, /var\n"); + fs_rdonly("/bin"); + fs_rdonly("/sbin"); + fs_rdonly("/lib"); + fs_rdonly("/lib64"); + fs_rdonly("/usr"); + fs_rdonly("/etc"); + fs_rdonly("/var"); + + // update /var directory in order to support multiple sandboxes running on the same root directory + if (!arg_private_dev) + fs_dev_shm(); + fs_var_lock(); + fs_var_tmp(); + fs_var_log(); + fs_var_lib(); + fs_var_cache(); + fs_var_utmp(); + + // only in user mode + if (getuid()) + sanitize_home(); +} + + +// mount overlayfs on top of / directory +// mounting an overlay and chrooting into it: +// +// Old Ubuntu kernel +// # cd ~ +// # mkdir -p overlay/root +// # mkdir -p overlay/diff +// # mount -t overlayfs -o lowerdir=/,upperdir=/root/overlay/diff overlayfs /root/overlay/root +// # chroot /root/overlay/root +// to shutdown, first exit the chroot and then unmount the overlay +// # exit +// # umount /root/overlay/root +// +// Kernels 3.18+ +// # cd ~ +// # mkdir -p overlay/root +// # mkdir -p overlay/diff +// # mkdir -p overlay/work +// # mount -t overlay -o lowerdir=/,upperdir=/root/overlay/diff,workdir=/root/overlay/work overlay /root/overlay/root +// # cat /etc/mtab | grep overlay +// /root/overlay /root/overlay/root overlay rw,relatime,lowerdir=/,upperdir=/root/overlay/diff,workdir=/root/overlay/work 0 0 +// # chroot /root/overlay/root +// to shutdown, first exit the chroot and then unmount the overlay +// # exit +// # umount /root/overlay/root + + +// to do: fix the code below; also, it might work without /dev; impose seccomp/caps filters when not root +#include +void fs_overlayfs(void) { + // check kernel version + struct utsname u; + int rv = uname(&u); + if (rv != 0) + errExit("uname"); + int major; + int minor; + if (2 != sscanf(u.release, "%d.%d", &major, &minor)) { + fprintf(stderr, "Error: cannot extract Linux kernel version: %s\n", u.version); + exit(1); + } + + if (arg_debug) + printf("Linux kernel version %d.%d\n", major, minor); + int oldkernel = 0; + if (major < 3) { + fprintf(stderr, "Error: minimum kernel version required 3.x\n"); + exit(1); + } + if (major == 3 && minor < 18) + oldkernel = 1; + + // build overlay directories + fs_build_mnt_dir(); + + char *oroot; + if(asprintf(&oroot, "%s/oroot", MNT_DIR) == -1) + errExit("asprintf"); + if (mkdir(oroot, S_IRWXU | S_IRWXG | S_IRWXO)) + errExit("mkdir"); + if (chown(oroot, 0, 0) < 0) + errExit("chown"); + if (chmod(oroot, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) + errExit("chmod"); + + char *odiff; + if(asprintf(&odiff, "%s/odiff", MNT_DIR) == -1) + errExit("asprintf"); + if (mkdir(odiff, S_IRWXU | S_IRWXG | S_IRWXO)) + errExit("mkdir"); + if (chown(odiff, 0, 0) < 0) + errExit("chown"); + if (chmod(odiff, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) + errExit("chmod"); + + char *owork; + if(asprintf(&owork, "%s/owork", MNT_DIR) == -1) + errExit("asprintf"); + if (mkdir(owork, S_IRWXU | S_IRWXG | S_IRWXO)) + errExit("mkdir"); + if (chown(owork, 0, 0) < 0) + errExit("chown"); + if (chmod(owork, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) + errExit("chmod"); + + // mount overlayfs + if (arg_debug) + printf("Mounting OverlayFS\n"); + char *option; + if (oldkernel) { // old Ubuntu/OpenSUSE kernels + if (asprintf(&option, "lowerdir=/,upperdir=%s", odiff) == -1) + errExit("asprintf"); + if (mount("overlayfs", oroot, "overlayfs", MS_MGC_VAL, option) < 0) + errExit("mounting overlayfs"); + } + else { // kernel 3.18 or newer + if (asprintf(&option, "lowerdir=/,upperdir=%s,workdir=%s", odiff, owork) == -1) + errExit("asprintf"); + if (mount("overlay", oroot, "overlay", MS_MGC_VAL, option) < 0) + errExit("mounting overlayfs"); + } + + // mount-bind dev directory + if (arg_debug) + printf("Mounting /dev\n"); + char *dev; + if (asprintf(&dev, "%s/dev", oroot) == -1) + errExit("asprintf"); + if (mount("/dev", dev, NULL, MS_BIND|MS_REC, NULL) < 0) + errExit("mounting /dev"); + + // chroot in the new filesystem + if (chroot(oroot) == -1) + errExit("chroot"); + // update /var directory in order to support multiple sandboxes running on the same root directory + if (!arg_private_dev) + fs_dev_shm(); + fs_var_lock(); + fs_var_tmp(); + fs_var_log(); + fs_var_lib(); + fs_var_cache(); + fs_var_utmp(); + + // only in user mode + if (getuid()) + sanitize_home(); + + // cleanup and exit + free(option); + free(oroot); + free(odiff); +} + + + +#ifdef HAVE_CHROOT +// return 1 if error +int fs_check_chroot_dir(const char *rootdir) { + assert(rootdir); + struct stat s; + char *name; + + // check /dev + if (asprintf(&name, "%s/dev", rootdir) == -1) + errExit("asprintf"); + if (stat(name, &s) == -1) { + fprintf(stderr, "Error: cannot find /dev in chroot directory\n"); + return 1; + } + free(name); + + // check /var/tmp + if (asprintf(&name, "%s/var/tmp", rootdir) == -1) + errExit("asprintf"); + if (stat(name, &s) == -1) { + fprintf(stderr, "Error: cannot find /var/tmp in chroot directory\n"); + return 1; + } + free(name); + + // check /proc + if (asprintf(&name, "%s/proc", rootdir) == -1) + errExit("asprintf"); + if (stat(name, &s) == -1) { + fprintf(stderr, "Error: cannot find /proc in chroot directory\n"); + return 1; + } + free(name); + + // check /proc + if (asprintf(&name, "%s/tmp", rootdir) == -1) + errExit("asprintf"); + if (stat(name, &s) == -1) { + fprintf(stderr, "Error: cannot find /tmp in chroot directory\n"); + return 1; + } + free(name); + + // check /bin/bash + if (asprintf(&name, "%s/bin/bash", rootdir) == -1) + errExit("asprintf"); + if (stat(name, &s) == -1) { + fprintf(stderr, "Error: cannot find /bin/bash in chroot directory\n"); + return 1; + } + free(name); + + return 0; +} + +// chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf +void fs_chroot(const char *rootdir) { + assert(rootdir); + + //*********************************** + // mount-bind a /dev in rootdir + //*********************************** + // mount /dev + char *newdev; + if (asprintf(&newdev, "%s/dev", rootdir) == -1) + errExit("asprintf"); + if (arg_debug) + printf("Mounting /dev on %s\n", newdev); + if (mount("/dev", newdev, NULL, MS_BIND|MS_REC, NULL) < 0) + errExit("mounting /dev"); + + // some older distros don't have a /run directory + // create one by default + // no exit on error, let the user deal with any problems + char *rundir; + if (asprintf(&rundir, "%s/run", rootdir) == -1) + errExit("asprintf"); + if (!is_dir(rundir)) { + int rv = mkdir(rundir, S_IRWXU | S_IRWXG | S_IRWXO); + (void) rv; + rv = chown(rundir, 0, 0); + (void) rv; + } + + // copy /etc/resolv.conf in chroot directory + // if resolv.conf in chroot is a symbolic link, this will fail + // no exit on error, let the user deal with the problem + char *fname; + if (asprintf(&fname, "%s/etc/resolv.conf", rootdir) == -1) + errExit("asprintf"); + if (arg_debug) + printf("Updating /etc/resolv.conf in %s\n", fname); + if (copy_file("/etc/resolv.conf", fname) == -1) + fprintf(stderr, "Warning: /etc/resolv.conf not initialized\n"); + + // chroot into the new directory + if (arg_debug) + printf("Chrooting into %s\n", rootdir); + if (chroot(rootdir) < 0) + errExit("chroot"); + + // update /var directory in order to support multiple sandboxes running on the same root directory + if (!arg_private_dev) + fs_dev_shm(); + fs_var_lock(); + fs_var_tmp(); + fs_var_log(); + fs_var_lib(); + fs_var_cache(); + fs_var_utmp(); + + // only in user mode + if (getuid()) + sanitize_home(); + +} +#endif + + diff --git a/src/firejail/fs_dev.c b/src/firejail/fs_dev.c new file mode 100644 index 00000000000..80bd1158201 --- /dev/null +++ b/src/firejail/fs_dev.c @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firejail.h" +#include +#include +#include +#include +#include +#include +#include +#ifndef _BSD_SOURCE +#define _BSD_SOURCE +#endif +#include + +static void create_char_dev(const char *path, mode_t mode, int major, int minor) { + dev_t dev = makedev(major, minor); + int rv = mknod(path, S_IFCHR | mode, dev); + if (rv == -1) + goto errexit; + + + if (chmod(path, mode) < 0) + goto errexit; + if (chown(path, 0, 0) < 0) + goto errexit; + + return; + +errexit: + fprintf(stderr, "Error: cannot create %s device\n", path); + exit(1); +} + +static void create_link(const char *oldpath, const char *newpath) { + if (symlink(oldpath, newpath) == -1) + goto errexit; + if (chown(newpath, 0, 0) < 0) + goto errexit; + return; + +errexit: + fprintf(stderr, "Error: cannot create %s device\n", newpath); + exit(1); +} + +void fs_private_dev(void){ + // install a new /dev directory + if (arg_debug) + printf("Mounting tmpfs on /dev\n"); + if (mount("tmpfs", "/dev", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) + errExit("mounting /dev"); + + // create /dev/shm + if (arg_debug) + printf("Create /dev/shm directory\n"); + int rv = mkdir("/dev/shm", S_IRWXU | S_IRWXG | S_IRWXO); + if (rv == -1) + errExit("mkdir"); + if (chown("/dev/shm", 0, 0) < 0) + errExit("chown"); + if (chmod("/dev/shm", S_IRWXU | S_IRWXG | S_IRWXO) < 0) + errExit("chmod"); + + // create devices + create_char_dev("/dev/zero", 0666, 1, 5); // mknod -m 666 /dev/zero c 1 5 + create_char_dev("/dev/null", 0666, 1, 3); // mknod -m 666 /dev/null c 1 3 + create_char_dev("/dev/full", 0666, 1, 7); // mknod -m 666 /dev/full c 1 7 + create_char_dev("/dev/random", 0666, 1, 8); // Mknod -m 666 /dev/random c 1 8 + create_char_dev("/dev/urandom", 0666, 1, 9); // mknod -m 666 /dev/urandom c 1 9 + create_char_dev("/dev/tty", 0666, 5, 0); // mknod -m 666 /dev/tty c 5 0 +#if 0 + create_dev("/dev/tty0", "mknod -m 666 /dev/tty0 c 4 0"); + create_dev("/dev/console", "mknod -m 622 /dev/console c 5 1"); +#endif + + // pseudo-terminal + rv = mkdir("/dev/pts", 0755); + if (rv == -1) + errExit("mkdir"); + if (chown("/dev/pts", 0, 0) < 0) + errExit("chown"); + if (chmod("/dev/pts", 0755) < 0) + errExit("chmod"); + create_char_dev("/dev/pts/ptmx", 0666, 5, 2); //"mknod -m 666 /dev/pts/ptmx c 5 2"); + create_link("/dev/pts/ptmx", "/dev/ptmx"); + // mount -vt devpts -o newinstance -o ptmxmode=0666 devpts //dev/pts + if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL, "newinstance,ptmxmode=0666") < 0) + errExit("mounting /dev/pts"); + +#if 0 + // stdin, stdout, stderr + create_link("/proc/self/fd", "/dev/fd"); + create_link("/proc/self/fd/0", "/dev/stdin"); + create_link("/proc/self/fd/1", "/dev/stdout"); + create_link("/proc/self/fd/2", "/dev/stderr"); +#endif +} + + +void fs_dev_shm(void) { + uid_t uid = getuid(); // set a new shm only if we started as root + if (uid) + return; + + if (is_dir("/dev/shm")) { + if (arg_debug) + printf("Mounting tmpfs on /dev/shm\n"); + if (mount("tmpfs", "/dev/shm", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) + errExit("mounting /dev/shm"); + } + else { + char *lnk = get_link("/dev/shm"); + if (lnk) { + // convert a link such as "../shm" into "/shm" + char *lnk2 = lnk; + int cnt = 0; + while (strncmp(lnk2, "../", 3) == 0) { + cnt++; + lnk2 = lnk2 + 3; + } + if (cnt != 0) + lnk2 = lnk + (cnt - 1) * 3 + 2; + + if (!is_dir(lnk2)) { + // create directory + if (mkdir(lnk2, S_IRWXU|S_IRWXG|S_IRWXO)) + errExit("mkdir"); + if (chown(lnk2, 0, 0)) + errExit("chown"); + if (chmod(lnk2, S_IRWXU|S_IRWXG|S_IRWXO)) + errExit("chmod"); + } + if (arg_debug) + printf("Mounting tmpfs on %s on behalf of /dev/shm\n", lnk2); + if (mount("tmpfs", lnk2, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) + errExit("mounting /var/tmp"); + free(lnk); + } + else { + fprintf(stderr, "Warning: /dev/shm not mounted\n"); + dbg_test_dir("/dev/shm"); + } + + } +} diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c new file mode 100644 index 00000000000..853e3930ba3 --- /dev/null +++ b/src/firejail/fs_home.c @@ -0,0 +1,494 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firejail.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void skel(const char *homedir, uid_t u, gid_t g) { + char *fname; + // zsh + if (arg_zsh) { + // copy skel files + if (asprintf(&fname, "%s/.zshrc", homedir) == -1) + errExit("asprintf"); + struct stat s; + // don't copy it if we already have the file + if (stat(fname, &s) == 0) + return; + if (stat("/etc/skel/.zshrc", &s) == 0) { + if (copy_file("/etc/skel/.zshrc", fname) == 0) { + if (chown(fname, u, g) == -1) + errExit("chown"); + } + } + else { // + FILE *fp = fopen(fname, "w"); + if (fp) { + fprintf(fp, "\n"); + fclose(fp); + if (chown(fname, u, g) == -1) + errExit("chown"); + if (chmod(fname, S_IRUSR | S_IWUSR) < 0) + errExit("chown"); + } + } + free(fname); + } + // csh + else if (arg_csh) { + // copy skel files + if (asprintf(&fname, "%s/.cshrc", homedir) == -1) + errExit("asprintf"); + struct stat s; + // don't copy it if we already have the file + if (stat(fname, &s) == 0) + return; + if (stat("/etc/skel/.cshrc", &s) == 0) { + if (copy_file("/etc/skel/.cshrc", fname) == 0) { + if (chown(fname, u, g) == -1) + errExit("chown"); + } + } + else { // + /* coverity[toctou] */ + FILE *fp = fopen(fname, "w"); + if (fp) { + fprintf(fp, "\n"); + fclose(fp); + if (chown(fname, u, g) == -1) + errExit("chown"); + if (chmod(fname, S_IRUSR | S_IWUSR) < 0) + errExit("chown"); + } + } + free(fname); + } + // bash etc. + else { + // copy skel files + if (asprintf(&fname, "%s/.bashrc", homedir) == -1) + errExit("asprintf"); + struct stat s; + // don't copy it if we already have the file + if (stat(fname, &s) == 0) + return; + if (stat("/etc/skel/.bashrc", &s) == 0) { + if (copy_file("/etc/skel/.bashrc", fname) == 0) { + /* coverity[toctou] */ + if (chown(fname, u, g) == -1) + errExit("chown"); + } + } + free(fname); + } +} + +static int store_xauthority(void) { + // put a copy of .Xauthority in MNT_DIR + fs_build_mnt_dir(); + + char *src; + char *dest; + if (asprintf(&src, "%s/.Xauthority", cfg.homedir) == -1) + errExit("asprintf"); + if (asprintf(&dest, "%s/.Xauthority", MNT_DIR) == -1) + errExit("asprintf"); + + struct stat s; + if (stat(src, &s) == 0) { + int rv = copy_file(src, dest); + if (rv) { + fprintf(stderr, "Warning: cannot transfer .Xauthority in private home directory\n"); + return 0; + } + return 1; // file copied + } + + return 0; +} + +static void copy_xauthority(void) { + // put a copy of .Xauthority in MNT_DIR + fs_build_mnt_dir(); + + char *src; + char *dest; + if (asprintf(&dest, "%s/.Xauthority", cfg.homedir) == -1) + errExit("asprintf"); + if (asprintf(&src, "%s/.Xauthority", MNT_DIR) == -1) + errExit("asprintf"); + int rv = copy_file(src, dest); + if (rv) + fprintf(stderr, "Warning: cannot transfer .Xauthority in private home directory\n"); + + // set permissions and ownership + if (chown(dest, getuid(), getgid()) < 0) + errExit("chown"); + if (chmod(dest, S_IRUSR | S_IWUSR) < 0) + errExit("chmod"); + + // delete the temporary file + unlink(src); +} + +// private mode (--private=homedir): +// mount homedir on top of /home/user, +// tmpfs on top of /root in nonroot mode, +// tmpfs on top of /tmp in root mode, +// set skel files, +// restore .Xauthority +void fs_private_homedir(void) { + char *homedir = cfg.homedir; + char *private_homedir = cfg.home_private; + assert(homedir); + assert(private_homedir); + + int xflag = store_xauthority(); + + uid_t u = getuid(); + gid_t g = getgid(); + struct stat s; + if (stat(homedir, &s) == -1) { + fprintf(stderr, "Error: cannot find user home directory\n"); + exit(1); + } + + + // mount bind private_homedir on top of homedir + if (arg_debug) + printf("Mount-bind %s on top of %s\n", private_homedir, homedir); + if (mount(private_homedir, homedir, NULL, MS_BIND|MS_REC, NULL) < 0) + errExit("mount bind"); +// preserve mode and ownership +// if (chown(homedir, s.st_uid, s.st_gid) == -1) +// errExit("mount-bind chown"); +// if (chmod(homedir, s.st_mode) == -1) +// errExit("mount-bind chmod"); + + if (u != 0) { + // mask /root + if (arg_debug) + printf("Mounting a new /root directory\n"); + if (mount("tmpfs", "/root", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=700,gid=0") < 0) + errExit("mounting home directory"); + } + else { + // mask /home + if (arg_debug) + printf("Mounting a new /home directory\n"); + if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) + errExit("mounting home directory"); + + // mask /tmp only in root mode; KDE keeps all kind of sockets in /tmp! + if (arg_debug) + printf("Mounting a new /tmp directory\n"); + if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) + errExit("mounting tmp directory"); + } + + + skel(homedir, u, g); + if (xflag) + copy_xauthority(); +} + +// private mode (--private): +// mount tmpfs over /home/user, +// tmpfs on top of /root in nonroot mode, +// tmpfs on top of /tmp in root mode +// set skel files, +// restore .Xauthority +void fs_private(void) { + char *homedir = cfg.homedir; + assert(homedir); + uid_t u = getuid(); + gid_t g = getgid(); + + int xflag = store_xauthority(); + + // mask /home + if (arg_debug) + printf("Mounting a new /home directory\n"); + if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) + errExit("mounting home directory"); + + // mask /root + if (arg_debug) + printf("Mounting a new /root directory\n"); + if (mount("tmpfs", "/root", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=700,gid=0") < 0) + errExit("mounting home directory"); + + if (u != 0) { + // create /home/user + if (arg_debug) + printf("Create a new user directory\n"); + int rv = mkdir(homedir, S_IRWXU); + if (rv == -1) + errExit("mkdir"); + if (chown(homedir, u, g) < 0) + errExit("chown"); + } + else { + // mask tmp only in root mode; KDE keeps all kind of sockets in /tmp! + if (arg_debug) + printf("Mounting a new /tmp directory\n"); + if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) + errExit("mounting tmp directory"); + } + + skel(homedir, u, g); + if (xflag) + copy_xauthority(); +} + +static void check_dir_or_file(const char *name) { + assert(name); + struct stat s; + char *fname; + if (asprintf(&fname, "%s/%s", cfg.homedir, name) == -1) + errExit("asprintf"); + if (arg_debug) + printf("***************Checking %s\n", fname); + if (stat(fname, &s) == -1) { + fprintf(stderr, "Error: file %s not found.\n", fname); + exit(1); + } + + // check uid + uid_t uid = getuid(); + gid_t gid = getgid(); + if (s.st_uid != uid || s.st_gid != gid) { + fprintf(stderr, "Error: only files or directories created by the current user are allowed.\n"); + exit(1); + } + + // dir or regular file + if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode)) { + free(fname); + return; + } + + if (!is_link(fname)) { + free(fname); + return; + } + + fprintf(stderr, "Error: invalid file type, %s.\n", fname); + exit(1); +} + +// check directory linst specified by user (--private.keep option) - exit if it fails +void fs_check_home_list(void) { + if (strstr(cfg.home_private_keep, "..")) { + fprintf(stderr, "Error: invalid private.keep list\n"); + exit(1); + } + + char *dlist = strdup(cfg.home_private_keep); + if (!dlist) + errExit("strdup"); + + char *ptr = strtok(dlist, ","); + check_dir_or_file(ptr); + while ((ptr = strtok(NULL, ",")) != NULL) + check_dir_or_file(ptr); + + free(dlist); +} + +// check new private home directory (--private= option) - exit if it fails +void fs_check_private_dir(void) { + // if the directory starts with ~, expand the home directory + if (*cfg.home_private == '~') { + char *tmp; + if (asprintf(&tmp, "%s%s", cfg.homedir, cfg.home_private + 1) == -1) + errExit("asprintf"); + cfg.home_private = tmp; + } + + if (!is_dir(cfg.home_private) || is_link(cfg.home_private) || strstr(cfg.home_private, "..")) { + fprintf(stderr, "Error: invalid private directory\n"); + exit(1); + } + + // check home directory and chroot home directory have the same owner + struct stat s2; + int rv = stat(cfg.home_private, &s2); + if (rv < 0) { + fprintf(stderr, "Error: cannot find %s directory\n", cfg.home_private); + exit(1); + } + + struct stat s1; + rv = stat(cfg.homedir, &s1); + if (rv < 0) { + fprintf(stderr, "Error: cannot find %s directory, full path name required\n", cfg.homedir); + exit(1); + } + if (s1.st_uid != s2.st_uid) { + printf("Error: the two home directories must have the same owner\n"); + exit(1); + } +} + +#if 0 +static int mkpath(char* file_path, mode_t mode) { + assert(file_path && *file_path); + char* p; + for (p=strchr(file_path+1, '/'); p; p=strchr(p+1, '/')) { + *p='\0'; + if (mkdir(file_path, mode)==-1) { + if (errno!=EEXIST) { *p='/'; return -1; } + } + *p='/'; + } + return 0; +} +#endif + +static void duplicate(char *fname) { + char *cmd; + + // copy the file + if (asprintf(&cmd, "cp -a --parents %s/%s %s", cfg.homedir, fname, HOME_DIR) == -1) + errExit("asprintf"); + if (arg_debug) + printf("%s\n", cmd); + if (system(cmd)) + errExit("system cp -a --parents"); + free(cmd); +} + + +// private mode (--private.keep=list): +// mount homedir on top of /home/user, +// tmpfs on top of /root in nonroot mode, +// tmpfs on top of /tmp in root mode, +// set skel files, +// restore .Xauthority +void fs_private_home_list(void) { + char *homedir = cfg.homedir; + char *private_list = cfg.home_private_keep; + assert(homedir); + assert(private_list); + + int xflag = store_xauthority(); + + uid_t u = getuid(); + gid_t g = getgid(); + struct stat s; + if (stat(homedir, &s) == -1) { + fprintf(stderr, "Error: cannot find user home directory\n"); + exit(1); + } + + // create /tmp/firejail/mnt/home directory + fs_build_mnt_dir(); + int rv = mkdir(HOME_DIR, S_IRWXU | S_IRWXG | S_IRWXO); + if (rv == -1) + errExit("mkdir"); + if (chown(HOME_DIR, u, g) < 0) + errExit("chown"); + if (chmod(HOME_DIR, 0755) < 0) + errExit("chmod"); + + // copy the list of files in the new home directory + // using a new child process without root privileges + pid_t child = fork(); + if (child < 0) + errExit("fork"); + if (child == 0) { + if (arg_debug) + printf("Copying files in the new home:\n"); + + // drop privileges + if (setgroups(0, NULL) < 0) + errExit("setgroups"); + if (setgid(getgid()) < 0) + errExit("setgid/getgid"); + if (setuid(getuid()) < 0) + errExit("setuid/getuid"); + + // copy the list of files in the new home directory + char *dlist = strdup(cfg.home_private_keep); + if (!dlist) + errExit("strdup"); + + char *ptr = strtok(dlist, ","); + duplicate(ptr); + + while ((ptr = strtok(NULL, ",")) != NULL) + duplicate(ptr); + free(dlist); + exit(0); + } + // wait for the child to finish + waitpid(child, NULL, 0); + + // mount bind private_homedir on top of homedir + char *newhome; + if (asprintf(&newhome, "%s%s", HOME_DIR, cfg.homedir) == -1) + errExit("asprintf"); + + if (arg_debug) + printf("Mount-bind %s on top of %s\n", newhome, homedir); + if (mount(newhome, homedir, NULL, MS_BIND|MS_REC, NULL) < 0) + errExit("mount bind"); +// preserve mode and ownership +// if (chown(homedir, s.st_uid, s.st_gid) == -1) +// errExit("mount-bind chown"); +// if (chmod(homedir, s.st_mode) == -1) +// errExit("mount-bind chmod"); + + if (u != 0) { + // mask /root + if (arg_debug) + printf("Mounting a new /root directory\n"); + if (mount("tmpfs", "/root", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=700,gid=0") < 0) + errExit("mounting home directory"); + } + else { + // mask /home + if (arg_debug) + printf("Mounting a new /home directory\n"); + if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) + errExit("mounting home directory"); + + // mask /tmp only in root mode; KDE keeps all kind of sockets in /tmp! + if (arg_debug) + printf("Mounting a new /tmp directory\n"); + if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) + errExit("mounting tmp directory"); + } + + skel(homedir, u, g); + if (xflag) + copy_xauthority(); + +} + diff --git a/src/firejail/fs_hostname.c b/src/firejail/fs_hostname.c new file mode 100644 index 00000000000..fb3fc530e7c --- /dev/null +++ b/src/firejail/fs_hostname.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firejail.h" +#include +#include +#include +#include +#include +#include + +void fs_hostname(const char *hostname) { + struct stat s; + fs_build_mnt_dir(); + + // create a new /etc/hostname + if (stat("/etc/hostname", &s) == 0) { + if (arg_debug) + printf("Creating a new /etc/hostname file\n"); + char *fhost; + if (asprintf(&fhost, "%s/hostname", MNT_DIR) == -1) + errExit("asprintf"); + FILE *fp = fopen(fhost, "w"); + if (!fp) { + fprintf(stderr, "Error: cannot create %s\n", fhost); + free(fhost); + exit(1); + } + fprintf(fp, "%s\n", hostname); + fclose(fp); + + // mode and owner + if (chown(fhost, 0, 0) < 0) + errExit("chown"); + if (chmod(fhost, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH ) < 0) + errExit("chmod"); + + // bind-mount the file on top of /etc/hostname + if (mount(fhost, "/etc/hostname", NULL, MS_BIND|MS_REC, NULL) < 0) + errExit("mount bind /etc/hostname"); + free(fhost); + } + + // create a new /etc/hosts + if (stat("/etc/hosts", &s) == 0) { + if (arg_debug) + printf("Creating a new /etc/hosts file\n"); + char *fhost; + if (asprintf(&fhost, "%s/hosts", MNT_DIR) == -1) + errExit("asprintf"); + // copy /etc/host into our new file, and modify it on the fly + /* coverity[toctou] */ + FILE *fp1 = fopen("/etc/hosts", "r"); + if (!fp1) { + fprintf(stderr, "Error: cannot open /etc/hosts\n"); + free(fhost); + exit(1); + } + FILE *fp2 = fopen(fhost, "w"); + if (!fp2) { + fprintf(stderr, "Error: cannot create %s\n", fhost); + free(fhost); + exit(1); + } + + char buf[4096]; + while (fgets(buf, sizeof(buf), fp1)) { + // remove '\n' + char *ptr = strchr(buf, '\n'); + if (ptr) + *ptr = '\0'; + + // copy line + if (strstr(buf, "127.0.0.1")) + fprintf(fp2, "%s %s\n", buf, hostname); + else + fprintf(fp2, "%s\n", buf); + } + fclose(fp1); + fclose(fp2); + + // mode and owner + if (chown(fhost, 0, 0) < 0) + errExit("chown"); + if (chmod(fhost, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH ) < 0) + errExit("chmod"); + + // bind-mount the file on top of /etc/hostname + if (mount(fhost, "/etc/hosts", NULL, MS_BIND|MS_REC, NULL) < 0) + errExit("mount bind /etc/hosts"); + free(fhost); + } +} + +void fs_resolvconf(void) { + if (cfg.dns1 == 0) + return; + + struct stat s; + fs_build_mnt_dir(); + + // create a new /etc/hostname + if (stat("/etc/resolv.conf", &s) == 0) { + if (arg_debug) + printf("Creating a new /etc/resolv.conf file\n"); + char *fname; + if (asprintf(&fname, "%s/resolv.conf", MNT_DIR) == -1) + errExit("asprintf"); + FILE *fp = fopen(fname, "w"); + if (!fp) { + fprintf(stderr, "Error: cannot create %s\n", fname); + free(fname); + exit(1); + } + + if (cfg.dns1) + fprintf(fp, "nameserver %d.%d.%d.%d\n", PRINT_IP(cfg.dns1)); + if (cfg.dns2) + fprintf(fp, "nameserver %d.%d.%d.%d\n", PRINT_IP(cfg.dns2)); + if (cfg.dns3) + fprintf(fp, "nameserver %d.%d.%d.%d\n", PRINT_IP(cfg.dns3)); + fclose(fp); + + // mode and owner + if (chown(fname, 0, 0) < 0) + errExit("chown"); + if (chmod(fname, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH ) < 0) + errExit("chmod"); + + // bind-mount the file on top of /etc/hostname + if (mount(fname, "/etc/resolv.conf", NULL, MS_BIND|MS_REC, NULL) < 0) + errExit("mount bind /etc/resolv.conf"); + free(fname); + } + else { + fprintf(stderr, "Error: cannot set DNS servers, /etc/resolv.conf file is missing\n"); + exit(1); + } +} + + diff --git a/src/firejail/fs_trace.c b/src/firejail/fs_trace.c new file mode 100644 index 00000000000..1c7ef5cbe8e --- /dev/null +++ b/src/firejail/fs_trace.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firejail.h" +#include +#include +#include +#include +#include +#include +#include + +void fs_trace_preload(void) { + struct stat s; + + // create an empty /etc/ld.so.preload + if (stat("/etc/ld.so.preload", &s)) { + if (arg_debug) + printf("Creating an empty /etc/ld.so.preload file\n"); + /* coverity[toctou] */ + FILE *fp = fopen("/etc/ld.so.preload", "w"); + if (!fp) + errExit("fopen"); + fclose(fp); + if (chown("/etc/ld.so.preload", 0, 0) < 0) + errExit("chown"); + if (chmod("/etc/ld.so.preload", S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH ) < 0) + errExit("chmod"); + } +} + +void fs_trace(void) { + // create /tmp/firejail/mnt directory + fs_build_mnt_dir(); + + // create the new ld.so.preload file and mount-bind it + if (arg_debug) + printf("Create the new ld.so.preload file\n"); + char *preload; + if (asprintf(&preload, "%s/ld.so.preload", MNT_DIR) == -1) + errExit("asprintf"); + FILE *fp = fopen(preload, "w"); + if (!fp) + errExit("fopen"); + fprintf(fp, "%s/lib/firejail/libtrace.so\n", PREFIX); + fclose(fp); + if (chown(preload, 0, 0) < 0) + errExit("chown"); + if (chmod(preload, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH ) < 0) + errExit("chmod"); + + // mount the new preload file + if (arg_debug) + printf("Mount the new ld.so.preload file\n"); + if (mount(preload, "/etc/ld.so.preload", NULL, MS_BIND|MS_REC, NULL) < 0) + errExit("mount bind ls.so.preload"); +} + + + \ No newline at end of file diff --git a/src/firejail/fs_var.c b/src/firejail/fs_var.c new file mode 100644 index 00000000000..ee0f81828bc --- /dev/null +++ b/src/firejail/fs_var.c @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firejail.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct dirdata_t{ + struct dirdata_t *next; + char *name; + mode_t st_mode; + uid_t st_uid; + gid_t st_gid; +} DirData; + +static DirData *dirlist = NULL; + +static void release_all(void) { + DirData *ptr = dirlist; + while (ptr) { + DirData *next = ptr->next; + free(ptr->name); + free(ptr); + ptr = next; + } + dirlist = NULL; +} + +static void build_list(const char *srcdir) { + // extract current /var/log directory data + struct dirent *dir; + DIR *d = opendir(srcdir); + if (d == NULL) + return; + + while ((dir = readdir(d))) { + if(strcmp(dir->d_name, "." ) == 0 || strcmp(dir->d_name, ".." ) == 0) + continue; + + if (dir->d_type == DT_DIR ) { + // get properties + struct stat s; + char *name; + if (asprintf(&name, "%s/%s", srcdir, dir->d_name) == -1) + continue; + if (stat(name, &s) == -1) + continue; + if (S_ISLNK(s.st_mode)) { + free(name); + continue; + } + +// printf("directory %u %u:%u %s\n", +// s.st_mode, +// s.st_uid, +// s.st_gid, +// dir->d_name); + + DirData *ptr = malloc(sizeof(DirData)); + if (ptr == NULL) + errExit("malloc"); + memset(ptr, 0, sizeof(DirData)); + ptr->name = name; + ptr->st_mode = s.st_mode; + ptr->st_uid = s.st_uid; + ptr->st_gid = s.st_gid; + ptr->next = dirlist; + dirlist = ptr; + } + } + closedir(d); +} + +static void build_dirs(void) { + // create directories under /var/log + DirData *ptr = dirlist; + while (ptr) { + if (mkdir(ptr->name, ptr->st_mode)) + errExit("mkdir"); + if (chown(ptr->name, ptr->st_uid, ptr->st_gid)) + errExit("chown"); + ptr = ptr->next; + } +} + +void fs_var_log(void) { + build_list("/var/log"); + + // create /var/log if it does't exit + if (is_dir("/var/log")) { + // extract group id for /var/log/wtmp + struct stat s; + gid_t wtmp_group = 0; + if (stat("/var/log/wtmp", &s) == 0) + wtmp_group = s.st_gid; + + // mount a tmpfs on top of /var/log + if (arg_debug) + printf("Mounting tmpfs on /var/log\n"); + if (mount("tmpfs", "/var/log", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) + errExit("mounting /var/log"); + + build_dirs(); + release_all(); + + // create an empty /var/log/wtmp file + /* coverity[toctou] */ + FILE *fp = fopen("/var/log/wtmp", "w"); + if (fp) + fclose(fp); + if (chown("/var/log/wtmp", 0, wtmp_group) < 0) + errExit("chown"); + if (chmod("/var/log/wtmp", S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH ) < 0) + errExit("chmod"); + + // create an empty /var/log/btmp file + fp = fopen("/var/log/btmp", "w"); + if (fp) + fclose(fp); + if (chown("/var/log/btmp", 0, wtmp_group) < 0) + errExit("chown"); + if (chmod("/var/log/btmp", S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP) < 0) + errExit("chmod"); + } + else + fprintf(stderr, "Warning: cannot mount tmpfs in top of /var/log\n"); +} + +void fs_var_lib(void) { + struct stat s; + + // ISC DHCP multiserver + if (stat("/var/lib/dhcp", &s) == 0) { + if (arg_debug) + printf("Mounting tmpfs on /var/lib/dhcp\n"); + if (mount("tmpfs", "/var/lib/dhcp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) + errExit("mounting /var/lib/dhcp"); + + // isc dhcp server requires a /var/lib/dhcp/dhcpd.leases file + FILE *fp = fopen("/var/lib/dhcp/dhcpd.leases", "w"); + + if (fp) { + fprintf(fp, "\n"); + fclose(fp); + if (chown("/var/lib/dhcp/dhcpd.leases", 0, 0) == -1) + errExit("chown"); + if (chmod("/var/lib/dhcp/dhcpd.leases", S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) + errExit("chmod"); + } + } + + // nginx multiserver + if (stat("/var/lib/nginx", &s) == 0) { + if (arg_debug) + printf("Mounting tmpfs on /var/lib/nginx\n"); + if (mount("tmpfs", "/var/lib/nginx", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) + errExit("mounting /var/lib/nginx"); + } + + // net-snmp multiserver + if (stat("/var/lib/snmp", &s) == 0) { + if (arg_debug) + printf("Mounting tmpfs on /var/lib/snmp\n"); + if (mount("tmpfs", "/var/lib/snmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) + errExit("mounting /var/lib/snmp"); + } + + // this is where sudo remembers its state + if (stat("/var/lib/sudo", &s) == 0) { + if (arg_debug) + printf("Mounting tmpfs on /var/lib/sudo\n"); + if (mount("tmpfs", "/var/lib/sudo", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) + errExit("mounting /var/lib/sudo"); + } +} + +void fs_var_cache(void) { + struct stat s; + + if (stat("/var/cache/apache2", &s) == 0) { + if (arg_debug) + printf("Mounting tmpfs on /var/cache/apache2\n"); + if (mount("tmpfs", "/var/cache/apache2", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) + errExit("mounting /var/cahce/apache2"); + } + + if (stat("/var/cache/lighttpd", &s) == 0) { + if (arg_debug) + printf("Mounting tmpfs on /var/cache/lighttpd\n"); + if (mount("tmpfs", "/var/cache/lighttpd", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) + errExit("mounting /var/cache/lighttpd"); + + struct passwd *p = getpwnam("www-data"); + uid_t uid = 0; + gid_t gid = 0; + if (p) { + uid = p->pw_uid; + gid = p->pw_gid; + } + + int rv = mkdir("/var/cache/lighttpd/compress", S_IRWXU | S_IRWXG | S_IRWXO); + if (rv == -1) + errExit("mkdir"); + if (chown("/var/cache/lighttpd/compress", uid, gid) < 0) + errExit("chown"); + + rv = mkdir("/var/cache/lighttpd/uploads", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + if (rv == -1) + errExit("mkdir"); + if (chown("/var/cache/lighttpd/uploads", uid, gid) < 0) + errExit("chown"); + } +} + +void dbg_test_dir(const char *dir) { + if (arg_debug) { + if (is_dir(dir)) + printf("%s is a directory\n", dir); + if (is_link(dir)) { + char *lnk = get_link(dir); + if (lnk) { + printf("%s is a symbolic link to %s\n", dir, lnk); + free(lnk); + } + } + } +} + + +void fs_var_lock(void) { + + if (is_dir("/var/lock")) { + if (arg_debug) + printf("Mounting tmpfs on /var/lock\n"); + if (mount("tmpfs", "/var/lock", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) + errExit("mounting /lock"); + } + else { + char *lnk = get_link("/var/lock"); + if (lnk) { + // convert a link such as "../shm" into "/shm" + char *lnk2 = lnk; + int cnt = 0; + while (strncmp(lnk2, "../", 3) == 0) { + cnt++; + lnk2 = lnk2 + 3; + } + if (cnt != 0) + lnk2 = lnk + (cnt - 1) * 3 + 2; + + if (!is_dir(lnk2)) { + // create directory + if (mkdir(lnk2, S_IRWXU|S_IRWXG|S_IRWXO)) + errExit("mkdir"); + if (chown(lnk2, 0, 0)) + errExit("chown"); + if (chmod(lnk2, S_IRWXU|S_IRWXG|S_IRWXO)) + errExit("chmod"); + } + if (arg_debug) + printf("Mounting tmpfs on %s on behalf of /var/lock\n", lnk2); + if (mount("tmpfs", lnk2, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) + errExit("mounting /var/lock"); + free(lnk); + } + else { + fprintf(stderr, "Warning: /var/lock not mounted\n"); + dbg_test_dir("/var/lock"); + } + } +} + +void fs_var_tmp(void) { + + if (!is_link("/var/tmp")) { + if (arg_debug) + printf("Mounting tmpfs on /var/tmp\n"); + if (mount("tmpfs", "/var/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0) + errExit("mounting /var/tmp"); + } + else { + fprintf(stderr, "Warning: /var/tmp not mounted\n"); + dbg_test_dir("/var/tmp"); + } +} + +void fs_var_utmp(void) { + struct stat s; + + // extract utmp group id + gid_t utmp_group = 0; + if (stat("/var/run/utmp", &s) == 0) + utmp_group = s.st_gid; + else { + fprintf(stderr, "Warning: cannot find /var/run/utmp\n"); + return; + } + + // create /tmp/firejail/mnt directory + fs_build_mnt_dir(); + + // create a new utmp file + if (arg_debug) + printf("Create the new utmp file\n"); + char *utmp; + if (asprintf(&utmp, "%s/utmp", MNT_DIR) == -1) + errExit("asprintf"); + FILE *fp = fopen(utmp, "w"); + if (!fp) + errExit("fopen"); + + // read current utmp + struct utmp *u; + struct utmp u_boot; + setutent(); + while ((u = getutent()) != NULL) { + if (u->ut_type == BOOT_TIME) { + memcpy(&u_boot, u, sizeof(u_boot)); + u_boot.ut_tv.tv_sec = (unsigned) time(NULL); + } + } + endutent(); + + // save new utmp file + fwrite(&u_boot, sizeof(u_boot), 1, fp); + fclose(fp); + if (chown(utmp, 0, utmp_group) < 0) + errExit("chown"); + if (chmod(utmp, S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH ) < 0) + errExit("chmod"); + + // mount the new utmp file + if (arg_debug) + printf("Mount the new utmp file\n"); + if (mount(utmp, "/var/run/utmp", NULL, MS_BIND|MS_REC, NULL) < 0) + errExit("mount bind utmp"); +} + + +#if 0 +Testing servers: + +brctl addbr br0 +ifconfig br0 10.10.20.1/24 + +apt-get install snmpd +insserv -r snmpd +sudo firejail --net=br0 --ip=10.10.20.10 "/etc/init.d/rsyslog start; /etc/init.d/ssh start; /etc/init.d/snmpd start; sleep inf" + +apt-get install apache2 +insserv -r apache2 +sudo firejail --net=br0 --ip=10.10.20.10 "/etc/init.d/rsyslog start; /etc/init.d/ssh start; /etc/init.d/apache2 start; sleep inf" + +apt-get install nginx +insserv -r nginx +sudo firejail --net=br0 --ip=10.10.20.10 "/etc/init.d/rsyslog start; /etc/init.d/ssh start; /etc/init.d/nginx start; sleep inf" + +apt-get install lighttpd +insserv -r lighttpd +sudo firejail --net=br0 --ip=10.10.20.10 "/etc/init.d/rsyslog start; /etc/init.d/ssh start; /etc/init.d/lighttpd start; sleep inf" + +apt-get install isc-dhcp-server +insserv -r isc-dhcp-server +sudo firejail --net=br0 --ip=10.10.20.10 "/etc/init.d/rsyslog start; /etc/init.d/ssh start; /etc/init.d/isc-dhcp-server start; sleep inf" +#endif diff --git a/src/firejail/join.c b/src/firejail/join.c new file mode 100644 index 00000000000..e2d2ca7fce3 --- /dev/null +++ b/src/firejail/join.c @@ -0,0 +1,364 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firejail.h" +#include +#include +#include +#include +#include + +static int apply_caps = 0; +static uint64_t caps = 0; +static int apply_seccomp = 0; +#define BUFLEN 4096 + +static void extract_command(int argc, char **argv, int index) { + if (index >= argc) + return; + + // doubledash followed by positional parameters + if (strcmp(argv[index], "--") == 0) { + arg_doubledash = 1; + index++; + if (index >= argc) + return; + } + + // first argv needs to be a valid command + if (arg_doubledash == 0 && *argv[index] == '-') { + fprintf(stderr, "Error: invalid option %s after --join\n", argv[index]); + exit(1); + } + + + int len = 0; + int i; + // calculate command length + for (i = index; i < argc; i++) { + len += strlen(argv[i]) + 1; + } + assert(len > 0); + + // build command + cfg.command_line = malloc(len + 1); + *cfg.command_line = '\0'; + for (i = index; i < argc; i++) { + strcat(cfg.command_line, argv[i]); + strcat(cfg.command_line, " "); + } + if (arg_debug) + printf("Extracted command #%s#\n", cfg.command_line); +} + +static void extract_nogroups(pid_t pid) { + char *fname; + if (asprintf(&fname, "/proc/%d/root%s/groups", pid, MNT_DIR) == -1) + errExit("asprintf"); + + struct stat s; + if (stat(fname, &s) == -1) + return; + + arg_nogroups = 1; + free(fname); +} + +static void extract_cpu(pid_t pid) { + char *fname; + if (asprintf(&fname, "/proc/%d/root%s/cpu", pid, MNT_DIR) == -1) + errExit("asprintf"); + + struct stat s; + if (stat(fname, &s) == -1) + return; + + // there is a cpu file in MNT_DIR; load the information from the file + load_cpu(fname); + free(fname); +} + +static void extract_cgroup(pid_t pid) { + char *fname; + if (asprintf(&fname, "/proc/%d/root%s/cgroup", pid, MNT_DIR) == -1) + errExit("asprintf"); + + struct stat s; + if (stat(fname, &s) == -1) + return; + + // there is a cgroup file in MNT_DIR; load the information from the file + load_cgroup(fname); + free(fname); +} + +static void extract_caps_seccomp(pid_t pid) { + // open stat file + char *file; + if (asprintf(&file, "/proc/%u/status", pid) == -1) { + perror("asprintf"); + exit(1); + } + FILE *fp = fopen(file, "r"); + if (!fp) { + free(file); + fprintf(stderr, "Error: cannot open stat file for process %u\n", pid); + exit(1); + } + + char buf[BUFLEN]; + while (fgets(buf, BUFLEN - 1, fp)) { + if (strncmp(buf, "Seccomp:", 8) == 0) { + char *ptr = buf + 8; + int val; + sscanf(ptr, "%d", &val); + if (val == 2) + apply_seccomp = 1; + break; + } + else if (strncmp(buf, "CapBnd:", 7) == 0) { + char *ptr = buf + 8; + unsigned long long val; + sscanf(ptr, "%llx", &val); + apply_caps = 1; + caps = val; + } + } + fclose(fp); + free(file); +} + +void extract_user_namespace(pid_t pid) { + // test user namespaces available in the kernel + struct stat s1; + struct stat s2; + struct stat s3; + if (stat("/proc/self/ns/user", &s1) == 0 && + stat("/proc/self/uid_map", &s2) == 0 && + stat("/proc/self/gid_map", &s3) == 0); + else + return; + + // read uid map + char *uidmap; + if (asprintf(&uidmap, "/proc/%u/uid_map", pid) == -1) + errExit("asprintf"); + FILE *fp = fopen(uidmap, "r"); + if (!fp) { + free(uidmap); + return; + } + + // check uid map + int u1; + int u2; + if (fscanf(fp, "%d %d", &u1, &u2) == 2) { + if (arg_debug) + printf("User namespace detected: %s, %d, %d\n", uidmap, u1, u2); + if (u1 != 0 || u2 != 0) + arg_noroot = 1; + } + fclose(fp); + free(uidmap); +} + +void join_name(const char *name, const char *homedir, int argc, char **argv, int index) { + if (!name || strlen(name) == 0) { + fprintf(stderr, "Error: invalid sandbox name\n"); + exit(1); + } + pid_t pid; + if (name2pid(name, &pid)) { + fprintf(stderr, "Error: cannot find sandbox %s\n", name); + exit(1); + } + + join(pid, homedir, argc, argv, index); +} + +void join(pid_t pid, const char *homedir, int argc, char **argv, int index) { + extract_command(argc, argv, index); + + // if the pid is that of a firejail process, use the pid of the first child process + char *comm = pid_proc_comm(pid); + if (comm) { + // remove \n + char *ptr = strchr(comm, '\n'); + if (ptr) + *ptr = '\0'; + if (strcmp(comm, "firejail") == 0) { + pid_t child; + if (find_child(pid, &child) == 0) { + pid = child; + printf("Switching to pid %u, the first child process inside the sandbox\n", (unsigned) pid); + } + } + free(comm); + } + + // check privileges for non-root users + uid_t uid = getuid(); + if (uid != 0) { + struct stat s; + char *dir; + if (asprintf(&dir, "/proc/%u/ns", pid) == -1) + errExit("asprintf"); + if (stat(dir, &s) < 0) + errExit("stat"); + if (s.st_uid != uid) { + fprintf(stderr, "Error: permission is denied to join a sandbox created by a different user.\n"); + exit(1); + } + } + + // in user mode set caps seccomp, cpu, cgroup, etc + if (getuid() != 0) { + extract_caps_seccomp(pid); + extract_cpu(pid); + extract_cgroup(pid); + extract_nogroups(pid); + extract_user_namespace(pid); + } + + // set cgroup + if (cfg.cgroup) + set_cgroup(cfg.cgroup); + + // join namespaces + if (join_namespace(pid, "ipc")) + exit(1); + if (join_namespace(pid, "net")) + exit(1); + if (join_namespace(pid, "pid")) + exit(1); + if (join_namespace(pid, "uts")) + exit(1); + if (join_namespace(pid, "mnt")) + exit(1); + + pid_t child = fork(); + if (child < 0) + errExit("fork"); + if (child == 0) { + // chroot into /proc/PID/root directory + char *rootdir; + if (asprintf(&rootdir, "/proc/%d/root", pid) == -1) + errExit("asprintf"); + + int rv = chroot(rootdir); // this will fail for processes in sandboxes not started with --chroot option + if (rv == 0) + printf("changing root to %s\n", rootdir); + + prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); // kill the child in case the parent died + if (chdir("/") < 0) + errExit("chdir"); + if (homedir) { + struct stat s; + if (stat(homedir, &s) == 0) { + /* coverity[toctou] */ + if (chdir(homedir) < 0) + errExit("chdir"); + } + } + + // set cpu affinity + if (cfg.cpus) + set_cpu_affinity(); + + // set caps filter + if (apply_caps == 1) + caps_set(caps); +#ifdef HAVE_SECCOMP + // set seccomp filter + if (apply_seccomp == 1) + seccomp_set(); +#endif + + // fix qt 4.8 + if (setenv("QT_X11_NO_MITSHM", "1", 1) < 0) + errExit("setenv"); + if (setenv("container", "firejail", 1) < 0) // LXC sets container=lxc, + errExit("setenv"); + + // mount user namespace or drop privileges + if (arg_noroot) { + if (arg_debug) + printf("Joining user namespace\n"); + if (join_namespace(1, "user")) + exit(1); + } + else + drop_privs(arg_nogroups); + + // set prompt color to green + //export PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\] ' + if (setenv("PROMPT_COMMAND", "export PS1=\"\\[\\e[1;32m\\][\\u@\\h \\W]\\$\\[\\e[0m\\] \"", 1) < 0) + errExit("setenv"); + + // run icmdline trough /bin/bash + if (cfg.command_line == NULL) + // replace the process with a regular bash session + execlp("/bin/bash", "/bin/bash", NULL); + else { + // run the command supplied by the user + int cwd = 0; + if (cfg.cwd) { + if (chdir(cfg.cwd) == 0) + cwd = 1; + } + + if (!cwd) { + if (chdir("/") < 0) + errExit("chdir"); + if (cfg.homedir) { + struct stat s; + if (stat(cfg.homedir, &s) == 0) { + if (chdir(cfg.homedir) < 0) + errExit("chdir"); + } + } + } + + char *arg[5]; + arg[0] = "/bin/bash"; + arg[1] = "-c"; + if (arg_debug) + printf("Starting %s\n", cfg.command_line); + if (!arg_doubledash) { + arg[2] = cfg.command_line; + arg[3] = NULL; + } + else { + arg[2] = "--"; + arg[3] = cfg.command_line; + arg[4] = NULL; + } + execvp("/bin/bash", arg); + } + + // it will never get here!!! + } + + // wait for the child to finish + waitpid(child, NULL, 0); + exit(0); +} + + + diff --git a/src/firejail/list.c b/src/firejail/list.c new file mode 100644 index 00000000000..c2c4e801fac --- /dev/null +++ b/src/firejail/list.c @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firejail.h" + +void top(void) { + drop_privs(1); + + char *arg[4]; + arg[0] = "bash"; + arg[1] = "-c"; + arg[2] = "firemon --top"; + arg[3] = NULL; + execvp("/bin/bash", arg); +} + +void netstats(void) { + drop_privs(1); + + char *arg[4]; + arg[0] = "bash"; + arg[1] = "-c"; + arg[2] = "firemon --netstats"; + arg[3] = NULL; + execvp("/bin/bash", arg); +} + +void list(void) { + drop_privs(1); + + char *arg[4]; + arg[0] = "bash"; + arg[1] = "-c"; + arg[2] = "firemon --list"; + arg[3] = NULL; + execvp("/bin/bash", arg); +} + +void tree(void) { + drop_privs(1); + + char *arg[4]; + arg[0] = "bash"; + arg[1] = "-c"; + arg[2] = "firemon --tree"; + arg[3] = NULL; + execvp("/bin/bash", arg); +} + diff --git a/src/firejail/main.c b/src/firejail/main.c new file mode 100644 index 00000000000..78971aa8634 --- /dev/null +++ b/src/firejail/main.c @@ -0,0 +1,1168 @@ +/* + * Copyright (C) 2014, 2015 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include "firejail.h" +#include "../include/pid.h" +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#include +{ +struct tms tm; +clock_t systick = times(&tm); +printf("time %s:%d %u\n", __FILE__, __LINE__, (uint32_t) systick); +} +#endif + +#define STACK_SIZE (1024 * 1024) +static char child_stack[STACK_SIZE]; // space for child's stack +Config cfg; // configuration +int arg_private = 0; // mount private /home and /tmp directoryu +int arg_debug = 0; // print debug messages +int arg_nonetwork = 0; // --net=none +int arg_command = 0; // -c +int arg_overlay = 0; // --overlay +int arg_zsh = 0; // use zsh as default shell +int arg_csh = 0; // use csh as default shell + +int arg_seccomp = 0; // enable default seccomp filter +char *arg_seccomp_list = NULL; // optional seccomp list on top of default filter +char *arg_seccomp_list_drop = NULL; // seccomp drop list +char *arg_seccomp_list_keep = NULL; // seccomp keep list + +int arg_caps_default_filter = 0; // enable default capabilities filter +int arg_caps_drop = 0; // drop list +int arg_caps_drop_all = 0; // drop all capabilities +int arg_caps_keep = 0; // keep list +char *arg_caps_list = NULL; // optional caps list + +int arg_trace = 0; // syscall tracing support +int arg_rlimit_nofile = 0; // rlimit nofile +int arg_rlimit_nproc = 0; // rlimit nproc +int arg_rlimit_fsize = 0; // rlimit fsize +int arg_rlimit_sigpending = 0; // rlimit fsize +int arg_nox11 = 0; // kill the program if x11 unix domain socket is accessed +int arg_nodbus = 0; // kill the program if D-Bus is accessed +int arg_nogroups = 0; // disable supplementary groups +int arg_noroot = 0; // create a new user namespace and disable root user +int arg_netfilter; // enable netfilter +char *arg_netfilter_file = NULL; // netfilter file +int arg_doubledash = 0; // double dash +int arg_shell_none = 0; // run the program directly without a shell +int arg_private_dev = 0; // private dev directory +int arg_scan = 0; // arp-scan all interfaces + +int parent_to_child_fds[2]; +int child_to_parent_fds[2]; + +char *fullargv[MAX_ARGS]; // expanded argv for restricted shell +int fullargc = 0; +static pid_t child = 0; +pid_t sandbox_pid; + +static void myexit(int rv) { + logmsg("exiting..."); + if (!arg_command) + printf("\nparent is shutting down, bye...\n"); + + struct stat s; + if (stat("/proc/firejail", &s) == 0) { + /* coverity[toctou] */ + FILE *fp = fopen("/proc/firejail", "w"); + if (fp) { + // deregistration + fprintf(fp, "release\n"); + fflush(0); + fclose(fp); + } + } + + // delete sandbox files in shared memory + bandwidth_shm_del_file(sandbox_pid); // bandwidht file + network_shm_del_file(sandbox_pid); // network map file + + exit(rv); +} + +static void my_handler(int s){ + printf("\nSignal %d caught, shutting down the child process\n", s); + logsignal(s); + kill(child, SIGKILL); + myexit(1); +} + +static void extract_user_data(void) { + // check suid + if (geteuid()) { + fprintf(stderr, "Error: the sandbox is not setuid root\n"); + exit(1); + } + + struct passwd *pw = getpwuid(getuid()); + if (!pw) + errExit("getpwuid"); + cfg.username = strdup(pw->pw_name); + if (!cfg.username) + errExit("strdup"); + + // build home directory name + cfg.homedir = NULL; + if (pw->pw_dir != NULL) { + cfg.homedir = strdup(pw->pw_dir); + if (!cfg.homedir) + errExit("strdup"); + } + else { + fprintf(stderr, "Error: user %s doesn't have a user directory assigned\n", cfg.username); + exit(1); + } + + cfg.cwd = getcwd(NULL, 0); +} + + + + +static inline Bridge *last_bridge_configured(void) { + if (cfg.bridge3.configured) + return &cfg.bridge3; + else if (cfg.bridge2.configured) + return &cfg.bridge2; + else if (cfg.bridge1.configured) + return &cfg.bridge1; + else if (cfg.bridge0.configured) + return &cfg.bridge0; + else + return NULL; +} + + + +// return 1 if error, 0 if a valid pid was found +static int read_pid(char *str, pid_t *pid) { + char *endptr; + errno = 0; + pid_t pidtmp = strtol(str, &endptr, 10); + if ((errno == ERANGE && (pidtmp == LONG_MAX || pidtmp == LONG_MIN)) + || (errno != 0 && pidtmp == 0)) { + return 1; + } + if (endptr == str) { + return 1; + } + *pid = pidtmp; + return 0; +} + +static void init_cfg(void) { + memset(&cfg, 0, sizeof(cfg)); + + cfg.bridge0.devsandbox = "eth0"; + cfg.bridge1.devsandbox = "eth1"; + cfg.bridge2.devsandbox = "eth2"; + cfg.bridge3.devsandbox = "eth3"; + + extract_user_data(); +} + +static void check_network(Bridge *br) { + assert(br); + if (br->macvlan == 0) // for bridge devices check network range or arp-scan and assign address + net_configure_sandbox_ip(br); + else if (br->ipsandbox) { // for macvlan check network range + char *rv = in_netrange(br->ipsandbox, br->ip, br->mask); + if (rv) { + fprintf(stderr, "%s", rv); + exit(1); + } + } +} + + +void check_user_namespace(void) { + if (getuid() == 0) { + fprintf(stderr, "Error: --noroot option cannot be used when starting the sandbox as root.\n"); + exit(1); + } + + // test user namespaces available in the kernel + struct stat s1; + struct stat s2; + struct stat s3; + if (stat("/proc/self/ns/user", &s1) == 0 && + stat("/proc/self/uid_map", &s2) == 0 && + stat("/proc/self/gid_map", &s3) == 0) + arg_noroot = 1; + else { + fprintf(stderr, "Warning: user namespaces not available in the current kernel.\n"); + arg_noroot = 0; + } +} + +//******************************************* +// Main program +//******************************************* +int main(int argc, char **argv) { + int i; + int prog_index = -1; // index in argv where the program command starts + int lockfd = -1; + int arg_ipc = 0; + int arg_cgroup = 0; + int custom_profile = 0; // custom profile loaded + + // initialize globals + init_cfg(); + cfg.original_argv = argv; + cfg.original_argc = argc; + + + // initialize random number generator + sandbox_pid = getpid(); + time_t t = time(NULL); + srand(t ^ sandbox_pid); + + // check firejail directories + fs_build_firejail_dir(); + shm_create_firejail_dir(); + bandwidth_shm_del_file(sandbox_pid); + + // is this a login shell? + if (*argv[0] == '-') { + fullargc = restricted_shell(cfg.username); + if (fullargc) { + int j; + for (i = 1, j = fullargc; i < argc && j < MAX_ARGS; i++, j++, fullargc++) + fullargv[j] = argv[i]; + + // replace argc/argv with fullargc/fullargv + argv = fullargv; + argc = j; + } + } + else { + // check --output option and execute it; + check_output(argc, argv); // the function will not return if --output option was found + } + + // parse arguments + for (i = 1; i < argc; i++) { + //************************************* + // basic arguments + //************************************* + if (strcmp(argv[i], "--help") == 0 || + strcmp(argv[i], "-?") == 0) { + usage(); + exit(0); + } + else if (strcmp(argv[i], "--version") == 0) { + printf("firejail version %s\n", VERSION); + exit(0); + } + else if (strcmp(argv[i], "--debug") == 0) + arg_debug = 1; + + else if (strncmp(argv[i], "--bandwidth=", 12) == 0) { + logargs(argc, argv); + + // extract the command + if ((i + 1) == argc) { + fprintf(stderr, "Error: command expected after --bandwidth option\n"); + exit(1); + } + char *cmd = argv[i + 1]; + if (strcmp(cmd, "status") && strcmp(cmd, "clear") && strcmp(cmd, "set")) { + fprintf(stderr, "Error: invalid --bandwidth command\n"); + exit(1); + } + + // extract network name + char *dev = NULL; + int down = 0; + int up = 0; + if (strcmp(cmd, "set") == 0 || strcmp(cmd, "clear") == 0) { + // extract device name + if ((i + 2) == argc) { + fprintf(stderr, "Error: network name expected after --bandwidth %s option\n", cmd); + exit(1); + } + dev = argv[i + 2]; + + // check device name + if (if_nametoindex(dev) == 0) { + fprintf(stderr, "Error: network device %s not found\n", dev); + exit(1); + } + + // extract bandwidth + if (strcmp(cmd, "set") == 0) { + if ((i + 4) >= argc) { + fprintf(stderr, "Error: invalid --bandwidth set command\n"); + exit(1); + } + + down = atoi(argv[i + 3]); + if (down < 0) { + fprintf(stderr, "Error: invalid download speed\n"); + exit(1); + } + up = atoi(argv[i + 4]); + if (up < 0) { + fprintf(stderr, "Error: invalid upload speed\n"); + exit(1); + } + } + } + + // extract pid or sandbox name + pid_t pid; + if (read_pid(argv[i] + 12, &pid) == 0) + bandwidth_pid(pid, cmd, dev, down, up); + else + bandwidth_name(argv[i] + 12, cmd, dev, down, up); + + // it will never get here + exit(0); + } + + //************************************* + // independent commands - the program will exit! + //************************************* +#ifdef HAVE_SECCOMP + else if (strcmp(argv[i], "--debug-syscalls") == 0) { + syscall_print(); + exit(0); + } + else if (strncmp(argv[i], "--seccomp.print=", 16) == 0) { + // join sandbox by pid or by name + pid_t pid; + if (read_pid(argv[i] + 16, &pid) == 0) + seccomp_print_filter(pid); + else + seccomp_print_filter_name(argv[i] + 16); + + // it will never get here!!! + exit(0); + } +#endif + else if (strncmp(argv[i], "--caps.print=", 13) == 0) { + // join sandbox by pid or by name + pid_t pid; + if (read_pid(argv[i] + 13, &pid) == 0) + caps_print_filter(pid); + else + caps_print_filter_name(argv[i] + 13); + + // it will never get here!!! + exit(0); + } + + else if (strncmp(argv[i], "--dns.print=", 12) == 0) { + // join sandbox by pid or by name + pid_t pid; + if (read_pid(argv[i] + 12, &pid) == 0) + net_dns_print(pid); + else + net_dns_print_name(argv[i] + 12); + + // it will never get here!!! + exit(0); + } + else if (strcmp(argv[i], "--debug-caps") == 0) { + caps_print(); + exit(0); + } + else if (strcmp(argv[i], "--list") == 0) { + list(); + exit(0); + } + else if (strcmp(argv[i], "--tree") == 0) { + tree(); + exit(0); + } + else if (strcmp(argv[i], "--top") == 0) { + top(); + exit(0); + } + else if (strcmp(argv[i], "--netstats") == 0) { + netstats(); + exit(0); + } + else if (strncmp(argv[i], "--join=", 7) == 0) { + logargs(argc, argv); + + // join sandbox by pid or by name + pid_t pid; + if (read_pid(argv[i] + 7, &pid) == 0) + join(pid, cfg.homedir, argc, argv, i + 1); + else + join_name(argv[i] + 7, cfg.homedir, argc, argv, i + 1); + + // it will never get here!!! + exit(0); + } + else if (strncmp(argv[i], "--shutdown=", 11) == 0) { + logargs(argc, argv); + + // shutdown sandbox by pid or by name + pid_t pid; + if (read_pid(argv[i] + 11, &pid) == 0) + shut(pid); + else + shut_name(argv[i] + 11); + + // it will never get here!!! + exit(0); + } + + //************************************* + // filtering + //************************************* +#ifdef HAVE_SECCOMP + else if (strcmp(argv[i], "--seccomp") == 0) { + if (arg_seccomp) { + fprintf(stderr, "Error: seccomp already enabled\n"); + exit(1); + } + arg_seccomp = 1; + } + else if (strncmp(argv[i], "--seccomp=", 10) == 0) { + if (arg_seccomp) { + fprintf(stderr, "Error: seccomp already enabled\n"); + exit(1); + } + arg_seccomp = 1; + arg_seccomp_list = strdup(argv[i] + 10); + if (!arg_seccomp_list) + errExit("strdup"); + } + else if (strncmp(argv[i], "--seccomp.drop=", 15) == 0) { + if (arg_seccomp) { + fprintf(stderr, "Error: seccomp already enabled\n"); + exit(1); + } + arg_seccomp = 1; + arg_seccomp_list_drop = strdup(argv[i] + 15); + if (!arg_seccomp_list_drop) + errExit("strdup"); + } + else if (strncmp(argv[i], "--seccomp.keep=", 15) == 0) { + if (arg_seccomp) { + fprintf(stderr, "Error: seccomp already enabled\n"); + exit(1); + } + arg_seccomp = 1; + arg_seccomp_list_keep = strdup(argv[i] + 15); + if (!arg_seccomp_list_keep) + errExit("strdup"); + } +#endif + else if (strcmp(argv[i], "--caps") == 0) + arg_caps_default_filter = 1; + else if (strcmp(argv[i], "--caps.drop=all") == 0) + arg_caps_drop_all = 1; + else if (strncmp(argv[i], "--caps.drop=", 12) == 0) { + arg_caps_drop = 1; + arg_caps_list = strdup(argv[i] + 12); + if (!arg_caps_list) + errExit("strdup"); + // verify caps list and exit if problems + if (caps_check_list(arg_caps_list, NULL)) + return 1; + } + else if (strncmp(argv[i], "--caps.keep=", 12) == 0) { + arg_caps_keep = 1; + arg_caps_list = strdup(argv[i] + 12); + if (!arg_caps_list) + errExit("strdup"); + // verify caps list and exit if problems + if (caps_check_list(arg_caps_list, NULL)) + return 1; + } + + + else if (strcmp(argv[i], "--trace") == 0) + arg_trace = 1; + else if (strncmp(argv[i], "--rlimit-nofile=", 16) == 0) { + if (not_unsigned(argv[i] + 16)) { + fprintf(stderr, "Error: invalid rlimt nofile\n"); + exit(1); + } + sscanf(argv[i] + 16, "%u", &cfg.rlimit_nofile); + arg_rlimit_nofile = 1; + } + else if (strncmp(argv[i], "--rlimit-nproc=", 15) == 0) { + if (not_unsigned(argv[i] + 15)) { + fprintf(stderr, "Error: invalid rlimt nproc\n"); + exit(1); + } + sscanf(argv[i] + 15, "%u", &cfg.rlimit_nproc); + arg_rlimit_nproc = 1; + } + else if (strncmp(argv[i], "--rlimit-fsize=", 15) == 0) { + if (not_unsigned(argv[i] + 15)) { + fprintf(stderr, "Error: invalid rlimt fsize\n"); + exit(1); + } + sscanf(argv[i] + 15, "%u", &cfg.rlimit_fsize); + arg_rlimit_fsize = 1; + } + else if (strncmp(argv[i], "--rlimit-sigpending=", 20) == 0) { + if (not_unsigned(argv[i] + 20)) { + fprintf(stderr, "Error: invalid rlimt sigpending\n"); + exit(1); + } + sscanf(argv[i] + 20, "%u", &cfg.rlimit_sigpending); + arg_rlimit_sigpending = 1; + } + else if (strncmp(argv[i], "--ipc-namespace", 15) == 0) + arg_ipc = 1; + else if (strncmp(argv[i], "--cpu=", 6) == 0) + read_cpu_list(argv[i] + 6); + else if (strcmp(argv[i], "--nox11") == 0) { + // check if firejail lkm is present + struct stat s; + if (stat("/proc/firejail", &s) < 0) { + fprintf(stderr, "Error: firejail Linux kernel module not found. The module" + " is required for --nox11 option to work.\n"); + exit(1); + } + arg_nox11 = 1; + } + else if (strcmp(argv[i], "--nodbus") == 0) { + // check if firejail lkm is present + struct stat s; + if (stat("/proc/firejail", &s) < 0) { + fprintf(stderr, "Error: firejail Linux kernel module not found. The module" + " is required for --nodbus option to work.\n"); + exit(1); + } + arg_nodbus = 1; + } + else if (strncmp(argv[i], "--cgroup=", 9) == 0) { + if (arg_cgroup) { + fprintf(stderr, "Error: only a cgroup can be defined\n"); + exit(1); + } + arg_cgroup = 1; + cfg.cgroup = strdup(argv[i] + 9); + if (!cfg.cgroup) + errExit("strdup"); + set_cgroup(cfg.cgroup); + } + + //************************************* + // filesystem + //************************************* +#ifdef HAVE_BIND + else if (strncmp(argv[i], "--bind=", 7) == 0) { + char *line; + if (asprintf(&line, "bind %s", argv[i] + 7) == -1) + errExit("asprintf"); + + profile_check_line(line, 0); // will exit if something wrong + profile_add(line); + } +#endif + else if (strncmp(argv[i], "--tmpfs=", 8) == 0) { + char *line; + if (asprintf(&line, "tmpfs %s", argv[i] + 8) == -1) + errExit("asprintf"); + + profile_check_line(line, 0); // will exit if something wrong + profile_add(line); + } + else if (strncmp(argv[i], "--blacklist=", 12) == 0) { + char *line; + if (asprintf(&line, "blacklist %s", argv[i] + 12) == -1) + errExit("asprintf"); + + profile_check_line(line, 0); // will exit if something wrong + profile_add(line); + } + else if (strncmp(argv[i], "--read-only=", 12) == 0) { + char *line; + if (asprintf(&line, "read-only %s", argv[i] + 12) == -1) + errExit("asprintf"); + + profile_check_line(line, 0); // will exit if something wrong + profile_add(line); + } + else if (strcmp(argv[i], "--overlay") == 0) { + if (cfg.chrootdir) { + fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); + exit(1); + } + arg_overlay = 1; + } + else if (strncmp(argv[i], "--profile=", 10) == 0) { + // multiple profile files are allowed! + char *ptr = argv[i] + 10; + if (is_dir(ptr) || is_link(ptr) || strstr(ptr, "..")) { + fprintf(stderr, "Error: invalid profile file\n"); + exit(1); + } + + // access call checks as real UID/GID, not as effective UID/GID + if (access(argv[i] + 10, R_OK)) { + fprintf(stderr, "Error: cannot access profile file\n"); + return 1; + } + + profile_read(argv[i] + 10, NULL, NULL); + custom_profile = 1; + } +#ifdef HAVE_CHROOT + else if (strncmp(argv[i], "--chroot=", 9) == 0) { + if (arg_overlay) { + fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); + exit(1); + } + + // extract chroot dirname + cfg.chrootdir = argv[i] + 9; + // if the directory starts with ~, expand the home directory + if (*cfg.chrootdir == '~') { + char *tmp; + if (asprintf(&tmp, "%s%s", cfg.homedir, cfg.chrootdir + 1) == -1) + errExit("asprintf"); + cfg.chrootdir = tmp; + } + + // check chroot dirname exists + if (strstr(cfg.chrootdir, "..") || !is_dir(cfg.chrootdir) || is_link(cfg.chrootdir)) { + fprintf(stderr, "Error: invalid directory %s\n", cfg.chrootdir); + return 1; + } + + // check chroot directory structure + if (fs_check_chroot_dir(cfg.chrootdir)) { + fprintf(stderr, "Error: invalid chroot\n"); + exit(1); + } + } +#endif + else if (strcmp(argv[i], "--private") == 0) + arg_private = 1; + else if (strncmp(argv[i], "--private=", 10) == 0) { + if (cfg.home_private_keep) { + fprintf(stderr, "Error: a private list of files was already defined with --private.keep option.\n"); + exit(1); + } + + // extract private home dirname + cfg.home_private = argv[i] + 10; + fs_check_private_dir(); + arg_private = 1; + } + else if (strncmp(argv[i], "--private.keep=", 15) == 0) { + if (cfg.home_private) { + fprintf(stderr, "Error: a private home directory was already defined with --private option.\n"); + exit(1); + } + + // extract private home dirname + cfg.home_private_keep = argv[i] + 15; + fs_check_home_list(); + arg_private = 1; + } + else if (strcmp(argv[i], "--private-dev") == 0) { + arg_private_dev = 1; + } + + + + //************************************* + // hostname, etc + //************************************* + else if (strncmp(argv[i], "--name=", 7) == 0) { + cfg.hostname = argv[i] + 7; + if (strlen(cfg.hostname) == 0) { + fprintf(stderr, "Error: please provide a name for sandbox\n"); + return 1; + } + } + else if (strcmp(argv[i], "--nogroups") == 0) + arg_nogroups = 1; + else if (strcmp(argv[i], "--noroot") == 0) { + check_user_namespace(); + } + + //************************************* + // network + //************************************* + else if (strncmp(argv[i], "--net=", 6) == 0) { + if (strcmp(argv[i] + 6, "none") == 0) { + arg_nonetwork = 1; + cfg.bridge0.configured = 0; + cfg.bridge1.configured = 0; + cfg.bridge2.configured = 0; + cfg.bridge3.configured = 0; + continue; + } + if (strcmp(argv[i] + 6, "lo") == 0) { + fprintf(stderr, "Error: cannot attach to lo device\n"); + exit(1); + } + + Bridge *br; + if (cfg.bridge0.configured == 0) + br = &cfg.bridge0; + else if (cfg.bridge1.configured == 0) + br = &cfg.bridge1; + else if (cfg.bridge2.configured == 0) + br = &cfg.bridge2; + else if (cfg.bridge3.configured == 0) + br = &cfg.bridge3; + else { + fprintf(stderr, "Error: maximum 4 network devices allowed\n"); + return 1; + } + net_configure_bridge(br, argv[i] + 6); + } + else if (strcmp(argv[i], "--scan") == 0) { + arg_scan = 1; + } + else if (strncmp(argv[i], "--iprange=", 10) == 0) { + Bridge *br = last_bridge_configured(); + if (br == NULL) { + fprintf(stderr, "Error: no network device configured\n"); + return 1; + } + if (br->iprange_start || br->iprange_end) { + fprintf(stderr, "Error: cannot configure the IP range twice for the same interface\n"); + return 1; + } + + // parse option arguments + char *firstip = argv[i] + 10; + char *secondip = firstip; + while (*secondip != '\0') { + if (*secondip == ',') + break; + secondip++; + } + if (*secondip == '\0') { + fprintf(stderr, "Error: invalid IP range\n"); + return 1; + } + *secondip = '\0'; + secondip++; + + // check addresses + if (atoip(firstip, &br->iprange_start) || atoip(secondip, &br->iprange_end) || + br->iprange_start >= br->iprange_end) { + fprintf(stderr, "Error: invalid IP range\n"); + return 1; + } + if (in_netrange(br->iprange_start, br->ip, br->mask) || in_netrange(br->iprange_end, br->ip, br->mask)) { + fprintf(stderr, "Error: IP range addresses not in network range\n"); + return 1; + } + } + else if (strncmp(argv[i], "--mac=", 6) == 0) { + Bridge *br = last_bridge_configured(); + if (br == NULL) { + fprintf(stderr, "Error: no network device configured\n"); + return 1; + } + if (mac_not_zero(br->macsandbox)) { + fprintf(stderr, "Error: cannot configure the MAC address twice for the same interface\n"); + return 1; + } + + // read the address + if (atomac(argv[i] + 6, br->macsandbox)) { + fprintf(stderr, "Error: invalid MAC address\n"); + return 1; + } + } + else if (strncmp(argv[i], "--ip=", 5) == 0) { + Bridge *br = last_bridge_configured(); + if (br == NULL) { + fprintf(stderr, "Error: no network device configured\n"); + return 1; + } + if (br->arg_ip_none || br->ipsandbox) { + fprintf(stderr, "Error: cannot configure the IP address twice for the same interface\n"); + return 1; + } + + // configure this IP address for the last bridge defined + if (strcmp(argv[i] + 5, "none") == 0) + br->arg_ip_none = 1; + else { + if (atoip(argv[i] + 5, &br->ipsandbox)) { + fprintf(stderr, "Error: invalid IP address\n"); + return 1; + } + } + } + else if (strncmp(argv[i], "--defaultgw=", 12) == 0) { + if (atoip(argv[i] + 12, &cfg.defaultgw)) { + fprintf(stderr, "Error: invalid IP address\n"); + return 1; + } + } + else if (strncmp(argv[i], "--dns=", 6) == 0) { + uint32_t dns; + if (atoip(argv[i] + 6, &dns)) { + fprintf(stderr, "Error: invalid DNS server IP address\n"); + return 1; + } + + if (cfg.dns1 == 0) + cfg.dns1 = dns; + else if (cfg.dns2 == 0) + cfg.dns2 = dns; + else if (cfg.dns3 == 0) + cfg.dns3 = dns; + else { + fprintf(stderr, "Error: up to 3 DNS servers can be specified\n"); + return 1; + } + } + else if (strcmp(argv[i], "--netfilter") == 0) + arg_netfilter = 1; + else if (strncmp(argv[i], "--netfilter=", 12) == 0) { + arg_netfilter = 1; + arg_netfilter_file = argv[i] + 12; + check_netfilter_file(arg_netfilter_file); + } + + //************************************* + // command + //************************************* + else if (strcmp(argv[i], "--csh") == 0) { + if (arg_shell_none) { + fprintf(stderr, "Error: --shell=none was already specified.\n"); + return 1; + } + if (arg_zsh || cfg.shell ) { + fprintf(stderr, "Error: only one default user shell can be specified\n"); + return 1; + } + arg_csh = 1; + } + else if (strcmp(argv[i], "--zsh") == 0) { + if (arg_shell_none) { + fprintf(stderr, "Error: --shell=none was already specified.\n"); + return 1; + } + if (arg_csh || cfg.shell ) { + fprintf(stderr, "Error: only one default user shell can be specified\n"); + return 1; + } + arg_zsh = 1; + } + else if (strcmp(argv[i], "--shell=none") == 0) { + arg_shell_none = 1; + if (arg_csh || arg_zsh || cfg.shell) { + fprintf(stderr, "Error: a shell was already specified\n"); + return 1; + } + } + else if (strncmp(argv[i], "--shell=", 8) == 0) { + if (arg_shell_none) { + fprintf(stderr, "Error: --shell=none was already specified.\n"); + return 1; + } + if (arg_csh || arg_zsh || cfg.shell) { + fprintf(stderr, "Error: only one user shell can be specified\n"); + return 1; + } + cfg.shell = argv[i] + 8; + + if (is_dir(cfg.shell) || is_link(cfg.shell) || strstr(cfg.shell, "..")) { + fprintf(stderr, "Error: invalid shell\n"); + exit(1); + } + + // access call checks as real UID/GID, not as effective UID/GID + if (access(cfg.shell, R_OK)) { + fprintf(stderr, "Error: cannot access shell file\n"); + exit(1); + } + } + else if (strcmp(argv[i], "-c") == 0) { + arg_command = 1; + if (i == (argc - 1)) { + fprintf(stderr, "Error: option -c requires an argument\n"); + return 1; + } + } + else if (strcmp(argv[i], "--") == 0) { + // double dash - positional params to follow + arg_doubledash = 1; + i++; + if (i >= argc) { + fprintf(stderr, "Error: program name not found\n"); + exit(1); + } + extract_command_name(argv[i]); + prog_index = i; + cfg.original_program_index = i; + break; + } + else { + // is this an invalid option? + if (*argv[i] == '-') { + fprintf(stderr, "Error: invalid %s command line option\n", argv[i]); + return 1; + } + + // we have a program name coming + extract_command_name(argv[i]); + prog_index = i; + cfg.original_program_index = i; + break; + } + } + + // check network configuration options - it will exit if anything went wrong + net_check_cfg(); + + // check user namespace (--noroot) options + if (arg_noroot) { + if (arg_overlay) { + fprintf(stderr, "Error: --overlay and --noroot are mutually exclusive.\n"); + exit(1); + } + else if (cfg.chrootdir) { + fprintf(stderr, "Error: --chroot and --noroot are mutually exclusive.\n"); + exit(1); + } + } + + // log command + logargs(argc, argv); + if (fullargc) { + char *msg; + if (asprintf(&msg, "user %s entering restricted shell", cfg.username) == -1) + errExit("asprintf"); + logmsg(msg); + free(msg); + } + + // build the sandbox command + if (prog_index == -1 && arg_zsh) { + cfg.command_line = "/usr/bin/zsh"; + cfg.command_name = "zsh"; + } + else if (prog_index == -1 && arg_csh) { + cfg.command_line = "/bin/csh"; + cfg.command_name = "csh"; + } + else if (prog_index == -1 && cfg.shell) { + cfg.command_line = cfg.shell; + cfg.command_name = cfg.shell; + } + else if (prog_index == -1) { + cfg.command_line = "/bin/bash"; + cfg.command_name = "bash"; + } + else { + // calculate the length of the command + int i; + int len = 0; + int argcnt = argc - prog_index; + for (i = 0; i < argcnt; i++) + len += strlen(argv[i + prog_index]) + 1; // + ' ' + + // build the string + cfg.command_line = malloc(len + 1); // + '\0' + if (!cfg.command_line) + errExit("malloc"); + char *ptr = cfg.command_line; + for (i = 0; i < argcnt; i++) { + sprintf(ptr, "%s ", argv[i + prog_index]); + ptr += strlen(ptr); + } + } + + // load the profile + { + assert(cfg.command_name); + if (arg_debug) + printf("Command name #%s#\n", cfg.command_name); + if (!custom_profile) { + // look for a profile in ~/.config/firejail directory + char *usercfgdir; + if (asprintf(&usercfgdir, "%s/.config/firejail", cfg.homedir) == -1) + errExit("asprintf"); + int rv = profile_find(cfg.command_name, usercfgdir); + free(usercfgdir); + custom_profile = rv; + } + if (!custom_profile) { + // look for a user profile in /etc/firejail directory + int rv = profile_find(cfg.command_name, "/etc/firejail"); + custom_profile = rv; + } + } + + // check and assign an IP address - for macvlan it will be done again in the sandbox! + if (any_bridge_configured()) { + lockfd = open("/tmp/firejail/firejail.lock", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); + if (lockfd != -1) { + int rv = fchown(lockfd, 0, 0); + (void) rv; + flock(lockfd, LOCK_EX); + } + + check_network(&cfg.bridge0); + check_network(&cfg.bridge1); + check_network(&cfg.bridge2); + check_network(&cfg.bridge3); + + // save network mapping in shared memory + network_shm_set_file(sandbox_pid); + } + + // create the parent-child communication pipe + if (pipe(parent_to_child_fds) < 0) + errExit("pipe"); + if (pipe(child_to_parent_fds) < 0) + errExit("pipe"); + + // clone environment + int flags = CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUTS | SIGCHLD; + + // in root mode also enable CLONE_NEWIPC + // in user mode CLONE_NEWIPC will break MIT Shared Memory Extension (MIT-SHM) + if (getuid() == 0 || arg_ipc) + flags |= CLONE_NEWIPC; + + if (any_bridge_configured() || arg_nonetwork) { + flags |= CLONE_NEWNET; + } + else if (arg_debug) + printf("Using the local network stack\n"); + + child = clone(sandbox, + child_stack + STACK_SIZE, + flags, + NULL); + if (child == -1) + errExit("clone"); + + if (!arg_command) { + printf("Parent pid %u, child pid %u\n", sandbox_pid, child); + // print the path of the new log directory + if (getuid() == 0) // only for root + printf("The new log directory is /proc/%d/root/var/log\n", child); + } + + + + // create veth pair or macvlan device + if (cfg.bridge0.configured && !arg_nonetwork) { + if (cfg.bridge0.macvlan == 0) + net_configure_veth_pair(&cfg.bridge0, "eth0", child); + else + net_create_macvlan(cfg.bridge0.devsandbox, cfg.bridge0.dev, child); + } + + if (cfg.bridge1.configured && !arg_nonetwork) { + if (cfg.bridge1.macvlan == 0) + net_configure_veth_pair(&cfg.bridge1, "eth1", child); + else + net_create_macvlan(cfg.bridge1.devsandbox, cfg.bridge1.dev, child); + } + + if (cfg.bridge2.configured && !arg_nonetwork) { + if (cfg.bridge2.macvlan == 0) + net_configure_veth_pair(&cfg.bridge2, "eth2", child); + else + net_create_macvlan(cfg.bridge2.devsandbox, cfg.bridge2.dev, child); + } + + if (cfg.bridge3.configured && !arg_nonetwork) { + if (cfg.bridge3.macvlan == 0) + net_configure_veth_pair(&cfg.bridge3, "eth3", child); + else + net_create_macvlan(cfg.bridge3.devsandbox, cfg.bridge3.dev, child); + } + + // close each end of the unused pipes + close(parent_to_child_fds[0]); + close(child_to_parent_fds[1]); + + // notify child that base setup is complete + notify_other(parent_to_child_fds[1]); + + // wait for child to create new user namespace with CLONE_NEWUSER + wait_for_other(child_to_parent_fds[0]); + close(child_to_parent_fds[0]); + + if (arg_noroot) { + // update the UID and GID maps in the new child user namespace + // uid + char *map_path; + if (asprintf(&map_path, "/proc/%d/uid_map", child) == -1) + errExit("asprintf"); + char *map; + uid_t uid = getuid(); + if (asprintf(&map, "%d %d 1", uid, uid) == -1) + errExit("asprintf"); + update_map(map, map_path); + free(map); + free(map_path); + + //gid + if (asprintf(&map_path, "/proc/%d/gid_map", child) == -1) + errExit("asprintf"); + gid_t gid = getgid(); + if (asprintf(&map, "%d %d 1", gid, gid) == -1) + errExit("asprintf"); + update_map(map, map_path); + free(map); + free(map_path); + } + + // notify child that UID/GID mapping is complete + notify_other(parent_to_child_fds[1]); + close(parent_to_child_fds[1]); + + if (lockfd != -1) + flock(lockfd, LOCK_UN); + + // handle CTRL-C in parent + signal (SIGINT, my_handler); + signal (SIGTERM, my_handler); + + // wait for the child to finish + waitpid(child, NULL, 0); + myexit(0); + return 0; +} diff --git a/src/firejail/netfilter.c b/src/firejail/netfilter.c new file mode 100644 index 00000000000..dbed4ac3007 --- /dev/null +++ b/src/firejail/netfilter.c @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include "firejail.h" +#include +#include +#include +#include +#include + +static char *client_filter = +"*filter\n" +":INPUT DROP [0:0]\n" +":FORWARD DROP [0:0]\n" +":OUTPUT ACCEPT [0:0]\n" +"-A INPUT -i lo -j ACCEPT\n" +"# echo replay is handled by -m state RELEATED/ESTABLISHED below\n" +"#-A INPUT -p icmp --icmp-type echo-reply -j ACCEPT\n" +"-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n" +"-A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT\n" +"-A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT\n" +"-A INPUT -p icmp --icmp-type echo-request -j ACCEPT \n" +"COMMIT\n"; + +void check_netfilter_file(const char *fname) { + if (is_dir(fname) || is_link(fname) || strstr(fname, "..")) { + fprintf(stderr, "Error: invalid network filter file\n"); + exit(1); + } + + // access call checks as real UID/GID, not as effective UID/GID + if (access(fname, R_OK)) { + fprintf(stderr, "Error: cannot access network filter file\n"); + exit(1); + } +} + + +void netfilter(const char *fname) { + // default filter + char *filter = client_filter; + + // custom filter + int allocated = 0; + if (fname) { + // buffer the filter + struct stat s; + if (stat(fname, &s) == -1) { + fprintf(stderr, "Error: cannot find network filter file\n"); + exit(1); + } + + filter = malloc(s.st_size + 1); // + '\0' + memset(filter, 0, s.st_size + 1); + if (!filter) + errExit("malloc"); + + /* coverity[toctou] */ + FILE *fp = fopen(fname, "r"); + if (!fp) { + fprintf(stderr, "Error: cannot open network filter file\n"); + exit(1); + } + + size_t sz = fread(filter, 1, s.st_size, fp); + if (sz != s.st_size) { + fprintf(stderr, "Error: cannot read network filter file\n"); + exit(1); + } + fclose(fp); + allocated = 1; + } + + // mount a tempfs on top of /tmp directory + if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) + errExit("mounting /tmp"); + + // create the filter file + FILE *fp = fopen("/tmp/netfilter", "w"); + if (!fp) { + fprintf(stderr, "Error: cannot open /tmp/netfilter file\n"); + exit(1); + } + fprintf(fp, "%s\n", filter); + fclose(fp); + + // find iptables command + struct stat s; + char *iptables = NULL; + char *iptables_restore = NULL; + if (stat("/sbin/iptables", &s) == 0) { + iptables = "/sbin/iptables"; + iptables_restore = "/sbin/iptables-restore"; + } + else if (stat("/usr/sbin/iptables", &s) == 0) { + iptables = "/usr/sbin/iptables"; + iptables_restore = "/usr/sbin/iptables-restore"; + } + if (iptables == NULL || iptables_restore == NULL) { + fprintf(stderr, "Error: iptables command not found\n"); + goto doexit; + } + + // push filter + pid_t child = fork(); + if (child < 0) + errExit("fork"); + if (child == 0) { + if (arg_debug) + printf("Installing network filter:\n%s\n", filter); + + int fd; + if((fd = open("/tmp/netfilter", O_RDONLY)) == -1) { + fprintf(stderr,"Error: cannot open /tmp/netfilter\n"); + exit(1); + } + dup2(fd,STDIN_FILENO); + close(fd); + + // wipe out environment variables + environ = NULL; + execl(iptables_restore, iptables_restore, NULL); + // it will never get here!!! + } + // wait for the child to finish + waitpid(child, NULL, 0); + + // debug + if (arg_debug) { + child = fork(); + if (child < 0) + errExit("fork"); + if (child == 0) { + environ = NULL; + execl(iptables, iptables, "-vL", NULL); + // it will never get here!!! + } + // wait for the child to finish + waitpid(child, NULL, 0); + } + +doexit: + // unmount /tmp + umount("/tmp"); + + if (allocated) + free(filter); +} diff --git a/src/firejail/network.c b/src/firejail/network.c new file mode 100644 index 00000000000..6a1d5274468 --- /dev/null +++ b/src/firejail/network.c @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include "firejail.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// scan interfaces in current namespace and print IP address/mask for each interface +void net_ifprint(void) { + uint32_t ip; + uint32_t mask; + struct ifaddrs *ifaddr, *ifa; + + if (getifaddrs(&ifaddr) == -1) + errExit("getifaddrs"); + + printf("%-17.17s%-19.19s%-17.17s%-17.17s%-6.6s\n", + "Interface", "MAC", "IP", "Mask", "Status"); + // walk through the linked list + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) + continue; + + if (ifa->ifa_addr->sa_family == AF_INET) { + struct sockaddr_in *si = (struct sockaddr_in *) ifa->ifa_netmask; + mask = ntohl(si->sin_addr.s_addr); + si = (struct sockaddr_in *) ifa->ifa_addr; + ip = ntohl(si->sin_addr.s_addr); + + // interface status + char *status; + if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP) + status = "UP"; + else + status = "DOWN"; + + // ip address and mask + char ipstr[30]; + sprintf(ipstr, "%d.%d.%d.%d", PRINT_IP(ip)); + char maskstr[30]; + sprintf(maskstr, "%d.%d.%d.%d", PRINT_IP(mask)); + + // mac address + unsigned char mac[6]; + net_get_mac(ifa->ifa_name, mac); + char macstr[30]; + if (strcmp(ifa->ifa_name, "lo") == 0) + macstr[0] = '\0'; + else + sprintf(macstr, "%02x:%02x:%02x:%02x:%02x:%02x", PRINT_MAC(mac)); + + // print + printf("%-17.17s%-19.19s%-17.17s%-17.17s%-6.6s\n", + ifa->ifa_name, macstr, ipstr, maskstr, status); + + // network scanning + if (!arg_scan) // scanning disabled + continue; + if (strcmp(ifa->ifa_name, "lo") == 0) // no loopbabck scanning + continue; + if (mask2bits(mask) < 16) // not scanning large networks + continue; + if (!ip) // if not configured + continue; + // only if the interface is up and running + if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP) + arp_scan(ifa->ifa_name, ip, mask); + } + } + freeifaddrs(ifaddr); +} + + +// return -1 if the interface was not found; if the interface was found retrn 0 and fill in IP address and mask +int net_get_if_addr(const char *bridge, uint32_t *ip, uint32_t *mask, uint8_t mac[6]) { + assert(bridge); + assert(ip); + assert(mask); + int rv = -1; + struct ifaddrs *ifaddr, *ifa; + + if (getifaddrs(&ifaddr) == -1) + errExit("getifaddrs"); + + // walk through the linked list; if the interface is found, extract IP address and mask + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) + continue; + if (strcmp(ifa->ifa_name, bridge) != 0) + continue; + + if (ifa->ifa_addr->sa_family == AF_INET) { + struct sockaddr_in *si = (struct sockaddr_in *) ifa->ifa_netmask; + *mask = ntohl(si->sin_addr.s_addr); + si = (struct sockaddr_in *) ifa->ifa_addr; + *ip = ntohl(si->sin_addr.s_addr); + if (strcmp(ifa->ifa_name, "lo") != 0) + net_get_mac(ifa->ifa_name, mac); + + rv = 0; + break; + } + } + + freeifaddrs(ifaddr); + return rv; +} + +// bring interface up +void net_if_up(const char *ifname) { + if (strlen(ifname) > IFNAMSIZ) { + fprintf(stderr, "Error: invalid network device name %s\n", ifname); + exit(1); + } + + int sock = socket(AF_INET,SOCK_DGRAM,0); + if (sock < 0) + errExit("socket"); + + // get the existing interface flags + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_addr.sa_family = AF_INET; + + // read the existing flags + if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) { + close(sock); + errExit("ioctl"); + } + + ifr.ifr_flags |= IFF_UP; + + // set the new flags + if (ioctl( sock, SIOCSIFFLAGS, &ifr ) < 0) { + close(sock); + errExit("ioctl"); + } + + // checking + // read the existing flags + if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) { + close(sock); + errExit("ioctl"); + } + + // wait not more than 500ms for the interface to come up + int cnt = 0; + while (cnt < 50) { + usleep(10000); // sleep 10ms + + // read the existing flags + if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) { + close(sock); + errExit("ioctl"); + } + if (ifr.ifr_flags & IFF_RUNNING) + break; + cnt++; + } + + close(sock); +} + +// configure interface +void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask) { + if (strlen(ifname) > IFNAMSIZ) { + fprintf(stderr, "Error: invalid network device name %s\n", ifname); + exit(1); + } + + int sock = socket(AF_INET,SOCK_DGRAM,0); + if (sock < 0) + errExit("socket"); + + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_addr.sa_family = AF_INET; + + ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(ip); + if (ioctl( sock, SIOCSIFADDR, &ifr ) < 0) { + close(sock); + errExit("ioctl"); + } + + if (ip != 0) { + ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(mask); + if (ioctl( sock, SIOCSIFNETMASK, &ifr ) < 0) { + close(sock); + errExit("ioctl"); + } + } + + close(sock); + usleep(10000); // sleep 10ms +} + + +// add an IP route, return -1 if error, 0 if the route was added +int net_add_route(uint32_t ip, uint32_t mask, uint32_t gw) { + int sock; + struct rtentry route; + struct sockaddr_in *addr; + int err = 0; + + // create the socket + if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + errExit("socket"); + + memset(&route, 0, sizeof(route)); + + addr = (struct sockaddr_in*) &route.rt_gateway; + addr->sin_family = AF_INET; + addr->sin_addr.s_addr = htonl(gw); + + addr = (struct sockaddr_in*) &route.rt_dst; + addr->sin_family = AF_INET; + addr->sin_addr.s_addr = htonl(ip); + + addr = (struct sockaddr_in*) &route.rt_genmask; + addr->sin_family = AF_INET; + addr->sin_addr.s_addr = htonl(mask); + + route.rt_flags = RTF_UP | RTF_GATEWAY; + route.rt_metric = 0; + if ((err = ioctl(sock, SIOCADDRT, &route)) != 0) { + close(sock); + return -1; + } + + close(sock); + return 0; +} + + +// add a veth device to a bridge +void net_bridge_add_interface(const char *bridge, const char *dev) { + if (strlen(bridge) > IFNAMSIZ) { + fprintf(stderr, "Error: invalid network device name %s\n", bridge); + exit(1); + } + + struct ifreq ifr; + int err; + int ifindex = if_nametoindex(dev); + + if (ifindex <= 0) + errExit("if_nametoindex"); + + int sock; + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + errExit("socket"); + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, bridge, IFNAMSIZ); +#ifdef SIOCBRADDIF + ifr.ifr_ifindex = ifindex; + err = ioctl(sock, SIOCBRADDIF, &ifr); + if (err < 0) +#endif + { + unsigned long args[4] = { BRCTL_ADD_IF, ifindex, 0, 0 }; + + ifr.ifr_data = (char *) args; + err = ioctl(sock, SIOCDEVPRIVATE, &ifr); + } + (void) err; + close(sock); +} + +#define BUFSIZE 1024 +uint32_t network_get_defaultgw(void) { + FILE *fp = fopen("/proc/self/net/route", "r"); + if (!fp) + errExit("fopen"); + + char buf[BUFSIZE]; + uint32_t retval = 0; + while (fgets(buf, BUFSIZE, fp)) { + if (strncmp(buf, "Iface", 5) == 0) + continue; + + char *ptr = buf; + while (*ptr != ' ' && *ptr != '\t') + ptr++; + while (*ptr == ' ' || *ptr == '\t') + ptr++; + + unsigned dest; + unsigned gw; + int rv = sscanf(ptr, "%x %x", &dest, &gw); + if (rv == 2 && dest == 0) { + retval = ntohl(gw); + break; + } + } + + fclose(fp); + return retval; +} + +int net_config_mac(const char *ifname, const unsigned char mac[6]) { + struct ifreq ifr; + int sock; + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + errExit("socket"); + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; + memcpy(ifr.ifr_hwaddr.sa_data, mac, 6); + + if (ioctl(sock, SIOCSIFHWADDR, &ifr) == -1) + errExit("ioctl"); + close(sock); + return 0; +} + +int net_get_mac(const char *ifname, unsigned char mac[6]) { + + struct ifreq ifr; + int sock; + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + errExit("socket"); + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; + + if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) + errExit("ioctl"); + memcpy(mac, ifr.ifr_hwaddr.sa_data, 6); + + close(sock); + return 0; +} diff --git a/src/firejail/network.txt b/src/firejail/network.txt new file mode 100644 index 00000000000..673d5b941a3 --- /dev/null +++ b/src/firejail/network.txt @@ -0,0 +1,95 @@ +struct Bridge { + char *dev; // bridge device name + uint32_t ip; // bridge device IP address + uint32_t mask; // bridge device mask + uint32_t ipsandbox // sandbox interface IP address +} + +net_configure_bridge(br, device) { + br->dev = devname; + br->ip = extracted from kernel device - using net_get_if_addr() in network.c + br->mask = extracted from kernel device - using net_get_if_addr() in network.c + check available network range; /31 networks are not supported +} + +net_configure_sandbox_ip(br) { + if br->ip_snadbox + check br->ipsandbox inside the bridge network + arp_check(br->ipsandbox) // send an arp req to check if anybody else is using this address + else + br->ipsandbox = arp_assign(); +} + +net_configure_veth_pair { + create a veth pair + place one interface end in the bridge + place the other end in the namespace of the child process +} + +net_bridge_wait_ip { + arp_check br->ipsandbox address to come up + wait for not more than 5 seconds +} + +main() { + + foreach argv[i] { + if --net + br = next bridge available + net_configure_bridge(br, device name from argv[i]); + else if --ip + br = last bridge configured + br->ipsandbox = ip address extracted from argv[i] + else if --defaultgw + cfg.defaultgw = ip address extracted from argv[i] + } + + net_check_cfg(); // check the validity of network configuration so far + + if (any bridge configured) { + lock /var/lock/firejail.lock file + for each bridge + net_configure_sandbox_ip(br) + } + + clone (new network namespace if any bridge configured or --net=none) + + if (any bridge configured) { + for each bridge + net_configure_veth_pair + } + + notify child init is done + + if (any bridge configured) { + for each bridge + net_bridge_wait_ip + unlock /var/lock/firejail.lock file + } + + wait on child + exit +} + + +****************************************************** +* macvlan notes +****************************************************** +Configure a macvlan interface + +# ip link add virtual0 link eth0 type macvlan mode bridge +(you can configure it with # ifconfig virtual0 192.168.1.52/24 up) + +Create a new network namespace and move the interface in the new network namespace + +# ip netns add dummy0 +# ip link set virtual0 netns dummy0 + +Join the namespace and configure the interfaces + +# ip netns exec dummy0 bash +# ifconfig lo up +# ifconfig virtual0 192.168.1.52/24 + +Investigate ipvlan interface - added to linux kernel 3.19 +https://github.com/torvalds/linux/blob/master/Documentation/networking/ipvlan.txt diff --git a/src/firejail/network_main.c b/src/firejail/network_main.c new file mode 100644 index 00000000000..c2459b0cd48 --- /dev/null +++ b/src/firejail/network_main.c @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "firejail.h" +#include +#include +#include +#include + +// configure bridge structure +// - extract ip address and mask from the bridge interface +void net_configure_bridge(Bridge *br, char *dev_name) { + assert(br); + assert(dev_name); + + br->dev = dev_name; + + // check the bridge device exists + char sysbridge[30 + strlen(br->dev)]; + sprintf(sysbridge, "/sys/class/net/%s/bridge", br->dev); + struct stat s; + int rv = stat(sysbridge, &s); + if (rv == 0) { + // this is a bridge device + br->macvlan = 0; + } + else { + // is this a regular Ethernet interface + if (if_nametoindex(br->dev) > 0) { + br->macvlan = 1; + char *newname; + if (asprintf(&newname, "%s-%u", br->devsandbox, getpid()) == -1) + errExit("asprintf"); + br->devsandbox = newname; + } + else { + fprintf(stderr, "Error: cannot find network device %s\n", br->dev); + exit(1); + } + } + + if (net_get_if_addr(br->dev, &br->ip, &br->mask, br->mac)) { + fprintf(stderr, "Error: interface %s is not configured\n", br->dev); + exit(1); + } + if (arg_debug) { + if (br->macvlan == 0) + printf("Bridge device %s at %d.%d.%d.%d/%d\n", + br->dev, PRINT_IP(br->ip), mask2bits(br->mask)); + else + printf("macvlan parent device %s at %d.%d.%d.%d/%d\n", + br->dev, PRINT_IP(br->ip), mask2bits(br->mask)); + } + + uint32_t range = ~br->mask + 1; // the number of potential addresses + // this software is not supported for /31 networks + if (range < 4) { + fprintf(stderr, "Error: the software is not supported for /31 networks\n"); + exit(1); + } + br->configured = 1; +} + + +void net_configure_sandbox_ip(Bridge *br) { + assert(br); + if (br->configured == 0) + return; + + if (br->arg_ip_none) + br->ipsandbox = 0; + else if (br->ipsandbox) { + // check network range + char *rv = in_netrange(br->ipsandbox, br->ip, br->mask); + if (rv) { + fprintf(stderr, "%s", rv); + exit(1); + } + // send an ARP request and check if there is anybody on this IP address + if (arp_check(br->dev, br->ipsandbox, br->ip)) { + fprintf(stderr, "Error: IP address %d.%d.%d.%d is already in use\n", PRINT_IP(br->ipsandbox)); + exit(1); + } + } + else + // ip address assigned by arp-scan for a bridge device + br->ipsandbox = arp_assign(br->dev, br); //br->ip, br->mask); +} + + +// create a veth pair +// - br - bridge device +// - ifname - interface name in sandbox namespace +// - child - child process running the namespace + +void net_configure_veth_pair(Bridge *br, const char *ifname, pid_t child) { + assert(br); + if (br->configured == 0) + return; + + // create a veth pair + char *dev; + if (asprintf(&dev, "veth%u%s", getpid(), ifname) < 0) + errExit("asprintf"); + net_create_veth(dev, ifname, child); + + // bring up the interface + net_if_up(dev); + + // add interface to the bridge + net_bridge_add_interface(br->dev, dev); + + char *msg; + if (asprintf(&msg, "%d.%d.%d.%d address assigned to sandbox", PRINT_IP(br->ipsandbox)) == -1) + errExit("asprintf"); + logmsg(msg); + fflush(0); + free(msg); +} + +// the default address should be in the range of at least on of the bridge devices +void check_default_gw(uint32_t defaultgw) { + assert(defaultgw); + + if (cfg.bridge0.configured) { + char *rv = in_netrange(defaultgw, cfg.bridge0.ip, cfg.bridge0.mask); + if (rv == 0) + return; + } + if (cfg.bridge1.configured) { + char *rv = in_netrange(defaultgw, cfg.bridge1.ip, cfg.bridge1.mask); + if (rv == 0) + return; + } + if (cfg.bridge2.configured) { + char *rv = in_netrange(defaultgw, cfg.bridge2.ip, cfg.bridge2.mask); + if (rv == 0) + return; + } + if (cfg.bridge3.configured) { + char *rv = in_netrange(defaultgw, cfg.bridge3.ip, cfg.bridge3.mask); + if (rv == 0) + return; + } + + fprintf(stderr, "Error: default gateway %d.%d.%d.%d is not in the range of any network\n", PRINT_IP(defaultgw)); + exit(1); +} + +void net_check_cfg(void) { + int net_configured = 0; + if (cfg.bridge0.configured) + net_configured++; + if (cfg.bridge1.configured) + net_configured++; + if (cfg.bridge2.configured) + net_configured++; + if (cfg.bridge3.configured) + net_configured++; + + // --defaultgw requires a network + if (cfg.defaultgw && net_configured == 0) { + fprintf(stderr, "Error: option --defaultgw requires at least one network to be configured\n"); + exit(1); + } + + if (net_configured == 0) // nothing to check + return; + + // --net=none + if (arg_nonetwork && net_configured) { + fprintf(stderr, "Error: --net and --net=none are mutually exclusive\n"); + exit(1); + } + + // check default gateway address or assign one + assert(cfg.bridge0.configured); + if (cfg.defaultgw) + check_default_gw(cfg.defaultgw); + else { + // first network is a regular bridge + if (cfg.bridge0.macvlan == 0) + cfg.defaultgw = cfg.bridge0.ip; + // first network is a mac device + else { + // get the host default gw + uint32_t gw = network_get_defaultgw(); + // check the gateway is network range + if (in_netrange(gw, cfg.bridge0.ip, cfg.bridge0.mask)) + gw = 0; + cfg.defaultgw = gw; + } + } +} + + + +void net_dns_print_name(const char *name) { + if (!name || strlen(name) == 0) { + fprintf(stderr, "Error: invalid sandbox name\n"); + exit(1); + } + pid_t pid; + if (name2pid(name, &pid)) { + fprintf(stderr, "Error: cannot find sandbox %s\n", name); + exit(1); + } + + net_dns_print(pid); +} + +#define MAXBUF 4096 +void net_dns_print(pid_t pid) { + // drop privileges - will not be able to read /etc/resolv.conf for --noroot option +// drop_privs(1); + + // if the pid is that of a firejail process, use the pid of the first child process + char *comm = pid_proc_comm(pid); + if (comm) { + // remove \n + char *ptr = strchr(comm, '\n'); + if (ptr) + *ptr = '\0'; + if (strcmp(comm, "firejail") == 0) { + pid_t child; + if (find_child(pid, &child) == 0) { + pid = child; + } + } + free(comm); + } + + char *fname; + if (asprintf(&fname, "/proc/%d/root/etc/resolv.conf", pid) == -1) + errExit("asprintf"); + + // access /etc/resolv.conf + FILE *fp = fopen(fname, "r"); + if (!fp) { + fprintf(stderr, "Error: cannot access /etc/resolv.conf\n"); + exit(1); + } + + char buf[MAXBUF]; + while (fgets(buf, MAXBUF, fp)) + printf("%s", buf); + printf("\n"); + fclose(fp); + free(fname); + exit(0); +} diff --git a/src/firejail/output.c b/src/firejail/output.c new file mode 100644 index 00000000000..32adac10845 --- /dev/null +++ b/src/firejail/output.c @@ -0,0 +1,84 @@ +#include "firejail.h" +#include +#include +#include + +void check_output(int argc, char **argv) { + int i; + char *outfile = NULL; +// drop_privs(0); + + int found = 0; + for (i = 1; i < argc; i++) { + if (strncmp(argv[i], "--output=", 9) == 0) { + found = 1; + outfile = argv[i] + 9; + + // do not accept directories, links, and files with ".." + if (strstr(outfile, "..") || is_link(outfile) || is_dir(outfile)) { + fprintf(stderr, "Error: invalid output file. Links, directories and files with \"..\" are not allowed.\n"); + exit(1); + } + + struct stat s; + if (stat(outfile, &s) == 0) { + // check permissions + if (s.st_uid != getuid() || s.st_gid != getgid()) { + fprintf(stderr, "Error: the output file needs to be owned by the current user.\n"); + exit(1); + } + + // check hard links + if (s.st_nlink != 1) { + fprintf(stderr, "Error: no hard links allowed.\n"); + exit(1); + } + } + + // drop privileges and try to open the file for writing + drop_privs(0); + /* coverity[toctou] */ + FILE *fp = fopen(outfile, "a"); + if (!fp) { + fprintf(stderr, "Error: cannot open output file %s\n", outfile); + exit(1); + } + fclose(fp); + break; + } + } + if (!found) + return; + + + // build the new command line + int len = 0; + for (i = 0; i < argc; i++) { + len += strlen(argv[i]) + 1; // + ' ' + } + len += 50 + strlen(outfile); // tee command + + char *cmd = malloc(len + 1); // + '\0' + if (!cmd) + errExit("malloc"); + + char *ptr = cmd; + for (i = 0; i < argc; i++) { + if (strncmp(argv[i], "--output=", 9) == 0) + continue; + ptr += sprintf(ptr, "%s ", argv[i]); + } + sprintf(ptr, "| %s/lib/firejail/ftee %s", PREFIX, outfile); + + // run command + char *a[4]; + a[0] = "/bin/bash"; + a[1] = "-c"; + a[2] = cmd; + a[3] = NULL; + + execvp(a[0], a); + + perror("execvp"); + exit(1); +} diff --git a/src/firejail/profile.c b/src/firejail/profile.c new file mode 100644 index 00000000000..343907584ea --- /dev/null +++ b/src/firejail/profile.c @@ -0,0 +1,444 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firejail.h" +#include +#include + +#define MAX_READ 8192 // line buffer for profile files + +// find and read the profile specified by name from dir directory +int profile_find(const char *name, const char *dir) { + assert(name); + assert(dir); + + int rv = 0; + DIR *dp; + char *pname; + if (asprintf(&pname, "%s.profile", name) == -1) + errExit("asprintf"); + + dp = opendir (dir); + if (dp != NULL) { + struct dirent *ep; + while ((ep = readdir(dp)) != NULL) { + if (strcmp(ep->d_name, pname) == 0) { + if (arg_debug) + printf("Found %s profile in %s directory\n", name, dir); + char *etcpname; + if (asprintf(&etcpname, "%s/%s", dir, pname) == -1) + errExit("asprintf"); + profile_read(etcpname, NULL, NULL); + free(etcpname); + rv = 1; + break; + } + } + (void) closedir (dp); + } + + free(pname); + return rv; +} + + +//*************************************************** +// run-time profiles +//*************************************************** +static void check_file_name(char *ptr, int lineno) { + if (strncmp(ptr, "${HOME}", 7) == 0) + ptr += 7; + else if (strncmp(ptr, "${PATH}", 7) == 0) + ptr += 7; + + int len = strlen(ptr); + // file globbing ('*') is allowed + if (strcspn(ptr, "\\&!?\"'<>%^(){}[];, ") != len) { + if (lineno == 0) + fprintf(stderr, "Error: \"%s\" is an invalid filename\n", ptr); + else + fprintf(stderr, "Error: line %d in the custom profile is invalid\n", lineno); + exit(1); + } +} + + +// check profile line; if line == 0, this was generated from a command line option +// return 1 if the command is to be added to the linked list of profile commands +// return 0 if the command was already executed inside the function +int profile_check_line(char *ptr, int lineno) { + // seccomp, caps, private, user namespace + if (strcmp(ptr, "noroot") == 0) { + check_user_namespace(); + return 0; + } + else if (strcmp(ptr, "seccomp") == 0) { + arg_seccomp = 1; + return 0; + } + else if (strcmp(ptr, "caps") == 0) { + arg_caps_default_filter = 1; + return 0; + } + else if (strcmp(ptr, "caps.drop all") == 0) { + arg_caps_drop_all = 1; + return 0; + } + else if (strcmp(ptr, "shell none") == 0) { + arg_shell_none = 1; + return 0; + } + else if (strcmp(ptr, "private") == 0) { + arg_private = 1; + return 0; + } + else if (strcmp(ptr, "private-dev") == 0) { + arg_private_dev = 1; + return 0; + } + else if (strcmp(ptr, "nogroups") == 0) { + arg_nogroups = 1; + return 0; + } + else if (strcmp(ptr, "netfilter") == 0) { + arg_netfilter = 1; + return 0; + } + else if (strncmp(ptr, "netfilter ", 10) == 0) { + arg_netfilter = 1; + arg_netfilter_file = strdup(ptr + 10); + if (!arg_netfilter_file) + errExit("strdup"); + check_netfilter_file(arg_netfilter_file); + return 0; + } + + // seccomp drop list on top of default list + if (strncmp(ptr, "seccomp ", 8) == 0) { + arg_seccomp = 1; +#ifdef HAVE_SECCOMP + arg_seccomp_list = strdup(ptr + 8); + if (!arg_seccomp_list) + errExit("strdup"); +#endif + return 0; + } + + // seccomp drop list without default list + if (strncmp(ptr, "seccomp.drop ", 13) == 0) { + arg_seccomp = 1; +#ifdef HAVE_SECCOMP + arg_seccomp_list_drop = strdup(ptr + 13); + if (!arg_seccomp_list_drop) + errExit("strdup"); +#endif + return 0; + } + + // seccomp keep list + if (strncmp(ptr, "seccomp.keep ", 13) == 0) { + arg_seccomp = 1; +#ifdef HAVE_SECCOMP + arg_seccomp_list_keep= strdup(ptr + 13); + if (!arg_seccomp_list_keep) + errExit("strdup"); +#endif + return 0; + } + + // caps drop list + if (strncmp(ptr, "caps.drop ", 10) == 0) { + arg_caps_drop = 1; + arg_caps_list = strdup(ptr + 10); + if (!arg_caps_list) + errExit("strdup"); + // verify seccomp list and exit if problems + if (caps_check_list(arg_caps_list, NULL)) + exit(1); + return 0; + } + + // caps keep list + if (strncmp(ptr, "caps.keep ", 10) == 0) { + arg_caps_keep = 1; + arg_caps_list = strdup(ptr + 10); + if (!arg_caps_list) + errExit("strdup"); + // verify seccomp list and exit if problems + if (caps_check_list(arg_caps_list, NULL)) + exit(1); + return 0; + } + + // dns + if (strncmp(ptr, "dns ", 4) == 0) { + uint32_t dns; + if (atoip(ptr + 4, &dns)) { + fprintf(stderr, "Error: invalid DNS server IP address\n"); + return 1; + } + + if (cfg.dns1 == 0) + cfg.dns1 = dns; + else if (cfg.dns2 == 0) + cfg.dns2 = dns; + else if (cfg.dns3 == 0) + cfg.dns3 = dns; + else { + fprintf(stderr, "Error: up to 3 DNS servers can be specified\n"); + return 1; + } + return 0; + } + + // cpu affinity + if (strncmp(ptr, "cpu ", 4) == 0) { + read_cpu_list(ptr + 4); + return 0; + } + + // cgroup + if (strncmp(ptr, "cgroup ", 7) == 0) { + set_cgroup(ptr + 7); + return 0; + } + + // private directory + if (strncmp(ptr, "private ", 8) == 0) { + cfg.home_private = ptr + 8; + fs_check_private_dir(); + arg_private = 1; + return 0; + } + + // private list of files and directories + if (strncmp(ptr, "private.keep ", 13) == 0) { + cfg.home_private_keep = ptr + 13; + fs_check_home_list(); + arg_private = 1; + return 0; + } + + // filesystem bind + if (strncmp(ptr, "bind ", 5) == 0) { + if (getuid() != 0) { + fprintf(stderr, "Error: --bind option is available only if running as root\n"); + exit(1); + } + + // extract two directories + char *dname1 = ptr + 5; + char *dname2 = split_comma(dname1); // this inserts a '0 to separate the two dierctories + if (dname2 == NULL) { + fprintf(stderr, "Error: mising second directory for bind\n"); + exit(1); + } + + // check directories + check_file_name(dname1, lineno); + check_file_name(dname2, lineno); + if (strstr(dname1, "..") || strstr(dname2, "..")) { + fprintf(stderr, "Error: invalid file name.\n"); + exit(1); + } + + // insert comma back + *(dname2 - 1) = ','; + return 1; + } + + // rlimit + if (strncmp(ptr, "rlimit", 6) == 0) { + if (strncmp(ptr, "rlimit-nofile ", 14) == 0) { + ptr += 14; + if (not_unsigned(ptr)) { + fprintf(stderr, "Invalid rlimit option on line %d\n", lineno); + exit(1); + } + sscanf(ptr, "%u", &cfg.rlimit_nofile); + arg_rlimit_nofile = 1; + } + else if (strncmp(ptr, "rlimit-nproc ", 13) == 0) { + ptr += 13; + if (not_unsigned(ptr)) { + fprintf(stderr, "Invalid rlimit option on line %d\n", lineno); + exit(1); + } + sscanf(ptr, "%u", &cfg.rlimit_nproc); + arg_rlimit_nproc = 1; + } + else if (strncmp(ptr, "rlimit-fsize ", 13) == 0) { + ptr += 13; + if (not_unsigned(ptr)) { + fprintf(stderr, "Invalid rlimit option on line %d\n", lineno); + exit(1); + } + sscanf(ptr, "%u", &cfg.rlimit_fsize); + arg_rlimit_fsize = 1; + } + else if (strncmp(ptr, "rlimit-sigpending ", 18) == 0) { + ptr += 18; + if (not_unsigned(ptr)) { + fprintf(stderr, "Invalid rlimit option on line %d\n", lineno); + exit(1); + } + sscanf(ptr, "%u", &cfg.rlimit_sigpending); + arg_rlimit_sigpending = 1; + } + else { + fprintf(stderr, "Invalid rlimit option on line %d\n", lineno); + exit(1); + } + + return 0; + } + + // rest of filesystem + if (strncmp(ptr, "blacklist ", 10) == 0) + ptr += 10; + else if (strncmp(ptr, "read-only ", 10) == 0) + ptr += 10; + else if (strncmp(ptr, "tmpfs ", 6) == 0) + ptr += 6; + else { + if (lineno == 0) + fprintf(stderr, "Error: \"%s\" as a command line option is invalid\n", ptr); + else + fprintf(stderr, "Error: line %d in the custom profile is invalid\n", lineno); + exit(1); + } + + // some characters just don't belong in filenames + check_file_name(ptr, lineno); + if (strstr(ptr, "..")) { + if (lineno == 0) + fprintf(stderr, "Error: \"%s\" is an invalid filename\n", ptr); + else + fprintf(stderr, "Error: line %d in the custom profile is invalid\n", lineno); + exit(1); + } + return 1; +} + +// add a profile entry in cfg.profile list; use str to populate the list +void profile_add(char *str) { + ProfileEntry *prf = malloc(sizeof(ProfileEntry)); + if (!prf) + errExit("malloc"); + prf->next = NULL; + prf->data = str; + + // add prf to the list + if (cfg.profile == NULL) { + cfg.profile = prf; + return; + } + ProfileEntry *ptr = cfg.profile; + while (ptr->next != NULL) + ptr = ptr->next; + ptr->next = prf; +} + +// read a profile file +static int include_level = 0; +// skip1, skip2 - if the string is found in the line, the line is not interpreted +void profile_read(const char *fname, const char *skip1, const char *skip2) { + // exit program if maximum include level was reached + if (include_level > MAX_INCLUDE_LEVEL) { + fprintf(stderr, "Error: maximum profile include level was reached\n"); + exit(1); + } + + if (strlen(fname) == 0) { + fprintf(stderr, "Error: invalid profile file\n"); + exit(1); + } + + // open profile file: + FILE *fp = fopen(fname, "r"); + if (fp == NULL) { + fprintf(stderr, "Error: cannot open profile file\n"); + exit(1); + } + + fprintf(stderr, "Reading profile %s\n", fname); + + // read the file line by line + char buf[MAX_READ + 1]; + int lineno = 0; + while (fgets(buf, MAX_READ, fp)) { + ++lineno; + // remove empty space - ptr in allocated memory + char *ptr = line_remove_spaces(buf); + if (ptr == NULL) + continue; + + // comments + if (*ptr == '#' || *ptr == '\0') { + free(ptr); + continue; + } + + // process include + if (strncmp(ptr, "include ", 8) == 0) { + include_level++; + + // extract profile filename and new skip params + char *newprofile = ptr + 8; // profile name + char *newskip1 = NULL; // new skip1 + char *newskip2 = NULL; // new skip2 + char *p = newprofile; + while (*p != '\0') { + if (*p == ' ') { + *p = '\0'; + if (newskip1 == NULL) + newskip1 = p + 1; + else if (newskip2 == NULL) + newskip2 = p + 1; + } + p++; + } + + // recursivity + profile_read(newprofile, newskip1, newskip2); + include_level--; + free(ptr); + continue; + } + + // skip + if (skip1) { + if (strstr(ptr, skip1)) { + free(ptr); + continue; + } + } + if (skip2) { + if (strstr(ptr, skip2)) { + free(ptr); + continue; + } + } + + // verify syntax, exit in case of error + if (profile_check_line(ptr, lineno)) + profile_add(ptr); + } + fclose(fp); +} diff --git a/src/firejail/restricted_shell.c b/src/firejail/restricted_shell.c new file mode 100644 index 00000000000..ba3aae759a3 --- /dev/null +++ b/src/firejail/restricted_shell.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firejail.h" + +#define MAX_READ 4096 // maximum line length +char *restricted_user = NULL; + + +int restricted_shell(const char *user) { + assert(user); + + // open profile file: + FILE *fp = fopen("/etc/firejail/login.users", "r"); + if (fp == NULL) + return 0; + + int lineno = 0; + char buf[MAX_READ]; + while (fgets(buf, MAX_READ, fp)) { + lineno++; + + // remove empty spaces at the beginning of the line + char *ptr = buf; + while (*ptr == ' ' || *ptr == '\t') { + ptr++; + } + if (*ptr == '\n' || *ptr == '#') + continue; + + // parse line + char *usr = ptr; + char *args = strchr(usr, ':'); + if (args == NULL) { + fprintf(stderr, "Error: users.conf line %d\n", lineno); + exit(1); + } + *args = '\0'; + args++; + ptr = strchr(args, '\n'); + if (ptr) + *ptr = '\0'; + + if (strcmp(user, usr) == 0) { + restricted_user = strdup(user); + // extract program arguments + + fullargv[0] = "firejail"; + int i; + ptr = args; + for (i = 1; i < MAX_ARGS; i++) { + fullargv[i] = ptr; + while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0') + ptr++; + if (*ptr != '\0') { + *ptr ='\0'; + fullargv[i] = strdup(fullargv[i]); + if (fullargv[i] == NULL) { + fprintf(stderr, "Error: cannot allocate memory\n"); + exit(1); + } + ptr++; + while (*ptr == ' ' || *ptr == '\t') + ptr++; + if (*ptr != '\0') + continue; + } + fullargv[i] = strdup(fullargv[i]); + fclose(fp); + return i + 1; + } + fprintf(stderr, "Error: too many program arguments in users.conf line %d\n", lineno); + exit(1); + } + } + fclose(fp); + + return 0; +} + diff --git a/src/firejail/rlimit.c b/src/firejail/rlimit.c new file mode 100644 index 00000000000..6c755a08d1c --- /dev/null +++ b/src/firejail/rlimit.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firejail.h" +#include +#include + +void set_rlimits(void) { + // resource limits + struct rlimit rl; + if (arg_rlimit_nofile) { + rl.rlim_cur = (rlim_t) cfg.rlimit_nofile; + rl.rlim_max = (rlim_t) cfg.rlimit_nofile; + if (setrlimit(RLIMIT_NOFILE, &rl) == -1) + errExit("setrlimit"); + if (arg_debug) + printf("Config rlimit: number of open file descriptors %u\n", cfg.rlimit_nofile); + } + + if (arg_rlimit_nproc) { + rl.rlim_cur = (rlim_t) cfg.rlimit_nproc; + rl.rlim_max = (rlim_t) cfg.rlimit_nproc; + if (setrlimit(RLIMIT_NPROC, &rl) == -1) + errExit("setrlimit"); + if (arg_debug) + printf("Config rlimit: number of processes %u\n", cfg.rlimit_nproc); + } + + if (arg_rlimit_fsize) { + rl.rlim_cur = (rlim_t) cfg.rlimit_fsize; + rl.rlim_max = (rlim_t) cfg.rlimit_fsize; + if (setrlimit(RLIMIT_FSIZE, &rl) == -1) + errExit("setrlimit"); + if (arg_debug) + printf("Config rlimit: maximum file size %u\n", cfg.rlimit_fsize); + } + + if (arg_rlimit_sigpending) { + rl.rlim_cur = (rlim_t) cfg.rlimit_sigpending; + rl.rlim_max = (rlim_t) cfg.rlimit_sigpending; + if (setrlimit(RLIMIT_SIGPENDING, &rl) == -1) + errExit("setrlimit"); + if (arg_debug) + printf("Config rlimit: maximum number of signals pending %u\n", cfg.rlimit_sigpending); + } +} diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c new file mode 100644 index 00000000000..3f5fb51fa7b --- /dev/null +++ b/src/firejail/sandbox.c @@ -0,0 +1,490 @@ +/* + * Copyright (C) 2014, 2015 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "firejail.h" +#include +#include +#include +#include +#include +#include + +#include +#ifndef CLONE_NEWUSER +#define CLONE_NEWUSER 0x10000000 +#endif + +static void set_caps(void) { + if (arg_caps_drop_all) + caps_drop_all(); + else if (arg_caps_drop) + caps_drop_list(arg_caps_list); + else if (arg_caps_keep) + caps_keep_list(arg_caps_list); + else if (arg_caps_default_filter) + caps_default_filter(); +} + +void save_nogroups(void) { + if (arg_nogroups == 0) + return; + + char *fname; + if (asprintf(&fname, "%s/groups", MNT_DIR) == -1) + errExit("asprintf"); + FILE *fp = fopen(fname, "w"); + if (fp) { + fprintf(fp, "\n"); + fclose(fp); + if (chown(fname, 0, 0) < 0) + errExit("chown"); + } + else { + fprintf(stderr, "Error: cannot save nogroups state\n"); + free(fname); + exit(1); + } + + free(fname); +} + +static void sandbox_if_up(Bridge *br) { + assert(br); + if (!br->configured) + return; + + char *dev = br->devsandbox; + net_if_up(dev); + + if (br->arg_ip_none == 1); // do nothing + else if (br->arg_ip_none == 0 && br->macvlan == 0) { + if (br->ipsandbox == br->ip) { + fprintf(stderr, "Error: %d.%d.%d.%d is interface %s address.\n", PRINT_IP(br->ipsandbox), br->dev); + exit(1); + } + + // just assign the address + assert(br->ipsandbox); + if (arg_debug) + printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev); + net_if_ip(dev, br->ipsandbox, br->mask); + net_if_up(dev); + } + else if (br->arg_ip_none == 0 && br->macvlan == 1) { + // reassign the macvlan address + if (br->ipsandbox == 0) + // ip address assigned by arp-scan for a macvlan device + br->ipsandbox = arp_assign(dev, br); //br->ip, br->mask); + else { + if (br->ipsandbox == br->ip) { + fprintf(stderr, "Error: %d.%d.%d.%d is interface %s address.\n", PRINT_IP(br->ipsandbox), br->dev); + exit(1); + } + + uint32_t rv = arp_check(dev, br->ipsandbox, br->ip); + if (rv) { + fprintf(stderr, "Error: the address %d.%d.%d.%d is already in use.\n", PRINT_IP(br->ipsandbox)); + exit(1); + } + } + + if (arg_debug) + printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev); + net_if_ip(dev, br->ipsandbox, br->mask); + net_if_up(dev); + } +} + +static void chk_chroot(void) { + // if we are starting firejail inside some other container technology, we don't care about this + char *mycont = getenv("container"); + if (mycont) + return; + + // check if this is a regular chroot + struct stat s; + if (stat("/", &s) == 0) { + if (s.st_ino != 2) + return; + } + + fprintf(stderr, "Error: cannot mount filesystem as slave\n"); + exit(1); +} + +int sandbox(void* sandbox_arg) { + pid_t child_pid = getpid(); + if (arg_debug) + printf("Initializing child process\n"); + + // close each end of the unused pipes + close(parent_to_child_fds[1]); + close(child_to_parent_fds[0]); + + // wait for parent to do base setup + wait_for_other(parent_to_child_fds[0]); + + if (arg_debug && child_pid == 1) + printf("PID namespace installed\n"); + + //**************************** + // set hostname + //**************************** + if (cfg.hostname) { + if (sethostname(cfg.hostname, strlen(cfg.hostname)) < 0) + errExit("sethostname"); + } + + //**************************** + // mount namespace + //**************************** + // mount events are not forwarded between the host the sandbox + if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0) { + chk_chroot(); + } + + //**************************** + // netfilter + //**************************** + if (arg_netfilter && any_bridge_configured()) { // assuming by default the client filter + netfilter(arg_netfilter_file); + } + + //**************************** + // trace pre-install + //**************************** + if (arg_trace) + fs_trace_preload(); + + //**************************** + // configure filesystem + //**************************** +#ifdef HAVE_CHROOT + if (cfg.chrootdir) { + fs_chroot(cfg.chrootdir); + // force caps and seccomp if not started as root + if (getuid() != 0) { + // force default seccomp inside the chroot, no keep or drop list + // the list build on top of the default drop list is kept intact + arg_seccomp = 1; + if (arg_seccomp_list_drop) { + free(arg_seccomp_list_drop); + arg_seccomp_list_drop = NULL; + } + if (arg_seccomp_list_keep) { + free(arg_seccomp_list_keep); + arg_seccomp_list_keep = NULL; + } + + // disable all capabilities + if (arg_caps_default_filter || arg_caps_list) + fprintf(stderr, "Warning: all capabilities disabled for a regular user during chroot\n"); + arg_caps_drop_all = 1; + + // drop all supplementary groups; /etc/group file inside chroot + // is controlled by a regular usr + arg_nogroups = 1; + printf("Dropping all Linux capabilities and enforcing default seccomp filter\n"); + } + + //**************************** + // trace pre-install, this time inside chroot + //**************************** + if (arg_trace) + fs_trace_preload(); + } + else +#endif + if (arg_overlay) + fs_overlayfs(); + else + fs_basic_fs(); + + + //**************************** + // set hostname in /etc/hostname + //**************************** + if (cfg.hostname) { + fs_hostname(cfg.hostname); + } + + //**************************** + // apply the profile file + //**************************** + if (cfg.profile) + fs_blacklist(cfg.homedir); + + //**************************** + // private mode + //**************************** + if (arg_private) { + if (cfg.home_private) // --private= + fs_private_homedir(); + else if (cfg.home_private_keep) // --private.keep= + fs_private_home_list(); + else // --private + fs_private(); + } + + if (arg_private_dev) + fs_private_dev(); + + //**************************** + // install trace + //**************************** + if (arg_trace) + fs_trace(); + + //**************************** + // update /proc, /dev, /boot directorymy + //**************************** + fs_proc_sys_dev_boot(); + + //**************************** + // networking + //**************************** + if (arg_nonetwork) { + net_if_up("lo"); + } + else if (any_bridge_configured()) { + // configure lo and eth0...eth3 + net_if_up("lo"); + + if (mac_not_zero(cfg.bridge0.macsandbox)) + net_config_mac(cfg.bridge0.devsandbox, cfg.bridge0.macsandbox); + sandbox_if_up(&cfg.bridge0); + + if (mac_not_zero(cfg.bridge1.macsandbox)) + net_config_mac(cfg.bridge1.devsandbox, cfg.bridge1.macsandbox); + sandbox_if_up(&cfg.bridge1); + + if (mac_not_zero(cfg.bridge2.macsandbox)) + net_config_mac(cfg.bridge2.devsandbox, cfg.bridge2.macsandbox); + sandbox_if_up(&cfg.bridge2); + + if (mac_not_zero(cfg.bridge3.macsandbox)) + net_config_mac(cfg.bridge3.devsandbox, cfg.bridge3.macsandbox); + sandbox_if_up(&cfg.bridge3); + + // add a default route + if (cfg.defaultgw) { + // set the default route + if (net_add_route(0, 0, cfg.defaultgw)) + fprintf(stderr, "Warning: cannot configure default route\n"); + } + + if (arg_debug) + printf("Network namespace enabled\n"); + } + + // if any dns server is configured, it is time to set it now + fs_resolvconf(); + + // print network configuration + if (any_bridge_configured() || cfg.defaultgw || cfg.dns1) { + printf("\n"); + if (any_bridge_configured()) + net_ifprint(); + if (cfg.defaultgw != 0) + printf("Default gateway %d.%d.%d.%d\n", PRINT_IP(cfg.defaultgw)); + if (cfg.dns1 != 0) + printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns1)); + if (cfg.dns2 != 0) + printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns2)); + if (cfg.dns3 != 0) + printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns3)); + printf("\n"); + } + + + + //**************************** + // start executable + //**************************** + prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); // kill the child in case the parent died + int cwd = 0; + if (cfg.cwd) { + if (chdir(cfg.cwd) == 0) + cwd = 1; + } + + if (!cwd) { + if (chdir("/") < 0) + errExit("chdir"); + if (cfg.homedir) { + struct stat s; + if (stat(cfg.homedir, &s) == 0) { + /* coverity[toctou] */ + if (chdir(cfg.homedir) < 0) + errExit("chdir"); + } + } + } + + // set environment + // fix qt 4.8 + if (setenv("QT_X11_NO_MITSHM", "1", 1) < 0) + errExit("setenv"); + if (setenv("container", "firejail", 1) < 0) // LXC sets container=lxc, + errExit("setenv"); + if (arg_zsh && setenv("SHELL", "/usr/bin/zsh", 1) < 0) + errExit("setenv"); + if (arg_csh && setenv("SHELL", "/bin/csh", 1) < 0) + errExit("setenv"); + if (cfg.shell && setenv("SHELL", cfg.shell, 1) < 0) + errExit("setenv"); + // set prompt color to green + //export PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\] ' + if (setenv("PROMPT_COMMAND", "export PS1=\"\\[\\e[1;32m\\][\\u@\\h \\W]\\$\\[\\e[0m\\] \"", 1) < 0) + errExit("setenv"); + + + // set capabilities + if (!arg_noroot) + set_caps(); + + // set rlimits + set_rlimits(); + + // set seccomp +#ifdef HAVE_SECCOMP + // if a keep list is available, disregard the drop list + if (arg_seccomp == 1) { + if (arg_seccomp_list_keep) + seccomp_filter_keep(); // this will also save the fmyilter to MNT_DIR/seccomp file + else + seccomp_filter_drop(); // this will also save the filter to MNT_DIR/seccomp file + } +#endif + + // set cpu affinity + if (cfg.cpus) { + save_cpu(); // save cpu affinity mask to MNT_DIR/cpu file + set_cpu_affinity(); + } + + // save cgroup in MNT_DIR/cgroup file + if (cfg.cgroup) + save_cgroup(); + + //**************************************** + // drop privileges or create a new user namespace + //**************************************** + save_nogroups(); + if (arg_noroot) { + int rv = unshare(CLONE_NEWUSER); + if (rv == -1) { + fprintf(stderr, "Warning: cannot mount a new user namespace\n"); + perror("unshare"); + drop_privs(arg_nogroups); + } + } + else + drop_privs(arg_nogroups); + + // notify parent that new user namespace has been created so a proper + // UID/GID map can be setup + notify_other(child_to_parent_fds[1]); + close(child_to_parent_fds[1]); + + // wait for parent to finish setting up a proper UID/GID map + wait_for_other(parent_to_child_fds[0]); + close(parent_to_child_fds[0]); + + // somehow, the new user namespace resets capabilities; + // we need to do them again + if (arg_noroot) { + set_caps(); + if (arg_debug) + printf("User namespace (noroot) installed\n"); + } + + + //**************************************** + // start the program without using a shell + //**************************************** + if (arg_shell_none) { + if (arg_debug) { + int i; + for (i = cfg.original_program_index; i < cfg.original_argc; i++) { + if (cfg.original_argv[i] == NULL) + break; + printf("execvp argument %d: %s\n", i - cfg.original_program_index, cfg.original_argv[i]); + } + } + + if (!arg_command) + printf("Child process initialized\n"); + execvp(cfg.original_argv[cfg.original_program_index], &cfg.original_argv[cfg.original_program_index + 1]); + } + //**************************************** + // start the program using a shell + //**************************************** + else { + // choose the shell requested by the user, or use bash as default + char *sh; + if (cfg.shell) + sh = cfg.shell; + else if (arg_zsh) + sh = "/usr/bin/zsh"; + else if (arg_csh) + sh = "/bin/csh"; + else + sh = "/bin/bash"; + + char *arg[5]; + int index = 0; + arg[index++] = sh; + arg[index++] = "-c"; + assert(cfg.command_line); + if (arg_debug) + printf("Starting %s\n", cfg.command_line); + if (arg_doubledash) + arg[index++] = "--"; + arg[index++] = cfg.command_line; + arg[index] = NULL; + assert(index < 5); + + if (arg_debug) { + char *msg; + if (asprintf(&msg, "sandbox %d, execvp into %s", sandbox_pid, cfg.command_line) == -1) + errExit("asprintf"); + logmsg(msg); + free(msg); + } + + if (arg_debug) { + int i; + for (i = 0; i < 5; i++) { + if (arg[i] == NULL) + break; + printf("execvp argument %d: %s\n", i, arg[i]); + } + } + + if (!arg_command) + printf("Child process initialized\n"); + execvp(sh, arg); + } + + + perror("execvp"); + return 0; +} diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c new file mode 100644 index 00000000000..c03eb68485a --- /dev/null +++ b/src/firejail/seccomp.c @@ -0,0 +1,658 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +/* default seccomp filter + // seccomp + struct sock_filter filter[] = { + VALIDATE_ARCHITECTURE, + EXAMINE_SYSCALL, + BLACKLIST(SYS_mount), // mount/unmount filesystems + BLACKLIST(SYS_umount2), + BLACKLIST(SYS_ptrace), // trace processes + BLACKLIST(SYS_kexec_load), // loading a different kernel + BLACKLIST(SYS_open_by_handle_at), // open by handle + BLACKLIST(SYS_init_module), // kernel module handling +#ifdef SYS_finit_module // introduced in 2013 + BLACKLIST(SYS_finit_module), +#endif + BLACKLIST(SYS_delete_module), + BLACKLIST(SYS_iopl), // io permisions +#ifdef SYS_ioperm + BLACKLIST(SYS_ioperm), +#endif +SYS_iopl + BLACKLIST(SYS_iopl), // io permisions +#endif +#ifdef SYS_ni_syscall), // new io permisions call on arm devices + BLACKLIST(SYS_ni_syscall), +#endif + BLACKLIST(SYS_swapon), // swap on/off + BLACKLIST(SYS_swapoff), + BLACKLIST(SYS_syslog), // kernel printk control + RETURN_ALLOW + }; +*/ +#ifdef HAVE_SECCOMP +#include "firejail.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#ifndef PR_SET_NO_NEW_PRIVS +# define PR_SET_NO_NEW_PRIVS 38 +#endif + +#if HAVE_SECCOMP_H +#include +#else +#define SECCOMP_MODE_FILTER 2 +#define SECCOMP_RET_KILL 0x00000000U +#define SECCOMP_RET_TRAP 0x00030000U +#define SECCOMP_RET_ALLOW 0x7fff0000U +#define SECCOMP_RET_ERRNO 0x00050000U +#define SECCOMP_RET_DATA 0x0000ffffU +struct seccomp_data { + int nr; + __u32 arch; + __u64 instruction_pointer; + __u64 args[6]; +}; +#endif + +#if defined(__i386__) +# define ARCH_NR AUDIT_ARCH_I386 +#elif defined(__x86_64__) +# define ARCH_NR AUDIT_ARCH_X86_64 +#elif defined(__arm__) +# define ARCH_NR AUDIT_ARCH_ARM +#else +# warning "Platform does not support seccomp filter yet" +# define ARCH_NR 0 +#endif + + +#define VALIDATE_ARCHITECTURE \ + BPF_STMT(BPF_LD+BPF_W+BPF_ABS, (offsetof(struct seccomp_data, arch))), \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) + +#define EXAMINE_SYSCALL BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \ + (offsetof(struct seccomp_data, nr))) + +#define BLACKLIST(syscall_nr) \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), \ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) + +#define WHITELIST(syscall_nr) \ + BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), \ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) + +#define RETURN_ALLOW \ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) + +#define KILL_PROCESS \ + BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) + +#define SECSIZE 128 // initial filter size +static struct sock_filter *sfilter = NULL; +static int sfilter_alloc_size = 0; +static int sfilter_index = 0; + +// debug filter +void filter_debug(void) { + // start filter + struct sock_filter filter[] = { + VALIDATE_ARCHITECTURE, + EXAMINE_SYSCALL + }; + + // print sizes + printf("SECCOMP Filter:\n"); + if (sfilter == NULL) { + printf("SECCOMP filter not allocated\n"); + return; + } + if (sfilter_index < 4) + return; + + // test the start of the filter + if (memcmp(sfilter, filter, sizeof(filter)) == 0) { + printf(" VALIDATE_ARCHITECTURE\n"); + printf(" EXAMINE_SYSCAL\n"); + } + + // loop trough blacklists + int i = 4; + while (i < sfilter_index) { + // minimal parsing! + unsigned char *ptr = (unsigned char *) &sfilter[i]; + int *nr = (int *) (ptr + 4); + if (*ptr == 0x15 && *(ptr +14) == 0xff && *(ptr + 15) == 0x7f ) { + printf(" WHITELIST %d %s\n", *nr, syscall_find_nr(*nr)); + i += 2; + } + else if (*ptr == 0x15 && *(ptr +14) == 0 && *(ptr + 15) == 0) { + printf(" BLACKLIST %d %s\n", *nr, syscall_find_nr(*nr)); + i += 2; + } + else if (*ptr == 0x06 && *(ptr +6) == 0 && *(ptr + 7) == 0 ) { + printf(" KILL_PROCESS\n"); + i++; + } + else if (*ptr == 0x06 && *(ptr +6) == 0xff && *(ptr + 7) == 0x7f ) { + printf(" RETURN_ALLOW\n"); + i++; + } + else { + printf(" UNKNOWN ENTRY!!!\n"); + i++; + } + } +} + +// initialize filter +static void filter_init(void) { + if (sfilter) { + assert(0); + return; + } + + if (arg_debug) + printf("Initialize seccomp filter\n"); + // allocate a filter of SECSIZE + sfilter = malloc(sizeof(struct sock_filter) * SECSIZE); + if (!sfilter) + errExit("malloc"); + memset(sfilter, 0, sizeof(struct sock_filter) * SECSIZE); + sfilter_alloc_size = SECSIZE; + + // copy the start entries + struct sock_filter filter[] = { + VALIDATE_ARCHITECTURE, + EXAMINE_SYSCALL + }; + sfilter_index = sizeof(filter) / sizeof(struct sock_filter); + memcpy(sfilter, filter, sizeof(filter)); +} + +static void filter_realloc(void) { + assert(sfilter); + assert(sfilter_alloc_size); + assert(sfilter_index); + if (arg_debug) + printf("Allocating more seccomp filter entries\n"); + + // allocate the new memory + struct sock_filter *old = sfilter; + sfilter = malloc(sizeof(struct sock_filter) * (sfilter_alloc_size + SECSIZE)); + if (!sfilter) + errExit("malloc"); + memset(sfilter, 0, sizeof(struct sock_filter) * (sfilter_alloc_size + SECSIZE)); + + // copy old filter + memcpy(sfilter, old, sizeof(struct sock_filter) * sfilter_alloc_size); + sfilter_alloc_size += SECSIZE; +} + +static void filter_add_whitelist(int syscall) { + assert(sfilter); + assert(sfilter_alloc_size); + assert(sfilter_index); + if (arg_debug) + printf("Whitelisting syscall %d %s\n", syscall, syscall_find_nr(syscall)); + + if ((sfilter_index + 2) > sfilter_alloc_size) + filter_realloc(); + + struct sock_filter filter[] = { + WHITELIST(syscall) + }; +#if 0 +{ + int i; + unsigned char *ptr = (unsigned char *) &filter[0]; + for (i = 0; i < sizeof(filter); i++, ptr++) + printf("%x, ", (*ptr) & 0xff); + printf("\n"); +} +#endif + memcpy(&sfilter[sfilter_index], filter, sizeof(filter)); + sfilter_index += sizeof(filter) / sizeof(struct sock_filter); +} + +static void filter_add_blacklist(int syscall) { + assert(sfilter); + assert(sfilter_alloc_size); + assert(sfilter_index); + if (arg_debug) + printf("Blacklisting syscall %d %s\n", syscall, syscall_find_nr(syscall)); + + if ((sfilter_index + 2) > sfilter_alloc_size) + filter_realloc(); + + struct sock_filter filter[] = { + BLACKLIST(syscall) + }; +#if 0 +{ + int i; + unsigned char *ptr = (unsigned char *) &filter[0]; + for (i = 0; i < sizeof(filter); i++, ptr++) + printf("%x, ", (*ptr) & 0xff); + printf("\n"); +} +#endif + memcpy(&sfilter[sfilter_index], filter, sizeof(filter)); + sfilter_index += sizeof(filter) / sizeof(struct sock_filter); +} + +static void filter_end_blacklist(void) { + assert(sfilter); + assert(sfilter_alloc_size); + assert(sfilter_index); + if (arg_debug) + printf("Ending syscall filter\n"); + + if ((sfilter_index + 2) > sfilter_alloc_size) + filter_realloc(); + + struct sock_filter filter[] = { + RETURN_ALLOW + }; +#if 0 +{ + int i; + unsigned char *ptr = (unsigned char *) &filter[0]; + for (i = 0; i < sizeof(filter); i++, ptr++) + printf("%x, ", (*ptr) & 0xff); + printf("\n"); +} +#endif + memcpy(&sfilter[sfilter_index], filter, sizeof(filter)); + sfilter_index += sizeof(filter) / sizeof(struct sock_filter); +} + +static void filter_end_whitelist(void) { + assert(sfilter); + assert(sfilter_alloc_size); + assert(sfilter_index); + if (arg_debug) + printf("Ending syscall filter\n"); + + if ((sfilter_index + 2) > sfilter_alloc_size) + filter_realloc(); + + struct sock_filter filter[] = { + KILL_PROCESS + }; +#if 0 +{ + int i; + unsigned char *ptr = (unsigned char *) &filter[0]; + for (i = 0; i < sizeof(filter); i++, ptr++) + printf("%x, ", (*ptr) & 0xff); + printf("\n"); +} +#endif + memcpy(&sfilter[sfilter_index], filter, sizeof(filter)); + sfilter_index += sizeof(filter) / sizeof(struct sock_filter); +} + + +// save seccomp filter in /tmp/firejail/mnt/seccomp +static void write_seccomp_file(void) { + fs_build_mnt_dir(); + assert(sfilter); + + char *fname; + if (asprintf(&fname, "%s/seccomp", MNT_DIR) == -1) + errExit("asprintf"); + int fd = open(fname, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); + if (fd == -1) + errExit("open"); + + if (arg_debug) + printf("Save seccomp filter, size %lu bytes\n", sfilter_index * sizeof(struct sock_filter)); + errno = 0; + ssize_t sz = write(fd, sfilter, sfilter_index * sizeof(struct sock_filter)); + if (sz != (sfilter_index * sizeof(struct sock_filter))) { + fprintf(stderr, "Error: cannot save seccomp filter\n"); + exit(1); + } + close(fd); + if (chown(fname, 0, 0) < 0) + errExit("chown"); + free(fname); +} + +// read seccomp filter from /tmp/firejail/mnt/seccomp +static void read_seccomp_file(char *file_name) { + assert(sfilter == NULL && sfilter_index == 0); + + char *fname; + if (file_name) + fname = file_name; + else { + if (asprintf(&fname, "%s/seccomp", MNT_DIR) == -1) + errExit("asprintf"); + } + + // check file + struct stat s; + if (stat(fname, &s) == -1) { + fprintf(stderr, "Error: seccomp file not found\n"); + exit(1); + } + ssize_t sz = s.st_size; + if (sz == 0 || (sz % sizeof(struct sock_filter)) != 0) { + fprintf(stderr, "Error: invalid seccomp file\n"); + exit(1); + } + sfilter = malloc(sz); + if (!sfilter) + errExit("malloc"); + + // read file + /* coverity[toctou] */ + int fd = open(fname,O_RDONLY); + if (fd == -1) + errExit("open"); + errno = 0; + ssize_t size = read(fd, sfilter, sz); + if (size != sz) { + fprintf(stderr, "Error: invalid seccomp file\n"); + exit(1); + } + sfilter_index = sz / sizeof(struct sock_filter); + + if (arg_debug) + printf("Read seccomp filter, size %lu bytes\n", sfilter_index * sizeof(struct sock_filter)); + + close(fd); + free(fname); + + if (arg_debug) + filter_debug(); +} + + +// drop filter for seccomp option +int seccomp_filter_drop(void) { + filter_init(); + + // default seccomp + if (arg_seccomp_list_drop == NULL) { +#ifdef SYS_mount + filter_add_blacklist(SYS_mount); +#endif +#ifdef SYS_umount2 + filter_add_blacklist(SYS_umount2); +#endif +#ifdef SYS_ptrace + filter_add_blacklist(SYS_ptrace); +#endif +#ifdef SYS_kexec_load + filter_add_blacklist(SYS_kexec_load); +#endif +#ifdef SYS_open_by_handle_at + filter_add_blacklist(SYS_open_by_handle_at); +#endif +#ifdef SYS_init_module + filter_add_blacklist(SYS_init_module); +#endif +#ifdef SYS_finit_module // introduced in 2013 + filter_add_blacklist(SYS_finit_module); +#endif +#ifdef SYS_delete_module + filter_add_blacklist(SYS_delete_module); +#endif +#ifdef SYS_iopl + filter_add_blacklist(SYS_iopl); +#endif +#ifdef SYS_ioperm + filter_add_blacklist(SYS_ioperm); +#endif +#ifdef SYS_ni_syscall // new io permisions call on arm devices + filter_add_blacklist(SYS_ni_syscall); +#endif +#ifdef SYS_swapon + filter_add_blacklist(SYS_swapon); +#endif +#ifdef SYS_swapoff + filter_add_blacklist(SYS_swapoff); +#endif +#ifdef SYS_syslog + filter_add_blacklist(SYS_syslog); +#endif +#ifdef SYS_process_vm_readv + filter_add_blacklist(SYS_process_vm_readv); +#endif +#ifdef SYS_process_vm_writev + filter_add_blacklist(SYS_process_vm_writev); +#endif +#ifdef SYS_mknod + filter_add_blacklist(SYS_mknod); +#endif + + // new syscalls in 0.9,23 +#ifdef SYS_sysfs + filter_add_blacklist(SYS_sysfs); +#endif +#ifdef SYS__sysctl + filter_add_blacklist(SYS__sysctl); +#endif +#ifdef SYS_adjtimex + filter_add_blacklist(SYS_adjtimex); +#endif +#ifdef SYS_clock_adjtime + filter_add_blacklist(SYS_clock_adjtime); +#endif +#ifdef SYS_lookup_dcookie + filter_add_blacklist(SYS_lookup_dcookie); +#endif +#ifdef SYS_perf_event_open + filter_add_blacklist(SYS_perf_event_open); +#endif +#ifdef SYS_fanotify_init + filter_add_blacklist(SYS_fanotify_init); +#endif +#ifdef SYS_kcmp + filter_add_blacklist(SYS_kcmp); +#endif + } + + // default seccomp filter with additional drop list + if (arg_seccomp_list && arg_seccomp_list_drop == NULL) { + if (syscall_check_list(arg_seccomp_list, filter_add_blacklist)) { + fprintf(stderr, "Error: cannot load seccomp filter\n"); + exit(1); + } + } + // drop list + else if (arg_seccomp_list == NULL && arg_seccomp_list_drop) { + if (syscall_check_list(arg_seccomp_list_drop, filter_add_blacklist)) { + fprintf(stderr, "Error: cannot load seccomp filter\n"); + exit(1); + } + } + + + filter_end_blacklist(); + if (arg_debug) + filter_debug(); + + // save seccomp filter in /tmp/firejail/mnt/seccomp + // in order to use it in --join operations + write_seccomp_file(); + + + struct sock_fprog prog = { + .len = sfilter_index, + .filter = sfilter, + }; + + if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { + fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); + return 1; + } + else if (arg_debug) { + printf("seccomp enabled\n"); + } + + return 0; +} + +// keep filter for seccomp option +int seccomp_filter_keep(void) { + filter_init(); + + // these 4 syscalls are used by firejail after the seccomp filter is initialized + filter_add_whitelist(SYS_setuid); + filter_add_whitelist(SYS_setgid); + filter_add_whitelist(SYS_setgroups); + filter_add_whitelist(SYS_dup); + + // apply keep list + if (arg_seccomp_list_keep) { + if (syscall_check_list(arg_seccomp_list_keep, filter_add_whitelist)) { + fprintf(stderr, "Error: cannot load seccomp filter\n"); + exit(1); + } + } + + filter_end_whitelist(); + if (arg_debug) + filter_debug(); + + // save seccomp filter in /tmp/firejail/mnt/seccomp + // in order to use it in --join operations + write_seccomp_file(); + + + struct sock_fprog prog = { + .len = sfilter_index, + .filter = sfilter, + }; + + if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { + fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); + return 1; + } + else if (arg_debug) { + printf("seccomp enabled\n"); + } + + return 0; +} + + + +void seccomp_set(void) { + // read seccomp filter from /tmp/firejail/mnt/seccomp + read_seccomp_file(NULL); + + // apply filter + struct sock_fprog prog = { + .len = sfilter_index, + .filter = sfilter, + }; + + if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { + fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); + return; + } + else if (arg_debug) { + printf("seccomp enabled\n"); + } +} + +void seccomp_print_filter_name(const char *name) { + if (!name || strlen(name) == 0) { + fprintf(stderr, "Error: invalid sandbox name\n"); + exit(1); + } + pid_t pid; + if (name2pid(name, &pid)) { + fprintf(stderr, "Error: cannot find sandbox %s\n", name); + exit(1); + } + + seccomp_print_filter(pid); +} + +void seccomp_print_filter(pid_t pid) { + // if the pid is that of a firejail process, use the pid of the first child process + char *comm = pid_proc_comm(pid); + if (comm) { + // remove \n + char *ptr = strchr(comm, '\n'); + if (ptr) + *ptr = '\0'; + if (strcmp(comm, "firejail") == 0) { + pid_t child; + if (find_child(pid, &child) == 0) { + pid = child; + } + } + free(comm); + } + + // check privileges for non-root users + uid_t uid = getuid(); + if (uid != 0) { + struct stat s; + char *dir; + if (asprintf(&dir, "/proc/%u/ns", pid) == -1) + errExit("asprintf"); + if (stat(dir, &s) < 0) + errExit("stat"); + if (s.st_uid != uid) { + printf("Error: permission denied.\n"); + exit(1); + } + } + + + // find the seccomp filter + char *fname; + if (asprintf(&fname, "/proc/%d/root/tmp/firejail/mnt/seccomp", pid) == -1) + errExit("asprintf"); + + struct stat s; + if (stat(fname, &s) == -1) { + printf("Cannot access seccomp filter.\n"); + exit(1); + } + + // read and print the filter + read_seccomp_file(fname); + drop_privs(1); + filter_debug(); + + exit(0); +} + +#endif // HAVE_SECCOMP + diff --git a/src/firejail/shutdown.c b/src/firejail/shutdown.c new file mode 100644 index 00000000000..b666996df6c --- /dev/null +++ b/src/firejail/shutdown.c @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firejail.h" +#include +#include +#include +#include + +void shut_name(const char *name) { + if (!name || strlen(name) == 0) { + fprintf(stderr, "Error: invalid sandbox name\n"); + exit(1); + } + + pid_t pid; + if (name2pid(name, &pid)) { + fprintf(stderr, "Error: cannot find sandbox %s\n", name); + exit(1); + } + + shut(pid); +} + +void shut(pid_t pid) { + pid_t parent = pid; + // if the pid is that of a firejail process, use the pid of a child process inside the sandbox + char *comm = pid_proc_comm(pid); + if (comm) { + // remove \n + char *ptr = strchr(comm, '\n'); + if (ptr) + *ptr = '\0'; + if (strcmp(comm, "firejail") == 0) { + pid_t child; + if (find_child(pid, &child) == 0) { + pid = child; + printf("Switching to pid %u, the first child process inside the sandbox\n", (unsigned) pid); + } + } + free(comm); + } + + // check privileges for non-root users + uid_t uid = getuid(); + if (uid != 0) { + struct stat s; + char *dir; + if (asprintf(&dir, "/proc/%u/ns", pid) == -1) + errExit("asprintf"); + if (stat(dir, &s) < 0) + errExit("stat"); + if (s.st_uid != uid) { + fprintf(stderr, "Error: permission is denied to shutdown a sandbox created by a different user.\n"); + exit(1); + } + } + + printf("Sending SIGTERM to %u\n", pid); + kill(pid, SIGTERM); + sleep(2); + + // if the process is still running, terminate it using SIGKILL + // try to open stat file + char *file; + if (asprintf(&file, "/proc/%u/status", pid) == -1) { + perror("asprintf"); + exit(1); + } + FILE *fp = fopen(file, "r"); + if (!fp) + return; + fclose(fp); + + // kill the process and also the parent + printf("Sending SIGKILL to %u\n", pid); + kill(pid, SIGKILL); + if (parent != pid) { + printf("Sending SIGKILL to %u\n", parent); + kill(parent, SIGKILL); + } +} diff --git a/src/firejail/syscall.c b/src/firejail/syscall.c new file mode 100644 index 00000000000..50bff7f5a68 --- /dev/null +++ b/src/firejail/syscall.c @@ -0,0 +1,4942 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifdef HAVE_SECCOMP +#include "firejail.h" +#include + +typedef struct { + char *name; + int nr; +} SyscallEntry; + +static SyscallEntry syslist[] = { +// +// code generated using tools/extract-syscall +// +#ifndef _SYSCALL_H +#endif +#if !defined __x86_64__ +#ifdef SYS__llseek +#ifdef __NR__llseek + {"_llseek", __NR__llseek}, +#endif +#endif +#ifdef SYS__newselect +#ifdef __NR__newselect + {"_newselect", __NR__newselect}, +#endif +#endif +#ifdef SYS__sysctl +#ifdef __NR__sysctl + {"_sysctl", __NR__sysctl}, +#endif +#endif +#ifdef SYS_access +#ifdef __NR_access + {"access", __NR_access}, +#endif +#endif +#ifdef SYS_acct +#ifdef __NR_acct + {"acct", __NR_acct}, +#endif +#endif +#ifdef SYS_add_key +#ifdef __NR_add_key + {"add_key", __NR_add_key}, +#endif +#endif +#ifdef SYS_adjtimex +#ifdef __NR_adjtimex + {"adjtimex", __NR_adjtimex}, +#endif +#endif +#ifdef SYS_afs_syscall +#ifdef __NR_afs_syscall + {"afs_syscall", __NR_afs_syscall}, +#endif +#endif +#ifdef SYS_alarm +#ifdef __NR_alarm + {"alarm", __NR_alarm}, +#endif +#endif +#ifdef SYS_bdflush +#ifdef __NR_bdflush + {"bdflush", __NR_bdflush}, +#endif +#endif +#ifdef SYS_break +#ifdef __NR_break + {"break", __NR_break}, +#endif +#endif +#ifdef SYS_brk +#ifdef __NR_brk + {"brk", __NR_brk}, +#endif +#endif +#ifdef SYS_capget +#ifdef __NR_capget + {"capget", __NR_capget}, +#endif +#endif +#ifdef SYS_capset +#ifdef __NR_capset + {"capset", __NR_capset}, +#endif +#endif +#ifdef SYS_chdir +#ifdef __NR_chdir + {"chdir", __NR_chdir}, +#endif +#endif +#ifdef SYS_chmod +#ifdef __NR_chmod + {"chmod", __NR_chmod}, +#endif +#endif +#ifdef SYS_chown +#ifdef __NR_chown + {"chown", __NR_chown}, +#endif +#endif +#ifdef SYS_chown32 +#ifdef __NR_chown32 + {"chown32", __NR_chown32}, +#endif +#endif +#ifdef SYS_chroot +#ifdef __NR_chroot + {"chroot", __NR_chroot}, +#endif +#endif +#ifdef SYS_clock_adjtime +#ifdef __NR_clock_adjtime + {"clock_adjtime", __NR_clock_adjtime}, +#endif +#endif +#ifdef SYS_clock_getres +#ifdef __NR_clock_getres + {"clock_getres", __NR_clock_getres}, +#endif +#endif +#ifdef SYS_clock_gettime +#ifdef __NR_clock_gettime + {"clock_gettime", __NR_clock_gettime}, +#endif +#endif +#ifdef SYS_clock_nanosleep +#ifdef __NR_clock_nanosleep + {"clock_nanosleep", __NR_clock_nanosleep}, +#endif +#endif +#ifdef SYS_clock_settime +#ifdef __NR_clock_settime + {"clock_settime", __NR_clock_settime}, +#endif +#endif +#ifdef SYS_clone +#ifdef __NR_clone + {"clone", __NR_clone}, +#endif +#endif +#ifdef SYS_close +#ifdef __NR_close + {"close", __NR_close}, +#endif +#endif +#ifdef SYS_creat +#ifdef __NR_creat + {"creat", __NR_creat}, +#endif +#endif +#ifdef SYS_create_module +#ifdef __NR_create_module + {"create_module", __NR_create_module}, +#endif +#endif +#ifdef SYS_delete_module +#ifdef __NR_delete_module + {"delete_module", __NR_delete_module}, +#endif +#endif +#ifdef SYS_dup +#ifdef __NR_dup + {"dup", __NR_dup}, +#endif +#endif +#ifdef SYS_dup2 +#ifdef __NR_dup2 + {"dup2", __NR_dup2}, +#endif +#endif +#ifdef SYS_dup3 +#ifdef __NR_dup3 + {"dup3", __NR_dup3}, +#endif +#endif +#ifdef SYS_epoll_create +#ifdef __NR_epoll_create + {"epoll_create", __NR_epoll_create}, +#endif +#endif +#ifdef SYS_epoll_create1 +#ifdef __NR_epoll_create1 + {"epoll_create1", __NR_epoll_create1}, +#endif +#endif +#ifdef SYS_epoll_ctl +#ifdef __NR_epoll_ctl + {"epoll_ctl", __NR_epoll_ctl}, +#endif +#endif +#ifdef SYS_epoll_pwait +#ifdef __NR_epoll_pwait + {"epoll_pwait", __NR_epoll_pwait}, +#endif +#endif +#ifdef SYS_epoll_wait +#ifdef __NR_epoll_wait + {"epoll_wait", __NR_epoll_wait}, +#endif +#endif +#ifdef SYS_eventfd +#ifdef __NR_eventfd + {"eventfd", __NR_eventfd}, +#endif +#endif +#ifdef SYS_eventfd2 +#ifdef __NR_eventfd2 + {"eventfd2", __NR_eventfd2}, +#endif +#endif +#ifdef SYS_execve +#ifdef __NR_execve + {"execve", __NR_execve}, +#endif +#endif +#ifdef SYS_exit +#ifdef __NR_exit + {"exit", __NR_exit}, +#endif +#endif +#ifdef SYS_exit_group +#ifdef __NR_exit_group + {"exit_group", __NR_exit_group}, +#endif +#endif +#ifdef SYS_faccessat +#ifdef __NR_faccessat + {"faccessat", __NR_faccessat}, +#endif +#endif +#ifdef SYS_fadvise64 +#ifdef __NR_fadvise64 + {"fadvise64", __NR_fadvise64}, +#endif +#endif +#ifdef SYS_fadvise64_64 +#ifdef __NR_fadvise64_64 + {"fadvise64_64", __NR_fadvise64_64}, +#endif +#endif +#ifdef SYS_fallocate +#ifdef __NR_fallocate + {"fallocate", __NR_fallocate}, +#endif +#endif +#ifdef SYS_fanotify_init +#ifdef __NR_fanotify_init + {"fanotify_init", __NR_fanotify_init}, +#endif +#endif +#ifdef SYS_fanotify_mark +#ifdef __NR_fanotify_mark + {"fanotify_mark", __NR_fanotify_mark}, +#endif +#endif +#ifdef SYS_fchdir +#ifdef __NR_fchdir + {"fchdir", __NR_fchdir}, +#endif +#endif +#ifdef SYS_fchmod +#ifdef __NR_fchmod + {"fchmod", __NR_fchmod}, +#endif +#endif +#ifdef SYS_fchmodat +#ifdef __NR_fchmodat + {"fchmodat", __NR_fchmodat}, +#endif +#endif +#ifdef SYS_fchown +#ifdef __NR_fchown + {"fchown", __NR_fchown}, +#endif +#endif +#ifdef SYS_fchown32 +#ifdef __NR_fchown32 + {"fchown32", __NR_fchown32}, +#endif +#endif +#ifdef SYS_fchownat +#ifdef __NR_fchownat + {"fchownat", __NR_fchownat}, +#endif +#endif +#ifdef SYS_fcntl +#ifdef __NR_fcntl + {"fcntl", __NR_fcntl}, +#endif +#endif +#ifdef SYS_fcntl64 +#ifdef __NR_fcntl64 + {"fcntl64", __NR_fcntl64}, +#endif +#endif +#ifdef SYS_fdatasync +#ifdef __NR_fdatasync + {"fdatasync", __NR_fdatasync}, +#endif +#endif +#ifdef SYS_fgetxattr +#ifdef __NR_fgetxattr + {"fgetxattr", __NR_fgetxattr}, +#endif +#endif +#ifdef SYS_finit_module +#ifdef __NR_finit_module + {"finit_module", __NR_finit_module}, +#endif +#endif +#ifdef SYS_flistxattr +#ifdef __NR_flistxattr + {"flistxattr", __NR_flistxattr}, +#endif +#endif +#ifdef SYS_flock +#ifdef __NR_flock + {"flock", __NR_flock}, +#endif +#endif +#ifdef SYS_fork +#ifdef __NR_fork + {"fork", __NR_fork}, +#endif +#endif +#ifdef SYS_fremovexattr +#ifdef __NR_fremovexattr + {"fremovexattr", __NR_fremovexattr}, +#endif +#endif +#ifdef SYS_fsetxattr +#ifdef __NR_fsetxattr + {"fsetxattr", __NR_fsetxattr}, +#endif +#endif +#ifdef SYS_fstat +#ifdef __NR_fstat + {"fstat", __NR_fstat}, +#endif +#endif +#ifdef SYS_fstat64 +#ifdef __NR_fstat64 + {"fstat64", __NR_fstat64}, +#endif +#endif +#ifdef SYS_fstatat64 +#ifdef __NR_fstatat64 + {"fstatat64", __NR_fstatat64}, +#endif +#endif +#ifdef SYS_fstatfs +#ifdef __NR_fstatfs + {"fstatfs", __NR_fstatfs}, +#endif +#endif +#ifdef SYS_fstatfs64 +#ifdef __NR_fstatfs64 + {"fstatfs64", __NR_fstatfs64}, +#endif +#endif +#ifdef SYS_fsync +#ifdef __NR_fsync + {"fsync", __NR_fsync}, +#endif +#endif +#ifdef SYS_ftime +#ifdef __NR_ftime + {"ftime", __NR_ftime}, +#endif +#endif +#ifdef SYS_ftruncate +#ifdef __NR_ftruncate + {"ftruncate", __NR_ftruncate}, +#endif +#endif +#ifdef SYS_ftruncate64 +#ifdef __NR_ftruncate64 + {"ftruncate64", __NR_ftruncate64}, +#endif +#endif +#ifdef SYS_futex +#ifdef __NR_futex + {"futex", __NR_futex}, +#endif +#endif +#ifdef SYS_futimesat +#ifdef __NR_futimesat + {"futimesat", __NR_futimesat}, +#endif +#endif +#ifdef SYS_get_kernel_syms +#ifdef __NR_get_kernel_syms + {"get_kernel_syms", __NR_get_kernel_syms}, +#endif +#endif +#ifdef SYS_get_mempolicy +#ifdef __NR_get_mempolicy + {"get_mempolicy", __NR_get_mempolicy}, +#endif +#endif +#ifdef SYS_get_robust_list +#ifdef __NR_get_robust_list + {"get_robust_list", __NR_get_robust_list}, +#endif +#endif +#ifdef SYS_get_thread_area +#ifdef __NR_get_thread_area + {"get_thread_area", __NR_get_thread_area}, +#endif +#endif +#ifdef SYS_getcpu +#ifdef __NR_getcpu + {"getcpu", __NR_getcpu}, +#endif +#endif +#ifdef SYS_getcwd +#ifdef __NR_getcwd + {"getcwd", __NR_getcwd}, +#endif +#endif +#ifdef SYS_getdents +#ifdef __NR_getdents + {"getdents", __NR_getdents}, +#endif +#endif +#ifdef SYS_getdents64 +#ifdef __NR_getdents64 + {"getdents64", __NR_getdents64}, +#endif +#endif +#ifdef SYS_getegid +#ifdef __NR_getegid + {"getegid", __NR_getegid}, +#endif +#endif +#ifdef SYS_getegid32 +#ifdef __NR_getegid32 + {"getegid32", __NR_getegid32}, +#endif +#endif +#ifdef SYS_geteuid +#ifdef __NR_geteuid + {"geteuid", __NR_geteuid}, +#endif +#endif +#ifdef SYS_geteuid32 +#ifdef __NR_geteuid32 + {"geteuid32", __NR_geteuid32}, +#endif +#endif +#ifdef SYS_getgid +#ifdef __NR_getgid + {"getgid", __NR_getgid}, +#endif +#endif +#ifdef SYS_getgid32 +#ifdef __NR_getgid32 + {"getgid32", __NR_getgid32}, +#endif +#endif +#ifdef SYS_getgroups +#ifdef __NR_getgroups + {"getgroups", __NR_getgroups}, +#endif +#endif +#ifdef SYS_getgroups32 +#ifdef __NR_getgroups32 + {"getgroups32", __NR_getgroups32}, +#endif +#endif +#ifdef SYS_getitimer +#ifdef __NR_getitimer + {"getitimer", __NR_getitimer}, +#endif +#endif +#ifdef SYS_getpgid +#ifdef __NR_getpgid + {"getpgid", __NR_getpgid}, +#endif +#endif +#ifdef SYS_getpgrp +#ifdef __NR_getpgrp + {"getpgrp", __NR_getpgrp}, +#endif +#endif +#ifdef SYS_getpid +#ifdef __NR_getpid + {"getpid", __NR_getpid}, +#endif +#endif +#ifdef SYS_getpmsg +#ifdef __NR_getpmsg + {"getpmsg", __NR_getpmsg}, +#endif +#endif +#ifdef SYS_getppid +#ifdef __NR_getppid + {"getppid", __NR_getppid}, +#endif +#endif +#ifdef SYS_getpriority +#ifdef __NR_getpriority + {"getpriority", __NR_getpriority}, +#endif +#endif +#ifdef SYS_getresgid +#ifdef __NR_getresgid + {"getresgid", __NR_getresgid}, +#endif +#endif +#ifdef SYS_getresgid32 +#ifdef __NR_getresgid32 + {"getresgid32", __NR_getresgid32}, +#endif +#endif +#ifdef SYS_getresuid +#ifdef __NR_getresuid + {"getresuid", __NR_getresuid}, +#endif +#endif +#ifdef SYS_getresuid32 +#ifdef __NR_getresuid32 + {"getresuid32", __NR_getresuid32}, +#endif +#endif +#ifdef SYS_getrlimit +#ifdef __NR_getrlimit + {"getrlimit", __NR_getrlimit}, +#endif +#endif +#ifdef SYS_getrusage +#ifdef __NR_getrusage + {"getrusage", __NR_getrusage}, +#endif +#endif +#ifdef SYS_getsid +#ifdef __NR_getsid + {"getsid", __NR_getsid}, +#endif +#endif +#ifdef SYS_gettid +#ifdef __NR_gettid + {"gettid", __NR_gettid}, +#endif +#endif +#ifdef SYS_gettimeofday +#ifdef __NR_gettimeofday + {"gettimeofday", __NR_gettimeofday}, +#endif +#endif +#ifdef SYS_getuid +#ifdef __NR_getuid + {"getuid", __NR_getuid}, +#endif +#endif +#ifdef SYS_getuid32 +#ifdef __NR_getuid32 + {"getuid32", __NR_getuid32}, +#endif +#endif +#ifdef SYS_getxattr +#ifdef __NR_getxattr + {"getxattr", __NR_getxattr}, +#endif +#endif +#ifdef SYS_gtty +#ifdef __NR_gtty + {"gtty", __NR_gtty}, +#endif +#endif +#ifdef SYS_idle +#ifdef __NR_idle + {"idle", __NR_idle}, +#endif +#endif +#ifdef SYS_init_module +#ifdef __NR_init_module + {"init_module", __NR_init_module}, +#endif +#endif +#ifdef SYS_inotify_add_watch +#ifdef __NR_inotify_add_watch + {"inotify_add_watch", __NR_inotify_add_watch}, +#endif +#endif +#ifdef SYS_inotify_init +#ifdef __NR_inotify_init + {"inotify_init", __NR_inotify_init}, +#endif +#endif +#ifdef SYS_inotify_init1 +#ifdef __NR_inotify_init1 + {"inotify_init1", __NR_inotify_init1}, +#endif +#endif +#ifdef SYS_inotify_rm_watch +#ifdef __NR_inotify_rm_watch + {"inotify_rm_watch", __NR_inotify_rm_watch}, +#endif +#endif +#ifdef SYS_io_cancel +#ifdef __NR_io_cancel + {"io_cancel", __NR_io_cancel}, +#endif +#endif +#ifdef SYS_io_destroy +#ifdef __NR_io_destroy + {"io_destroy", __NR_io_destroy}, +#endif +#endif +#ifdef SYS_io_getevents +#ifdef __NR_io_getevents + {"io_getevents", __NR_io_getevents}, +#endif +#endif +#ifdef SYS_io_setup +#ifdef __NR_io_setup + {"io_setup", __NR_io_setup}, +#endif +#endif +#ifdef SYS_io_submit +#ifdef __NR_io_submit + {"io_submit", __NR_io_submit}, +#endif +#endif +#ifdef SYS_ioctl +#ifdef __NR_ioctl + {"ioctl", __NR_ioctl}, +#endif +#endif +#ifdef SYS_ioperm +#ifdef __NR_ioperm + {"ioperm", __NR_ioperm}, +#endif +#endif +#ifdef SYS_iopl +#ifdef __NR_iopl + {"iopl", __NR_iopl}, +#endif +#endif +#ifdef SYS_ioprio_get +#ifdef __NR_ioprio_get + {"ioprio_get", __NR_ioprio_get}, +#endif +#endif +#ifdef SYS_ioprio_set +#ifdef __NR_ioprio_set + {"ioprio_set", __NR_ioprio_set}, +#endif +#endif +#ifdef SYS_ipc +#ifdef __NR_ipc + {"ipc", __NR_ipc}, +#endif +#endif +#ifdef SYS_kcmp +#ifdef __NR_kcmp + {"kcmp", __NR_kcmp}, +#endif +#endif +#ifdef SYS_kexec_load +#ifdef __NR_kexec_load + {"kexec_load", __NR_kexec_load}, +#endif +#endif +#ifdef SYS_keyctl +#ifdef __NR_keyctl + {"keyctl", __NR_keyctl}, +#endif +#endif +#ifdef SYS_kill +#ifdef __NR_kill + {"kill", __NR_kill}, +#endif +#endif +#ifdef SYS_lchown +#ifdef __NR_lchown + {"lchown", __NR_lchown}, +#endif +#endif +#ifdef SYS_lchown32 +#ifdef __NR_lchown32 + {"lchown32", __NR_lchown32}, +#endif +#endif +#ifdef SYS_lgetxattr +#ifdef __NR_lgetxattr + {"lgetxattr", __NR_lgetxattr}, +#endif +#endif +#ifdef SYS_link +#ifdef __NR_link + {"link", __NR_link}, +#endif +#endif +#ifdef SYS_linkat +#ifdef __NR_linkat + {"linkat", __NR_linkat}, +#endif +#endif +#ifdef SYS_listxattr +#ifdef __NR_listxattr + {"listxattr", __NR_listxattr}, +#endif +#endif +#ifdef SYS_llistxattr +#ifdef __NR_llistxattr + {"llistxattr", __NR_llistxattr}, +#endif +#endif +#ifdef SYS_lock +#ifdef __NR_lock + {"lock", __NR_lock}, +#endif +#endif +#ifdef SYS_lookup_dcookie +#ifdef __NR_lookup_dcookie + {"lookup_dcookie", __NR_lookup_dcookie}, +#endif +#endif +#ifdef SYS_lremovexattr +#ifdef __NR_lremovexattr + {"lremovexattr", __NR_lremovexattr}, +#endif +#endif +#ifdef SYS_lseek +#ifdef __NR_lseek + {"lseek", __NR_lseek}, +#endif +#endif +#ifdef SYS_lsetxattr +#ifdef __NR_lsetxattr + {"lsetxattr", __NR_lsetxattr}, +#endif +#endif +#ifdef SYS_lstat +#ifdef __NR_lstat + {"lstat", __NR_lstat}, +#endif +#endif +#ifdef SYS_lstat64 +#ifdef __NR_lstat64 + {"lstat64", __NR_lstat64}, +#endif +#endif +#ifdef SYS_madvise +#ifdef __NR_madvise + {"madvise", __NR_madvise}, +#endif +#endif +#ifdef SYS_mbind +#ifdef __NR_mbind + {"mbind", __NR_mbind}, +#endif +#endif +#ifdef SYS_migrate_pages +#ifdef __NR_migrate_pages + {"migrate_pages", __NR_migrate_pages}, +#endif +#endif +#ifdef SYS_mincore +#ifdef __NR_mincore + {"mincore", __NR_mincore}, +#endif +#endif +#ifdef SYS_mkdir +#ifdef __NR_mkdir + {"mkdir", __NR_mkdir}, +#endif +#endif +#ifdef SYS_mkdirat +#ifdef __NR_mkdirat + {"mkdirat", __NR_mkdirat}, +#endif +#endif +#ifdef SYS_mknod +#ifdef __NR_mknod + {"mknod", __NR_mknod}, +#endif +#endif +#ifdef SYS_mknodat +#ifdef __NR_mknodat + {"mknodat", __NR_mknodat}, +#endif +#endif +#ifdef SYS_mlock +#ifdef __NR_mlock + {"mlock", __NR_mlock}, +#endif +#endif +#ifdef SYS_mlockall +#ifdef __NR_mlockall + {"mlockall", __NR_mlockall}, +#endif +#endif +#ifdef SYS_mmap +#ifdef __NR_mmap + {"mmap", __NR_mmap}, +#endif +#endif +#ifdef SYS_mmap2 +#ifdef __NR_mmap2 + {"mmap2", __NR_mmap2}, +#endif +#endif +#ifdef SYS_modify_ldt +#ifdef __NR_modify_ldt + {"modify_ldt", __NR_modify_ldt}, +#endif +#endif +#ifdef SYS_mount +#ifdef __NR_mount + {"mount", __NR_mount}, +#endif +#endif +#ifdef SYS_move_pages +#ifdef __NR_move_pages + {"move_pages", __NR_move_pages}, +#endif +#endif +#ifdef SYS_mprotect +#ifdef __NR_mprotect + {"mprotect", __NR_mprotect}, +#endif +#endif +#ifdef SYS_mpx +#ifdef __NR_mpx + {"mpx", __NR_mpx}, +#endif +#endif +#ifdef SYS_mq_getsetattr +#ifdef __NR_mq_getsetattr + {"mq_getsetattr", __NR_mq_getsetattr}, +#endif +#endif +#ifdef SYS_mq_notify +#ifdef __NR_mq_notify + {"mq_notify", __NR_mq_notify}, +#endif +#endif +#ifdef SYS_mq_open +#ifdef __NR_mq_open + {"mq_open", __NR_mq_open}, +#endif +#endif +#ifdef SYS_mq_timedreceive +#ifdef __NR_mq_timedreceive + {"mq_timedreceive", __NR_mq_timedreceive}, +#endif +#endif +#ifdef SYS_mq_timedsend +#ifdef __NR_mq_timedsend + {"mq_timedsend", __NR_mq_timedsend}, +#endif +#endif +#ifdef SYS_mq_unlink +#ifdef __NR_mq_unlink + {"mq_unlink", __NR_mq_unlink}, +#endif +#endif +#ifdef SYS_mremap +#ifdef __NR_mremap + {"mremap", __NR_mremap}, +#endif +#endif +#ifdef SYS_msync +#ifdef __NR_msync + {"msync", __NR_msync}, +#endif +#endif +#ifdef SYS_munlock +#ifdef __NR_munlock + {"munlock", __NR_munlock}, +#endif +#endif +#ifdef SYS_munlockall +#ifdef __NR_munlockall + {"munlockall", __NR_munlockall}, +#endif +#endif +#ifdef SYS_munmap +#ifdef __NR_munmap + {"munmap", __NR_munmap}, +#endif +#endif +#ifdef SYS_name_to_handle_at +#ifdef __NR_name_to_handle_at + {"name_to_handle_at", __NR_name_to_handle_at}, +#endif +#endif +#ifdef SYS_nanosleep +#ifdef __NR_nanosleep + {"nanosleep", __NR_nanosleep}, +#endif +#endif +#ifdef SYS_nfsservctl +#ifdef __NR_nfsservctl + {"nfsservctl", __NR_nfsservctl}, +#endif +#endif +#ifdef SYS_nice +#ifdef __NR_nice + {"nice", __NR_nice}, +#endif +#endif +#ifdef SYS_oldfstat +#ifdef __NR_oldfstat + {"oldfstat", __NR_oldfstat}, +#endif +#endif +#ifdef SYS_oldlstat +#ifdef __NR_oldlstat + {"oldlstat", __NR_oldlstat}, +#endif +#endif +#ifdef SYS_oldolduname +#ifdef __NR_oldolduname + {"oldolduname", __NR_oldolduname}, +#endif +#endif +#ifdef SYS_oldstat +#ifdef __NR_oldstat + {"oldstat", __NR_oldstat}, +#endif +#endif +#ifdef SYS_olduname +#ifdef __NR_olduname + {"olduname", __NR_olduname}, +#endif +#endif +#ifdef SYS_open +#ifdef __NR_open + {"open", __NR_open}, +#endif +#endif +#ifdef SYS_open_by_handle_at +#ifdef __NR_open_by_handle_at + {"open_by_handle_at", __NR_open_by_handle_at}, +#endif +#endif +#ifdef SYS_openat +#ifdef __NR_openat + {"openat", __NR_openat}, +#endif +#endif +#ifdef SYS_pause +#ifdef __NR_pause + {"pause", __NR_pause}, +#endif +#endif +#ifdef SYS_perf_event_open +#ifdef __NR_perf_event_open + {"perf_event_open", __NR_perf_event_open}, +#endif +#endif +#ifdef SYS_personality +#ifdef __NR_personality + {"personality", __NR_personality}, +#endif +#endif +#ifdef SYS_pipe +#ifdef __NR_pipe + {"pipe", __NR_pipe}, +#endif +#endif +#ifdef SYS_pipe2 +#ifdef __NR_pipe2 + {"pipe2", __NR_pipe2}, +#endif +#endif +#ifdef SYS_pivot_root +#ifdef __NR_pivot_root + {"pivot_root", __NR_pivot_root}, +#endif +#endif +#ifdef SYS_poll +#ifdef __NR_poll + {"poll", __NR_poll}, +#endif +#endif +#ifdef SYS_ppoll +#ifdef __NR_ppoll + {"ppoll", __NR_ppoll}, +#endif +#endif +#ifdef SYS_prctl +#ifdef __NR_prctl + {"prctl", __NR_prctl}, +#endif +#endif +#ifdef SYS_pread64 +#ifdef __NR_pread64 + {"pread64", __NR_pread64}, +#endif +#endif +#ifdef SYS_preadv +#ifdef __NR_preadv + {"preadv", __NR_preadv}, +#endif +#endif +#ifdef SYS_prlimit64 +#ifdef __NR_prlimit64 + {"prlimit64", __NR_prlimit64}, +#endif +#endif +#ifdef SYS_process_vm_readv +#ifdef __NR_process_vm_readv + {"process_vm_readv", __NR_process_vm_readv}, +#endif +#endif +#ifdef SYS_process_vm_writev +#ifdef __NR_process_vm_writev + {"process_vm_writev", __NR_process_vm_writev}, +#endif +#endif +#ifdef SYS_prof +#ifdef __NR_prof + {"prof", __NR_prof}, +#endif +#endif +#ifdef SYS_profil +#ifdef __NR_profil + {"profil", __NR_profil}, +#endif +#endif +#ifdef SYS_pselect6 +#ifdef __NR_pselect6 + {"pselect6", __NR_pselect6}, +#endif +#endif +#ifdef SYS_ptrace +#ifdef __NR_ptrace + {"ptrace", __NR_ptrace}, +#endif +#endif +#ifdef SYS_putpmsg +#ifdef __NR_putpmsg + {"putpmsg", __NR_putpmsg}, +#endif +#endif +#ifdef SYS_pwrite64 +#ifdef __NR_pwrite64 + {"pwrite64", __NR_pwrite64}, +#endif +#endif +#ifdef SYS_pwritev +#ifdef __NR_pwritev + {"pwritev", __NR_pwritev}, +#endif +#endif +#ifdef SYS_query_module +#ifdef __NR_query_module + {"query_module", __NR_query_module}, +#endif +#endif +#ifdef SYS_quotactl +#ifdef __NR_quotactl + {"quotactl", __NR_quotactl}, +#endif +#endif +#ifdef SYS_read +#ifdef __NR_read + {"read", __NR_read}, +#endif +#endif +#ifdef SYS_readahead +#ifdef __NR_readahead + {"readahead", __NR_readahead}, +#endif +#endif +#ifdef SYS_readdir +#ifdef __NR_readdir + {"readdir", __NR_readdir}, +#endif +#endif +#ifdef SYS_readlink +#ifdef __NR_readlink + {"readlink", __NR_readlink}, +#endif +#endif +#ifdef SYS_readlinkat +#ifdef __NR_readlinkat + {"readlinkat", __NR_readlinkat}, +#endif +#endif +#ifdef SYS_readv +#ifdef __NR_readv + {"readv", __NR_readv}, +#endif +#endif +#ifdef SYS_reboot +#ifdef __NR_reboot + {"reboot", __NR_reboot}, +#endif +#endif +#ifdef SYS_recvmmsg +#ifdef __NR_recvmmsg + {"recvmmsg", __NR_recvmmsg}, +#endif +#endif +#ifdef SYS_remap_file_pages +#ifdef __NR_remap_file_pages + {"remap_file_pages", __NR_remap_file_pages}, +#endif +#endif +#ifdef SYS_removexattr +#ifdef __NR_removexattr + {"removexattr", __NR_removexattr}, +#endif +#endif +#ifdef SYS_rename +#ifdef __NR_rename + {"rename", __NR_rename}, +#endif +#endif +#ifdef SYS_renameat +#ifdef __NR_renameat + {"renameat", __NR_renameat}, +#endif +#endif +#ifdef SYS_request_key +#ifdef __NR_request_key + {"request_key", __NR_request_key}, +#endif +#endif +#ifdef SYS_restart_syscall +#ifdef __NR_restart_syscall + {"restart_syscall", __NR_restart_syscall}, +#endif +#endif +#ifdef SYS_rmdir +#ifdef __NR_rmdir + {"rmdir", __NR_rmdir}, +#endif +#endif +#ifdef SYS_rt_sigaction +#ifdef __NR_rt_sigaction + {"rt_sigaction", __NR_rt_sigaction}, +#endif +#endif +#ifdef SYS_rt_sigpending +#ifdef __NR_rt_sigpending + {"rt_sigpending", __NR_rt_sigpending}, +#endif +#endif +#ifdef SYS_rt_sigprocmask +#ifdef __NR_rt_sigprocmask + {"rt_sigprocmask", __NR_rt_sigprocmask}, +#endif +#endif +#ifdef SYS_rt_sigqueueinfo +#ifdef __NR_rt_sigqueueinfo + {"rt_sigqueueinfo", __NR_rt_sigqueueinfo}, +#endif +#endif +#ifdef SYS_rt_sigreturn +#ifdef __NR_rt_sigreturn + {"rt_sigreturn", __NR_rt_sigreturn}, +#endif +#endif +#ifdef SYS_rt_sigsuspend +#ifdef __NR_rt_sigsuspend + {"rt_sigsuspend", __NR_rt_sigsuspend}, +#endif +#endif +#ifdef SYS_rt_sigtimedwait +#ifdef __NR_rt_sigtimedwait + {"rt_sigtimedwait", __NR_rt_sigtimedwait}, +#endif +#endif +#ifdef SYS_rt_tgsigqueueinfo +#ifdef __NR_rt_tgsigqueueinfo + {"rt_tgsigqueueinfo", __NR_rt_tgsigqueueinfo}, +#endif +#endif +#ifdef SYS_sched_get_priority_max +#ifdef __NR_sched_get_priority_max + {"sched_get_priority_max", __NR_sched_get_priority_max}, +#endif +#endif +#ifdef SYS_sched_get_priority_min +#ifdef __NR_sched_get_priority_min + {"sched_get_priority_min", __NR_sched_get_priority_min}, +#endif +#endif +#ifdef SYS_sched_getaffinity +#ifdef __NR_sched_getaffinity + {"sched_getaffinity", __NR_sched_getaffinity}, +#endif +#endif +#ifdef SYS_sched_getparam +#ifdef __NR_sched_getparam + {"sched_getparam", __NR_sched_getparam}, +#endif +#endif +#ifdef SYS_sched_getscheduler +#ifdef __NR_sched_getscheduler + {"sched_getscheduler", __NR_sched_getscheduler}, +#endif +#endif +#ifdef SYS_sched_rr_get_interval +#ifdef __NR_sched_rr_get_interval + {"sched_rr_get_interval", __NR_sched_rr_get_interval}, +#endif +#endif +#ifdef SYS_sched_setaffinity +#ifdef __NR_sched_setaffinity + {"sched_setaffinity", __NR_sched_setaffinity}, +#endif +#endif +#ifdef SYS_sched_setparam +#ifdef __NR_sched_setparam + {"sched_setparam", __NR_sched_setparam}, +#endif +#endif +#ifdef SYS_sched_setscheduler +#ifdef __NR_sched_setscheduler + {"sched_setscheduler", __NR_sched_setscheduler}, +#endif +#endif +#ifdef SYS_sched_yield +#ifdef __NR_sched_yield + {"sched_yield", __NR_sched_yield}, +#endif +#endif +#ifdef SYS_select +#ifdef __NR_select + {"select", __NR_select}, +#endif +#endif +#ifdef SYS_sendfile +#ifdef __NR_sendfile + {"sendfile", __NR_sendfile}, +#endif +#endif +#ifdef SYS_sendfile64 +#ifdef __NR_sendfile64 + {"sendfile64", __NR_sendfile64}, +#endif +#endif +#ifdef SYS_sendmmsg +#ifdef __NR_sendmmsg + {"sendmmsg", __NR_sendmmsg}, +#endif +#endif +#ifdef SYS_set_mempolicy +#ifdef __NR_set_mempolicy + {"set_mempolicy", __NR_set_mempolicy}, +#endif +#endif +#ifdef SYS_set_robust_list +#ifdef __NR_set_robust_list + {"set_robust_list", __NR_set_robust_list}, +#endif +#endif +#ifdef SYS_set_thread_area +#ifdef __NR_set_thread_area + {"set_thread_area", __NR_set_thread_area}, +#endif +#endif +#ifdef SYS_set_tid_address +#ifdef __NR_set_tid_address + {"set_tid_address", __NR_set_tid_address}, +#endif +#endif +#ifdef SYS_setdomainname +#ifdef __NR_setdomainname + {"setdomainname", __NR_setdomainname}, +#endif +#endif +#ifdef SYS_setfsgid +#ifdef __NR_setfsgid + {"setfsgid", __NR_setfsgid}, +#endif +#endif +#ifdef SYS_setfsgid32 +#ifdef __NR_setfsgid32 + {"setfsgid32", __NR_setfsgid32}, +#endif +#endif +#ifdef SYS_setfsuid +#ifdef __NR_setfsuid + {"setfsuid", __NR_setfsuid}, +#endif +#endif +#ifdef SYS_setfsuid32 +#ifdef __NR_setfsuid32 + {"setfsuid32", __NR_setfsuid32}, +#endif +#endif +#ifdef SYS_setgid +#ifdef __NR_setgid + {"setgid", __NR_setgid}, +#endif +#endif +#ifdef SYS_setgid32 +#ifdef __NR_setgid32 + {"setgid32", __NR_setgid32}, +#endif +#endif +#ifdef SYS_setgroups +#ifdef __NR_setgroups + {"setgroups", __NR_setgroups}, +#endif +#endif +#ifdef SYS_setgroups32 +#ifdef __NR_setgroups32 + {"setgroups32", __NR_setgroups32}, +#endif +#endif +#ifdef SYS_sethostname +#ifdef __NR_sethostname + {"sethostname", __NR_sethostname}, +#endif +#endif +#ifdef SYS_setitimer +#ifdef __NR_setitimer + {"setitimer", __NR_setitimer}, +#endif +#endif +#ifdef SYS_setns +#ifdef __NR_setns + {"setns", __NR_setns}, +#endif +#endif +#ifdef SYS_setpgid +#ifdef __NR_setpgid + {"setpgid", __NR_setpgid}, +#endif +#endif +#ifdef SYS_setpriority +#ifdef __NR_setpriority + {"setpriority", __NR_setpriority}, +#endif +#endif +#ifdef SYS_setregid +#ifdef __NR_setregid + {"setregid", __NR_setregid}, +#endif +#endif +#ifdef SYS_setregid32 +#ifdef __NR_setregid32 + {"setregid32", __NR_setregid32}, +#endif +#endif +#ifdef SYS_setresgid +#ifdef __NR_setresgid + {"setresgid", __NR_setresgid}, +#endif +#endif +#ifdef SYS_setresgid32 +#ifdef __NR_setresgid32 + {"setresgid32", __NR_setresgid32}, +#endif +#endif +#ifdef SYS_setresuid +#ifdef __NR_setresuid + {"setresuid", __NR_setresuid}, +#endif +#endif +#ifdef SYS_setresuid32 +#ifdef __NR_setresuid32 + {"setresuid32", __NR_setresuid32}, +#endif +#endif +#ifdef SYS_setreuid +#ifdef __NR_setreuid + {"setreuid", __NR_setreuid}, +#endif +#endif +#ifdef SYS_setreuid32 +#ifdef __NR_setreuid32 + {"setreuid32", __NR_setreuid32}, +#endif +#endif +#ifdef SYS_setrlimit +#ifdef __NR_setrlimit + {"setrlimit", __NR_setrlimit}, +#endif +#endif +#ifdef SYS_setsid +#ifdef __NR_setsid + {"setsid", __NR_setsid}, +#endif +#endif +#ifdef SYS_settimeofday +#ifdef __NR_settimeofday + {"settimeofday", __NR_settimeofday}, +#endif +#endif +#ifdef SYS_setuid +#ifdef __NR_setuid + {"setuid", __NR_setuid}, +#endif +#endif +#ifdef SYS_setuid32 +#ifdef __NR_setuid32 + {"setuid32", __NR_setuid32}, +#endif +#endif +#ifdef SYS_setxattr +#ifdef __NR_setxattr + {"setxattr", __NR_setxattr}, +#endif +#endif +#ifdef SYS_sgetmask +#ifdef __NR_sgetmask + {"sgetmask", __NR_sgetmask}, +#endif +#endif +#ifdef SYS_sigaction +#ifdef __NR_sigaction + {"sigaction", __NR_sigaction}, +#endif +#endif +#ifdef SYS_sigaltstack +#ifdef __NR_sigaltstack + {"sigaltstack", __NR_sigaltstack}, +#endif +#endif +#ifdef SYS_signal +#ifdef __NR_signal + {"signal", __NR_signal}, +#endif +#endif +#ifdef SYS_signalfd +#ifdef __NR_signalfd + {"signalfd", __NR_signalfd}, +#endif +#endif +#ifdef SYS_signalfd4 +#ifdef __NR_signalfd4 + {"signalfd4", __NR_signalfd4}, +#endif +#endif +#ifdef SYS_sigpending +#ifdef __NR_sigpending + {"sigpending", __NR_sigpending}, +#endif +#endif +#ifdef SYS_sigprocmask +#ifdef __NR_sigprocmask + {"sigprocmask", __NR_sigprocmask}, +#endif +#endif +#ifdef SYS_sigreturn +#ifdef __NR_sigreturn + {"sigreturn", __NR_sigreturn}, +#endif +#endif +#ifdef SYS_sigsuspend +#ifdef __NR_sigsuspend + {"sigsuspend", __NR_sigsuspend}, +#endif +#endif +#ifdef SYS_socketcall +#ifdef __NR_socketcall + {"socketcall", __NR_socketcall}, +#endif +#endif +#ifdef SYS_splice +#ifdef __NR_splice + {"splice", __NR_splice}, +#endif +#endif +#ifdef SYS_ssetmask +#ifdef __NR_ssetmask + {"ssetmask", __NR_ssetmask}, +#endif +#endif +#ifdef SYS_stat +#ifdef __NR_stat + {"stat", __NR_stat}, +#endif +#endif +#ifdef SYS_stat64 +#ifdef __NR_stat64 + {"stat64", __NR_stat64}, +#endif +#endif +#ifdef SYS_statfs +#ifdef __NR_statfs + {"statfs", __NR_statfs}, +#endif +#endif +#ifdef SYS_statfs64 +#ifdef __NR_statfs64 + {"statfs64", __NR_statfs64}, +#endif +#endif +#ifdef SYS_stime +#ifdef __NR_stime + {"stime", __NR_stime}, +#endif +#endif +#ifdef SYS_stty +#ifdef __NR_stty + {"stty", __NR_stty}, +#endif +#endif +#ifdef SYS_swapoff +#ifdef __NR_swapoff + {"swapoff", __NR_swapoff}, +#endif +#endif +#ifdef SYS_swapon +#ifdef __NR_swapon + {"swapon", __NR_swapon}, +#endif +#endif +#ifdef SYS_symlink +#ifdef __NR_symlink + {"symlink", __NR_symlink}, +#endif +#endif +#ifdef SYS_symlinkat +#ifdef __NR_symlinkat + {"symlinkat", __NR_symlinkat}, +#endif +#endif +#ifdef SYS_sync +#ifdef __NR_sync + {"sync", __NR_sync}, +#endif +#endif +#ifdef SYS_sync_file_range +#ifdef __NR_sync_file_range + {"sync_file_range", __NR_sync_file_range}, +#endif +#endif +#ifdef SYS_syncfs +#ifdef __NR_syncfs + {"syncfs", __NR_syncfs}, +#endif +#endif +#ifdef SYS_sysfs +#ifdef __NR_sysfs + {"sysfs", __NR_sysfs}, +#endif +#endif +#ifdef SYS_sysinfo +#ifdef __NR_sysinfo + {"sysinfo", __NR_sysinfo}, +#endif +#endif +#ifdef SYS_syslog +#ifdef __NR_syslog + {"syslog", __NR_syslog}, +#endif +#endif +#ifdef SYS_tee +#ifdef __NR_tee + {"tee", __NR_tee}, +#endif +#endif +#ifdef SYS_tgkill +#ifdef __NR_tgkill + {"tgkill", __NR_tgkill}, +#endif +#endif +#ifdef SYS_time +#ifdef __NR_time + {"time", __NR_time}, +#endif +#endif +#ifdef SYS_timer_create +#ifdef __NR_timer_create + {"timer_create", __NR_timer_create}, +#endif +#endif +#ifdef SYS_timer_delete +#ifdef __NR_timer_delete + {"timer_delete", __NR_timer_delete}, +#endif +#endif +#ifdef SYS_timer_getoverrun +#ifdef __NR_timer_getoverrun + {"timer_getoverrun", __NR_timer_getoverrun}, +#endif +#endif +#ifdef SYS_timer_gettime +#ifdef __NR_timer_gettime + {"timer_gettime", __NR_timer_gettime}, +#endif +#endif +#ifdef SYS_timer_settime +#ifdef __NR_timer_settime + {"timer_settime", __NR_timer_settime}, +#endif +#endif +#ifdef SYS_timerfd_create +#ifdef __NR_timerfd_create + {"timerfd_create", __NR_timerfd_create}, +#endif +#endif +#ifdef SYS_timerfd_gettime +#ifdef __NR_timerfd_gettime + {"timerfd_gettime", __NR_timerfd_gettime}, +#endif +#endif +#ifdef SYS_timerfd_settime +#ifdef __NR_timerfd_settime + {"timerfd_settime", __NR_timerfd_settime}, +#endif +#endif +#ifdef SYS_times +#ifdef __NR_times + {"times", __NR_times}, +#endif +#endif +#ifdef SYS_tkill +#ifdef __NR_tkill + {"tkill", __NR_tkill}, +#endif +#endif +#ifdef SYS_truncate +#ifdef __NR_truncate + {"truncate", __NR_truncate}, +#endif +#endif +#ifdef SYS_truncate64 +#ifdef __NR_truncate64 + {"truncate64", __NR_truncate64}, +#endif +#endif +#ifdef SYS_ugetrlimit +#ifdef __NR_ugetrlimit + {"ugetrlimit", __NR_ugetrlimit}, +#endif +#endif +#ifdef SYS_ulimit +#ifdef __NR_ulimit + {"ulimit", __NR_ulimit}, +#endif +#endif +#ifdef SYS_umask +#ifdef __NR_umask + {"umask", __NR_umask}, +#endif +#endif +#ifdef SYS_umount +#ifdef __NR_umount + {"umount", __NR_umount}, +#endif +#endif +#ifdef SYS_umount2 +#ifdef __NR_umount2 + {"umount2", __NR_umount2}, +#endif +#endif +#ifdef SYS_uname +#ifdef __NR_uname + {"uname", __NR_uname}, +#endif +#endif +#ifdef SYS_unlink +#ifdef __NR_unlink + {"unlink", __NR_unlink}, +#endif +#endif +#ifdef SYS_unlinkat +#ifdef __NR_unlinkat + {"unlinkat", __NR_unlinkat}, +#endif +#endif +#ifdef SYS_unshare +#ifdef __NR_unshare + {"unshare", __NR_unshare}, +#endif +#endif +#ifdef SYS_uselib +#ifdef __NR_uselib + {"uselib", __NR_uselib}, +#endif +#endif +#ifdef SYS_ustat +#ifdef __NR_ustat + {"ustat", __NR_ustat}, +#endif +#endif +#ifdef SYS_utime +#ifdef __NR_utime + {"utime", __NR_utime}, +#endif +#endif +#ifdef SYS_utimensat +#ifdef __NR_utimensat + {"utimensat", __NR_utimensat}, +#endif +#endif +#ifdef SYS_utimes +#ifdef __NR_utimes + {"utimes", __NR_utimes}, +#endif +#endif +#ifdef SYS_vfork +#ifdef __NR_vfork + {"vfork", __NR_vfork}, +#endif +#endif +#ifdef SYS_vhangup +#ifdef __NR_vhangup + {"vhangup", __NR_vhangup}, +#endif +#endif +#ifdef SYS_vm86 +#ifdef __NR_vm86 + {"vm86", __NR_vm86}, +#endif +#endif +#ifdef SYS_vm86old +#ifdef __NR_vm86old + {"vm86old", __NR_vm86old}, +#endif +#endif +#ifdef SYS_vmsplice +#ifdef __NR_vmsplice + {"vmsplice", __NR_vmsplice}, +#endif +#endif +#ifdef SYS_vserver +#ifdef __NR_vserver + {"vserver", __NR_vserver}, +#endif +#endif +#ifdef SYS_wait4 +#ifdef __NR_wait4 + {"wait4", __NR_wait4}, +#endif +#endif +#ifdef SYS_waitid +#ifdef __NR_waitid + {"waitid", __NR_waitid}, +#endif +#endif +#ifdef SYS_waitpid +#ifdef __NR_waitpid + {"waitpid", __NR_waitpid}, +#endif +#endif +#ifdef SYS_write +#ifdef __NR_write + {"write", __NR_write}, +#endif +#endif +#ifdef SYS_writev +#ifdef __NR_writev + {"writev", __NR_writev}, +#endif +#endif +#endif +#if defined __x86_64__ && defined __LP64__ +#ifdef SYS__sysctl +#ifdef __NR__sysctl + {"_sysctl", __NR__sysctl}, +#endif +#endif +#ifdef SYS_accept +#ifdef __NR_accept + {"accept", __NR_accept}, +#endif +#endif +#ifdef SYS_accept4 +#ifdef __NR_accept4 + {"accept4", __NR_accept4}, +#endif +#endif +#ifdef SYS_access +#ifdef __NR_access + {"access", __NR_access}, +#endif +#endif +#ifdef SYS_acct +#ifdef __NR_acct + {"acct", __NR_acct}, +#endif +#endif +#ifdef SYS_add_key +#ifdef __NR_add_key + {"add_key", __NR_add_key}, +#endif +#endif +#ifdef SYS_adjtimex +#ifdef __NR_adjtimex + {"adjtimex", __NR_adjtimex}, +#endif +#endif +#ifdef SYS_afs_syscall +#ifdef __NR_afs_syscall + {"afs_syscall", __NR_afs_syscall}, +#endif +#endif +#ifdef SYS_alarm +#ifdef __NR_alarm + {"alarm", __NR_alarm}, +#endif +#endif +#ifdef SYS_arch_prctl +#ifdef __NR_arch_prctl + {"arch_prctl", __NR_arch_prctl}, +#endif +#endif +#ifdef SYS_bind +#ifdef __NR_bind + {"bind", __NR_bind}, +#endif +#endif +#ifdef SYS_brk +#ifdef __NR_brk + {"brk", __NR_brk}, +#endif +#endif +#ifdef SYS_capget +#ifdef __NR_capget + {"capget", __NR_capget}, +#endif +#endif +#ifdef SYS_capset +#ifdef __NR_capset + {"capset", __NR_capset}, +#endif +#endif +#ifdef SYS_chdir +#ifdef __NR_chdir + {"chdir", __NR_chdir}, +#endif +#endif +#ifdef SYS_chmod +#ifdef __NR_chmod + {"chmod", __NR_chmod}, +#endif +#endif +#ifdef SYS_chown +#ifdef __NR_chown + {"chown", __NR_chown}, +#endif +#endif +#ifdef SYS_chroot +#ifdef __NR_chroot + {"chroot", __NR_chroot}, +#endif +#endif +#ifdef SYS_clock_adjtime +#ifdef __NR_clock_adjtime + {"clock_adjtime", __NR_clock_adjtime}, +#endif +#endif +#ifdef SYS_clock_getres +#ifdef __NR_clock_getres + {"clock_getres", __NR_clock_getres}, +#endif +#endif +#ifdef SYS_clock_gettime +#ifdef __NR_clock_gettime + {"clock_gettime", __NR_clock_gettime}, +#endif +#endif +#ifdef SYS_clock_nanosleep +#ifdef __NR_clock_nanosleep + {"clock_nanosleep", __NR_clock_nanosleep}, +#endif +#endif +#ifdef SYS_clock_settime +#ifdef __NR_clock_settime + {"clock_settime", __NR_clock_settime}, +#endif +#endif +#ifdef SYS_clone +#ifdef __NR_clone + {"clone", __NR_clone}, +#endif +#endif +#ifdef SYS_close +#ifdef __NR_close + {"close", __NR_close}, +#endif +#endif +#ifdef SYS_connect +#ifdef __NR_connect + {"connect", __NR_connect}, +#endif +#endif +#ifdef SYS_creat +#ifdef __NR_creat + {"creat", __NR_creat}, +#endif +#endif +#ifdef SYS_create_module +#ifdef __NR_create_module + {"create_module", __NR_create_module}, +#endif +#endif +#ifdef SYS_delete_module +#ifdef __NR_delete_module + {"delete_module", __NR_delete_module}, +#endif +#endif +#ifdef SYS_dup +#ifdef __NR_dup + {"dup", __NR_dup}, +#endif +#endif +#ifdef SYS_dup2 +#ifdef __NR_dup2 + {"dup2", __NR_dup2}, +#endif +#endif +#ifdef SYS_dup3 +#ifdef __NR_dup3 + {"dup3", __NR_dup3}, +#endif +#endif +#ifdef SYS_epoll_create +#ifdef __NR_epoll_create + {"epoll_create", __NR_epoll_create}, +#endif +#endif +#ifdef SYS_epoll_create1 +#ifdef __NR_epoll_create1 + {"epoll_create1", __NR_epoll_create1}, +#endif +#endif +#ifdef SYS_epoll_ctl +#ifdef __NR_epoll_ctl + {"epoll_ctl", __NR_epoll_ctl}, +#endif +#endif +#ifdef SYS_epoll_ctl_old +#ifdef __NR_epoll_ctl_old + {"epoll_ctl_old", __NR_epoll_ctl_old}, +#endif +#endif +#ifdef SYS_epoll_pwait +#ifdef __NR_epoll_pwait + {"epoll_pwait", __NR_epoll_pwait}, +#endif +#endif +#ifdef SYS_epoll_wait +#ifdef __NR_epoll_wait + {"epoll_wait", __NR_epoll_wait}, +#endif +#endif +#ifdef SYS_epoll_wait_old +#ifdef __NR_epoll_wait_old + {"epoll_wait_old", __NR_epoll_wait_old}, +#endif +#endif +#ifdef SYS_eventfd +#ifdef __NR_eventfd + {"eventfd", __NR_eventfd}, +#endif +#endif +#ifdef SYS_eventfd2 +#ifdef __NR_eventfd2 + {"eventfd2", __NR_eventfd2}, +#endif +#endif +#ifdef SYS_execve +#ifdef __NR_execve + {"execve", __NR_execve}, +#endif +#endif +#ifdef SYS_exit +#ifdef __NR_exit + {"exit", __NR_exit}, +#endif +#endif +#ifdef SYS_exit_group +#ifdef __NR_exit_group + {"exit_group", __NR_exit_group}, +#endif +#endif +#ifdef SYS_faccessat +#ifdef __NR_faccessat + {"faccessat", __NR_faccessat}, +#endif +#endif +#ifdef SYS_fadvise64 +#ifdef __NR_fadvise64 + {"fadvise64", __NR_fadvise64}, +#endif +#endif +#ifdef SYS_fallocate +#ifdef __NR_fallocate + {"fallocate", __NR_fallocate}, +#endif +#endif +#ifdef SYS_fanotify_init +#ifdef __NR_fanotify_init + {"fanotify_init", __NR_fanotify_init}, +#endif +#endif +#ifdef SYS_fanotify_mark +#ifdef __NR_fanotify_mark + {"fanotify_mark", __NR_fanotify_mark}, +#endif +#endif +#ifdef SYS_fchdir +#ifdef __NR_fchdir + {"fchdir", __NR_fchdir}, +#endif +#endif +#ifdef SYS_fchmod +#ifdef __NR_fchmod + {"fchmod", __NR_fchmod}, +#endif +#endif +#ifdef SYS_fchmodat +#ifdef __NR_fchmodat + {"fchmodat", __NR_fchmodat}, +#endif +#endif +#ifdef SYS_fchown +#ifdef __NR_fchown + {"fchown", __NR_fchown}, +#endif +#endif +#ifdef SYS_fchownat +#ifdef __NR_fchownat + {"fchownat", __NR_fchownat}, +#endif +#endif +#ifdef SYS_fcntl +#ifdef __NR_fcntl + {"fcntl", __NR_fcntl}, +#endif +#endif +#ifdef SYS_fdatasync +#ifdef __NR_fdatasync + {"fdatasync", __NR_fdatasync}, +#endif +#endif +#ifdef SYS_fgetxattr +#ifdef __NR_fgetxattr + {"fgetxattr", __NR_fgetxattr}, +#endif +#endif +#ifdef SYS_finit_module +#ifdef __NR_finit_module + {"finit_module", __NR_finit_module}, +#endif +#endif +#ifdef SYS_flistxattr +#ifdef __NR_flistxattr + {"flistxattr", __NR_flistxattr}, +#endif +#endif +#ifdef SYS_flock +#ifdef __NR_flock + {"flock", __NR_flock}, +#endif +#endif +#ifdef SYS_fork +#ifdef __NR_fork + {"fork", __NR_fork}, +#endif +#endif +#ifdef SYS_fremovexattr +#ifdef __NR_fremovexattr + {"fremovexattr", __NR_fremovexattr}, +#endif +#endif +#ifdef SYS_fsetxattr +#ifdef __NR_fsetxattr + {"fsetxattr", __NR_fsetxattr}, +#endif +#endif +#ifdef SYS_fstat +#ifdef __NR_fstat + {"fstat", __NR_fstat}, +#endif +#endif +#ifdef SYS_fstatfs +#ifdef __NR_fstatfs + {"fstatfs", __NR_fstatfs}, +#endif +#endif +#ifdef SYS_fsync +#ifdef __NR_fsync + {"fsync", __NR_fsync}, +#endif +#endif +#ifdef SYS_ftruncate +#ifdef __NR_ftruncate + {"ftruncate", __NR_ftruncate}, +#endif +#endif +#ifdef SYS_futex +#ifdef __NR_futex + {"futex", __NR_futex}, +#endif +#endif +#ifdef SYS_futimesat +#ifdef __NR_futimesat + {"futimesat", __NR_futimesat}, +#endif +#endif +#ifdef SYS_get_kernel_syms +#ifdef __NR_get_kernel_syms + {"get_kernel_syms", __NR_get_kernel_syms}, +#endif +#endif +#ifdef SYS_get_mempolicy +#ifdef __NR_get_mempolicy + {"get_mempolicy", __NR_get_mempolicy}, +#endif +#endif +#ifdef SYS_get_robust_list +#ifdef __NR_get_robust_list + {"get_robust_list", __NR_get_robust_list}, +#endif +#endif +#ifdef SYS_get_thread_area +#ifdef __NR_get_thread_area + {"get_thread_area", __NR_get_thread_area}, +#endif +#endif +#ifdef SYS_getcpu +#ifdef __NR_getcpu + {"getcpu", __NR_getcpu}, +#endif +#endif +#ifdef SYS_getcwd +#ifdef __NR_getcwd + {"getcwd", __NR_getcwd}, +#endif +#endif +#ifdef SYS_getdents +#ifdef __NR_getdents + {"getdents", __NR_getdents}, +#endif +#endif +#ifdef SYS_getdents64 +#ifdef __NR_getdents64 + {"getdents64", __NR_getdents64}, +#endif +#endif +#ifdef SYS_getegid +#ifdef __NR_getegid + {"getegid", __NR_getegid}, +#endif +#endif +#ifdef SYS_geteuid +#ifdef __NR_geteuid + {"geteuid", __NR_geteuid}, +#endif +#endif +#ifdef SYS_getgid +#ifdef __NR_getgid + {"getgid", __NR_getgid}, +#endif +#endif +#ifdef SYS_getgroups +#ifdef __NR_getgroups + {"getgroups", __NR_getgroups}, +#endif +#endif +#ifdef SYS_getitimer +#ifdef __NR_getitimer + {"getitimer", __NR_getitimer}, +#endif +#endif +#ifdef SYS_getpeername +#ifdef __NR_getpeername + {"getpeername", __NR_getpeername}, +#endif +#endif +#ifdef SYS_getpgid +#ifdef __NR_getpgid + {"getpgid", __NR_getpgid}, +#endif +#endif +#ifdef SYS_getpgrp +#ifdef __NR_getpgrp + {"getpgrp", __NR_getpgrp}, +#endif +#endif +#ifdef SYS_getpid +#ifdef __NR_getpid + {"getpid", __NR_getpid}, +#endif +#endif +#ifdef SYS_getpmsg +#ifdef __NR_getpmsg + {"getpmsg", __NR_getpmsg}, +#endif +#endif +#ifdef SYS_getppid +#ifdef __NR_getppid + {"getppid", __NR_getppid}, +#endif +#endif +#ifdef SYS_getpriority +#ifdef __NR_getpriority + {"getpriority", __NR_getpriority}, +#endif +#endif +#ifdef SYS_getresgid +#ifdef __NR_getresgid + {"getresgid", __NR_getresgid}, +#endif +#endif +#ifdef SYS_getresuid +#ifdef __NR_getresuid + {"getresuid", __NR_getresuid}, +#endif +#endif +#ifdef SYS_getrlimit +#ifdef __NR_getrlimit + {"getrlimit", __NR_getrlimit}, +#endif +#endif +#ifdef SYS_getrusage +#ifdef __NR_getrusage + {"getrusage", __NR_getrusage}, +#endif +#endif +#ifdef SYS_getsid +#ifdef __NR_getsid + {"getsid", __NR_getsid}, +#endif +#endif +#ifdef SYS_getsockname +#ifdef __NR_getsockname + {"getsockname", __NR_getsockname}, +#endif +#endif +#ifdef SYS_getsockopt +#ifdef __NR_getsockopt + {"getsockopt", __NR_getsockopt}, +#endif +#endif +#ifdef SYS_gettid +#ifdef __NR_gettid + {"gettid", __NR_gettid}, +#endif +#endif +#ifdef SYS_gettimeofday +#ifdef __NR_gettimeofday + {"gettimeofday", __NR_gettimeofday}, +#endif +#endif +#ifdef SYS_getuid +#ifdef __NR_getuid + {"getuid", __NR_getuid}, +#endif +#endif +#ifdef SYS_getxattr +#ifdef __NR_getxattr + {"getxattr", __NR_getxattr}, +#endif +#endif +#ifdef SYS_init_module +#ifdef __NR_init_module + {"init_module", __NR_init_module}, +#endif +#endif +#ifdef SYS_inotify_add_watch +#ifdef __NR_inotify_add_watch + {"inotify_add_watch", __NR_inotify_add_watch}, +#endif +#endif +#ifdef SYS_inotify_init +#ifdef __NR_inotify_init + {"inotify_init", __NR_inotify_init}, +#endif +#endif +#ifdef SYS_inotify_init1 +#ifdef __NR_inotify_init1 + {"inotify_init1", __NR_inotify_init1}, +#endif +#endif +#ifdef SYS_inotify_rm_watch +#ifdef __NR_inotify_rm_watch + {"inotify_rm_watch", __NR_inotify_rm_watch}, +#endif +#endif +#ifdef SYS_io_cancel +#ifdef __NR_io_cancel + {"io_cancel", __NR_io_cancel}, +#endif +#endif +#ifdef SYS_io_destroy +#ifdef __NR_io_destroy + {"io_destroy", __NR_io_destroy}, +#endif +#endif +#ifdef SYS_io_getevents +#ifdef __NR_io_getevents + {"io_getevents", __NR_io_getevents}, +#endif +#endif +#ifdef SYS_io_setup +#ifdef __NR_io_setup + {"io_setup", __NR_io_setup}, +#endif +#endif +#ifdef SYS_io_submit +#ifdef __NR_io_submit + {"io_submit", __NR_io_submit}, +#endif +#endif +#ifdef SYS_ioctl +#ifdef __NR_ioctl + {"ioctl", __NR_ioctl}, +#endif +#endif +#ifdef SYS_ioperm +#ifdef __NR_ioperm + {"ioperm", __NR_ioperm}, +#endif +#endif +#ifdef SYS_iopl +#ifdef __NR_iopl + {"iopl", __NR_iopl}, +#endif +#endif +#ifdef SYS_ioprio_get +#ifdef __NR_ioprio_get + {"ioprio_get", __NR_ioprio_get}, +#endif +#endif +#ifdef SYS_ioprio_set +#ifdef __NR_ioprio_set + {"ioprio_set", __NR_ioprio_set}, +#endif +#endif +#ifdef SYS_kcmp +#ifdef __NR_kcmp + {"kcmp", __NR_kcmp}, +#endif +#endif +#ifdef SYS_kexec_load +#ifdef __NR_kexec_load + {"kexec_load", __NR_kexec_load}, +#endif +#endif +#ifdef SYS_keyctl +#ifdef __NR_keyctl + {"keyctl", __NR_keyctl}, +#endif +#endif +#ifdef SYS_kill +#ifdef __NR_kill + {"kill", __NR_kill}, +#endif +#endif +#ifdef SYS_lchown +#ifdef __NR_lchown + {"lchown", __NR_lchown}, +#endif +#endif +#ifdef SYS_lgetxattr +#ifdef __NR_lgetxattr + {"lgetxattr", __NR_lgetxattr}, +#endif +#endif +#ifdef SYS_link +#ifdef __NR_link + {"link", __NR_link}, +#endif +#endif +#ifdef SYS_linkat +#ifdef __NR_linkat + {"linkat", __NR_linkat}, +#endif +#endif +#ifdef SYS_listen +#ifdef __NR_listen + {"listen", __NR_listen}, +#endif +#endif +#ifdef SYS_listxattr +#ifdef __NR_listxattr + {"listxattr", __NR_listxattr}, +#endif +#endif +#ifdef SYS_llistxattr +#ifdef __NR_llistxattr + {"llistxattr", __NR_llistxattr}, +#endif +#endif +#ifdef SYS_lookup_dcookie +#ifdef __NR_lookup_dcookie + {"lookup_dcookie", __NR_lookup_dcookie}, +#endif +#endif +#ifdef SYS_lremovexattr +#ifdef __NR_lremovexattr + {"lremovexattr", __NR_lremovexattr}, +#endif +#endif +#ifdef SYS_lseek +#ifdef __NR_lseek + {"lseek", __NR_lseek}, +#endif +#endif +#ifdef SYS_lsetxattr +#ifdef __NR_lsetxattr + {"lsetxattr", __NR_lsetxattr}, +#endif +#endif +#ifdef SYS_lstat +#ifdef __NR_lstat + {"lstat", __NR_lstat}, +#endif +#endif +#ifdef SYS_madvise +#ifdef __NR_madvise + {"madvise", __NR_madvise}, +#endif +#endif +#ifdef SYS_mbind +#ifdef __NR_mbind + {"mbind", __NR_mbind}, +#endif +#endif +#ifdef SYS_migrate_pages +#ifdef __NR_migrate_pages + {"migrate_pages", __NR_migrate_pages}, +#endif +#endif +#ifdef SYS_mincore +#ifdef __NR_mincore + {"mincore", __NR_mincore}, +#endif +#endif +#ifdef SYS_mkdir +#ifdef __NR_mkdir + {"mkdir", __NR_mkdir}, +#endif +#endif +#ifdef SYS_mkdirat +#ifdef __NR_mkdirat + {"mkdirat", __NR_mkdirat}, +#endif +#endif +#ifdef SYS_mknod +#ifdef __NR_mknod + {"mknod", __NR_mknod}, +#endif +#endif +#ifdef SYS_mknodat +#ifdef __NR_mknodat + {"mknodat", __NR_mknodat}, +#endif +#endif +#ifdef SYS_mlock +#ifdef __NR_mlock + {"mlock", __NR_mlock}, +#endif +#endif +#ifdef SYS_mlockall +#ifdef __NR_mlockall + {"mlockall", __NR_mlockall}, +#endif +#endif +#ifdef SYS_mmap +#ifdef __NR_mmap + {"mmap", __NR_mmap}, +#endif +#endif +#ifdef SYS_modify_ldt +#ifdef __NR_modify_ldt + {"modify_ldt", __NR_modify_ldt}, +#endif +#endif +#ifdef SYS_mount +#ifdef __NR_mount + {"mount", __NR_mount}, +#endif +#endif +#ifdef SYS_move_pages +#ifdef __NR_move_pages + {"move_pages", __NR_move_pages}, +#endif +#endif +#ifdef SYS_mprotect +#ifdef __NR_mprotect + {"mprotect", __NR_mprotect}, +#endif +#endif +#ifdef SYS_mq_getsetattr +#ifdef __NR_mq_getsetattr + {"mq_getsetattr", __NR_mq_getsetattr}, +#endif +#endif +#ifdef SYS_mq_notify +#ifdef __NR_mq_notify + {"mq_notify", __NR_mq_notify}, +#endif +#endif +#ifdef SYS_mq_open +#ifdef __NR_mq_open + {"mq_open", __NR_mq_open}, +#endif +#endif +#ifdef SYS_mq_timedreceive +#ifdef __NR_mq_timedreceive + {"mq_timedreceive", __NR_mq_timedreceive}, +#endif +#endif +#ifdef SYS_mq_timedsend +#ifdef __NR_mq_timedsend + {"mq_timedsend", __NR_mq_timedsend}, +#endif +#endif +#ifdef SYS_mq_unlink +#ifdef __NR_mq_unlink + {"mq_unlink", __NR_mq_unlink}, +#endif +#endif +#ifdef SYS_mremap +#ifdef __NR_mremap + {"mremap", __NR_mremap}, +#endif +#endif +#ifdef SYS_msgctl +#ifdef __NR_msgctl + {"msgctl", __NR_msgctl}, +#endif +#endif +#ifdef SYS_msgget +#ifdef __NR_msgget + {"msgget", __NR_msgget}, +#endif +#endif +#ifdef SYS_msgrcv +#ifdef __NR_msgrcv + {"msgrcv", __NR_msgrcv}, +#endif +#endif +#ifdef SYS_msgsnd +#ifdef __NR_msgsnd + {"msgsnd", __NR_msgsnd}, +#endif +#endif +#ifdef SYS_msync +#ifdef __NR_msync + {"msync", __NR_msync}, +#endif +#endif +#ifdef SYS_munlock +#ifdef __NR_munlock + {"munlock", __NR_munlock}, +#endif +#endif +#ifdef SYS_munlockall +#ifdef __NR_munlockall + {"munlockall", __NR_munlockall}, +#endif +#endif +#ifdef SYS_munmap +#ifdef __NR_munmap + {"munmap", __NR_munmap}, +#endif +#endif +#ifdef SYS_name_to_handle_at +#ifdef __NR_name_to_handle_at + {"name_to_handle_at", __NR_name_to_handle_at}, +#endif +#endif +#ifdef SYS_nanosleep +#ifdef __NR_nanosleep + {"nanosleep", __NR_nanosleep}, +#endif +#endif +#ifdef SYS_newfstatat +#ifdef __NR_newfstatat + {"newfstatat", __NR_newfstatat}, +#endif +#endif +#ifdef SYS_nfsservctl +#ifdef __NR_nfsservctl + {"nfsservctl", __NR_nfsservctl}, +#endif +#endif +#ifdef SYS_open +#ifdef __NR_open + {"open", __NR_open}, +#endif +#endif +#ifdef SYS_open_by_handle_at +#ifdef __NR_open_by_handle_at + {"open_by_handle_at", __NR_open_by_handle_at}, +#endif +#endif +#ifdef SYS_openat +#ifdef __NR_openat + {"openat", __NR_openat}, +#endif +#endif +#ifdef SYS_pause +#ifdef __NR_pause + {"pause", __NR_pause}, +#endif +#endif +#ifdef SYS_perf_event_open +#ifdef __NR_perf_event_open + {"perf_event_open", __NR_perf_event_open}, +#endif +#endif +#ifdef SYS_personality +#ifdef __NR_personality + {"personality", __NR_personality}, +#endif +#endif +#ifdef SYS_pipe +#ifdef __NR_pipe + {"pipe", __NR_pipe}, +#endif +#endif +#ifdef SYS_pipe2 +#ifdef __NR_pipe2 + {"pipe2", __NR_pipe2}, +#endif +#endif +#ifdef SYS_pivot_root +#ifdef __NR_pivot_root + {"pivot_root", __NR_pivot_root}, +#endif +#endif +#ifdef SYS_poll +#ifdef __NR_poll + {"poll", __NR_poll}, +#endif +#endif +#ifdef SYS_ppoll +#ifdef __NR_ppoll + {"ppoll", __NR_ppoll}, +#endif +#endif +#ifdef SYS_prctl +#ifdef __NR_prctl + {"prctl", __NR_prctl}, +#endif +#endif +#ifdef SYS_pread64 +#ifdef __NR_pread64 + {"pread64", __NR_pread64}, +#endif +#endif +#ifdef SYS_preadv +#ifdef __NR_preadv + {"preadv", __NR_preadv}, +#endif +#endif +#ifdef SYS_prlimit64 +#ifdef __NR_prlimit64 + {"prlimit64", __NR_prlimit64}, +#endif +#endif +#ifdef SYS_process_vm_readv +#ifdef __NR_process_vm_readv + {"process_vm_readv", __NR_process_vm_readv}, +#endif +#endif +#ifdef SYS_process_vm_writev +#ifdef __NR_process_vm_writev + {"process_vm_writev", __NR_process_vm_writev}, +#endif +#endif +#ifdef SYS_pselect6 +#ifdef __NR_pselect6 + {"pselect6", __NR_pselect6}, +#endif +#endif +#ifdef SYS_ptrace +#ifdef __NR_ptrace + {"ptrace", __NR_ptrace}, +#endif +#endif +#ifdef SYS_putpmsg +#ifdef __NR_putpmsg + {"putpmsg", __NR_putpmsg}, +#endif +#endif +#ifdef SYS_pwrite64 +#ifdef __NR_pwrite64 + {"pwrite64", __NR_pwrite64}, +#endif +#endif +#ifdef SYS_pwritev +#ifdef __NR_pwritev + {"pwritev", __NR_pwritev}, +#endif +#endif +#ifdef SYS_query_module +#ifdef __NR_query_module + {"query_module", __NR_query_module}, +#endif +#endif +#ifdef SYS_quotactl +#ifdef __NR_quotactl + {"quotactl", __NR_quotactl}, +#endif +#endif +#ifdef SYS_read +#ifdef __NR_read + {"read", __NR_read}, +#endif +#endif +#ifdef SYS_readahead +#ifdef __NR_readahead + {"readahead", __NR_readahead}, +#endif +#endif +#ifdef SYS_readlink +#ifdef __NR_readlink + {"readlink", __NR_readlink}, +#endif +#endif +#ifdef SYS_readlinkat +#ifdef __NR_readlinkat + {"readlinkat", __NR_readlinkat}, +#endif +#endif +#ifdef SYS_readv +#ifdef __NR_readv + {"readv", __NR_readv}, +#endif +#endif +#ifdef SYS_reboot +#ifdef __NR_reboot + {"reboot", __NR_reboot}, +#endif +#endif +#ifdef SYS_recvfrom +#ifdef __NR_recvfrom + {"recvfrom", __NR_recvfrom}, +#endif +#endif +#ifdef SYS_recvmmsg +#ifdef __NR_recvmmsg + {"recvmmsg", __NR_recvmmsg}, +#endif +#endif +#ifdef SYS_recvmsg +#ifdef __NR_recvmsg + {"recvmsg", __NR_recvmsg}, +#endif +#endif +#ifdef SYS_remap_file_pages +#ifdef __NR_remap_file_pages + {"remap_file_pages", __NR_remap_file_pages}, +#endif +#endif +#ifdef SYS_removexattr +#ifdef __NR_removexattr + {"removexattr", __NR_removexattr}, +#endif +#endif +#ifdef SYS_rename +#ifdef __NR_rename + {"rename", __NR_rename}, +#endif +#endif +#ifdef SYS_renameat +#ifdef __NR_renameat + {"renameat", __NR_renameat}, +#endif +#endif +#ifdef SYS_request_key +#ifdef __NR_request_key + {"request_key", __NR_request_key}, +#endif +#endif +#ifdef SYS_restart_syscall +#ifdef __NR_restart_syscall + {"restart_syscall", __NR_restart_syscall}, +#endif +#endif +#ifdef SYS_rmdir +#ifdef __NR_rmdir + {"rmdir", __NR_rmdir}, +#endif +#endif +#ifdef SYS_rt_sigaction +#ifdef __NR_rt_sigaction + {"rt_sigaction", __NR_rt_sigaction}, +#endif +#endif +#ifdef SYS_rt_sigpending +#ifdef __NR_rt_sigpending + {"rt_sigpending", __NR_rt_sigpending}, +#endif +#endif +#ifdef SYS_rt_sigprocmask +#ifdef __NR_rt_sigprocmask + {"rt_sigprocmask", __NR_rt_sigprocmask}, +#endif +#endif +#ifdef SYS_rt_sigqueueinfo +#ifdef __NR_rt_sigqueueinfo + {"rt_sigqueueinfo", __NR_rt_sigqueueinfo}, +#endif +#endif +#ifdef SYS_rt_sigreturn +#ifdef __NR_rt_sigreturn + {"rt_sigreturn", __NR_rt_sigreturn}, +#endif +#endif +#ifdef SYS_rt_sigsuspend +#ifdef __NR_rt_sigsuspend + {"rt_sigsuspend", __NR_rt_sigsuspend}, +#endif +#endif +#ifdef SYS_rt_sigtimedwait +#ifdef __NR_rt_sigtimedwait + {"rt_sigtimedwait", __NR_rt_sigtimedwait}, +#endif +#endif +#ifdef SYS_rt_tgsigqueueinfo +#ifdef __NR_rt_tgsigqueueinfo + {"rt_tgsigqueueinfo", __NR_rt_tgsigqueueinfo}, +#endif +#endif +#ifdef SYS_sched_get_priority_max +#ifdef __NR_sched_get_priority_max + {"sched_get_priority_max", __NR_sched_get_priority_max}, +#endif +#endif +#ifdef SYS_sched_get_priority_min +#ifdef __NR_sched_get_priority_min + {"sched_get_priority_min", __NR_sched_get_priority_min}, +#endif +#endif +#ifdef SYS_sched_getaffinity +#ifdef __NR_sched_getaffinity + {"sched_getaffinity", __NR_sched_getaffinity}, +#endif +#endif +#ifdef SYS_sched_getparam +#ifdef __NR_sched_getparam + {"sched_getparam", __NR_sched_getparam}, +#endif +#endif +#ifdef SYS_sched_getscheduler +#ifdef __NR_sched_getscheduler + {"sched_getscheduler", __NR_sched_getscheduler}, +#endif +#endif +#ifdef SYS_sched_rr_get_interval +#ifdef __NR_sched_rr_get_interval + {"sched_rr_get_interval", __NR_sched_rr_get_interval}, +#endif +#endif +#ifdef SYS_sched_setaffinity +#ifdef __NR_sched_setaffinity + {"sched_setaffinity", __NR_sched_setaffinity}, +#endif +#endif +#ifdef SYS_sched_setparam +#ifdef __NR_sched_setparam + {"sched_setparam", __NR_sched_setparam}, +#endif +#endif +#ifdef SYS_sched_setscheduler +#ifdef __NR_sched_setscheduler + {"sched_setscheduler", __NR_sched_setscheduler}, +#endif +#endif +#ifdef SYS_sched_yield +#ifdef __NR_sched_yield + {"sched_yield", __NR_sched_yield}, +#endif +#endif +#ifdef SYS_security +#ifdef __NR_security + {"security", __NR_security}, +#endif +#endif +#ifdef SYS_select +#ifdef __NR_select + {"select", __NR_select}, +#endif +#endif +#ifdef SYS_semctl +#ifdef __NR_semctl + {"semctl", __NR_semctl}, +#endif +#endif +#ifdef SYS_semget +#ifdef __NR_semget + {"semget", __NR_semget}, +#endif +#endif +#ifdef SYS_semop +#ifdef __NR_semop + {"semop", __NR_semop}, +#endif +#endif +#ifdef SYS_semtimedop +#ifdef __NR_semtimedop + {"semtimedop", __NR_semtimedop}, +#endif +#endif +#ifdef SYS_sendfile +#ifdef __NR_sendfile + {"sendfile", __NR_sendfile}, +#endif +#endif +#ifdef SYS_sendmmsg +#ifdef __NR_sendmmsg + {"sendmmsg", __NR_sendmmsg}, +#endif +#endif +#ifdef SYS_sendmsg +#ifdef __NR_sendmsg + {"sendmsg", __NR_sendmsg}, +#endif +#endif +#ifdef SYS_sendto +#ifdef __NR_sendto + {"sendto", __NR_sendto}, +#endif +#endif +#ifdef SYS_set_mempolicy +#ifdef __NR_set_mempolicy + {"set_mempolicy", __NR_set_mempolicy}, +#endif +#endif +#ifdef SYS_set_robust_list +#ifdef __NR_set_robust_list + {"set_robust_list", __NR_set_robust_list}, +#endif +#endif +#ifdef SYS_set_thread_area +#ifdef __NR_set_thread_area + {"set_thread_area", __NR_set_thread_area}, +#endif +#endif +#ifdef SYS_set_tid_address +#ifdef __NR_set_tid_address + {"set_tid_address", __NR_set_tid_address}, +#endif +#endif +#ifdef SYS_setdomainname +#ifdef __NR_setdomainname + {"setdomainname", __NR_setdomainname}, +#endif +#endif +#ifdef SYS_setfsgid +#ifdef __NR_setfsgid + {"setfsgid", __NR_setfsgid}, +#endif +#endif +#ifdef SYS_setfsuid +#ifdef __NR_setfsuid + {"setfsuid", __NR_setfsuid}, +#endif +#endif +#ifdef SYS_setgid +#ifdef __NR_setgid + {"setgid", __NR_setgid}, +#endif +#endif +#ifdef SYS_setgroups +#ifdef __NR_setgroups + {"setgroups", __NR_setgroups}, +#endif +#endif +#ifdef SYS_sethostname +#ifdef __NR_sethostname + {"sethostname", __NR_sethostname}, +#endif +#endif +#ifdef SYS_setitimer +#ifdef __NR_setitimer + {"setitimer", __NR_setitimer}, +#endif +#endif +#ifdef SYS_setns +#ifdef __NR_setns + {"setns", __NR_setns}, +#endif +#endif +#ifdef SYS_setpgid +#ifdef __NR_setpgid + {"setpgid", __NR_setpgid}, +#endif +#endif +#ifdef SYS_setpriority +#ifdef __NR_setpriority + {"setpriority", __NR_setpriority}, +#endif +#endif +#ifdef SYS_setregid +#ifdef __NR_setregid + {"setregid", __NR_setregid}, +#endif +#endif +#ifdef SYS_setresgid +#ifdef __NR_setresgid + {"setresgid", __NR_setresgid}, +#endif +#endif +#ifdef SYS_setresuid +#ifdef __NR_setresuid + {"setresuid", __NR_setresuid}, +#endif +#endif +#ifdef SYS_setreuid +#ifdef __NR_setreuid + {"setreuid", __NR_setreuid}, +#endif +#endif +#ifdef SYS_setrlimit +#ifdef __NR_setrlimit + {"setrlimit", __NR_setrlimit}, +#endif +#endif +#ifdef SYS_setsid +#ifdef __NR_setsid + {"setsid", __NR_setsid}, +#endif +#endif +#ifdef SYS_setsockopt +#ifdef __NR_setsockopt + {"setsockopt", __NR_setsockopt}, +#endif +#endif +#ifdef SYS_settimeofday +#ifdef __NR_settimeofday + {"settimeofday", __NR_settimeofday}, +#endif +#endif +#ifdef SYS_setuid +#ifdef __NR_setuid + {"setuid", __NR_setuid}, +#endif +#endif +#ifdef SYS_setxattr +#ifdef __NR_setxattr + {"setxattr", __NR_setxattr}, +#endif +#endif +#ifdef SYS_shmat +#ifdef __NR_shmat + {"shmat", __NR_shmat}, +#endif +#endif +#ifdef SYS_shmctl +#ifdef __NR_shmctl + {"shmctl", __NR_shmctl}, +#endif +#endif +#ifdef SYS_shmdt +#ifdef __NR_shmdt + {"shmdt", __NR_shmdt}, +#endif +#endif +#ifdef SYS_shmget +#ifdef __NR_shmget + {"shmget", __NR_shmget}, +#endif +#endif +#ifdef SYS_shutdown +#ifdef __NR_shutdown + {"shutdown", __NR_shutdown}, +#endif +#endif +#ifdef SYS_sigaltstack +#ifdef __NR_sigaltstack + {"sigaltstack", __NR_sigaltstack}, +#endif +#endif +#ifdef SYS_signalfd +#ifdef __NR_signalfd + {"signalfd", __NR_signalfd}, +#endif +#endif +#ifdef SYS_signalfd4 +#ifdef __NR_signalfd4 + {"signalfd4", __NR_signalfd4}, +#endif +#endif +#ifdef SYS_socket +#ifdef __NR_socket + {"socket", __NR_socket}, +#endif +#endif +#ifdef SYS_socketpair +#ifdef __NR_socketpair + {"socketpair", __NR_socketpair}, +#endif +#endif +#ifdef SYS_splice +#ifdef __NR_splice + {"splice", __NR_splice}, +#endif +#endif +#ifdef SYS_stat +#ifdef __NR_stat + {"stat", __NR_stat}, +#endif +#endif +#ifdef SYS_statfs +#ifdef __NR_statfs + {"statfs", __NR_statfs}, +#endif +#endif +#ifdef SYS_swapoff +#ifdef __NR_swapoff + {"swapoff", __NR_swapoff}, +#endif +#endif +#ifdef SYS_swapon +#ifdef __NR_swapon + {"swapon", __NR_swapon}, +#endif +#endif +#ifdef SYS_symlink +#ifdef __NR_symlink + {"symlink", __NR_symlink}, +#endif +#endif +#ifdef SYS_symlinkat +#ifdef __NR_symlinkat + {"symlinkat", __NR_symlinkat}, +#endif +#endif +#ifdef SYS_sync +#ifdef __NR_sync + {"sync", __NR_sync}, +#endif +#endif +#ifdef SYS_sync_file_range +#ifdef __NR_sync_file_range + {"sync_file_range", __NR_sync_file_range}, +#endif +#endif +#ifdef SYS_syncfs +#ifdef __NR_syncfs + {"syncfs", __NR_syncfs}, +#endif +#endif +#ifdef SYS_sysfs +#ifdef __NR_sysfs + {"sysfs", __NR_sysfs}, +#endif +#endif +#ifdef SYS_sysinfo +#ifdef __NR_sysinfo + {"sysinfo", __NR_sysinfo}, +#endif +#endif +#ifdef SYS_syslog +#ifdef __NR_syslog + {"syslog", __NR_syslog}, +#endif +#endif +#ifdef SYS_tee +#ifdef __NR_tee + {"tee", __NR_tee}, +#endif +#endif +#ifdef SYS_tgkill +#ifdef __NR_tgkill + {"tgkill", __NR_tgkill}, +#endif +#endif +#ifdef SYS_time +#ifdef __NR_time + {"time", __NR_time}, +#endif +#endif +#ifdef SYS_timer_create +#ifdef __NR_timer_create + {"timer_create", __NR_timer_create}, +#endif +#endif +#ifdef SYS_timer_delete +#ifdef __NR_timer_delete + {"timer_delete", __NR_timer_delete}, +#endif +#endif +#ifdef SYS_timer_getoverrun +#ifdef __NR_timer_getoverrun + {"timer_getoverrun", __NR_timer_getoverrun}, +#endif +#endif +#ifdef SYS_timer_gettime +#ifdef __NR_timer_gettime + {"timer_gettime", __NR_timer_gettime}, +#endif +#endif +#ifdef SYS_timer_settime +#ifdef __NR_timer_settime + {"timer_settime", __NR_timer_settime}, +#endif +#endif +#ifdef SYS_timerfd_create +#ifdef __NR_timerfd_create + {"timerfd_create", __NR_timerfd_create}, +#endif +#endif +#ifdef SYS_timerfd_gettime +#ifdef __NR_timerfd_gettime + {"timerfd_gettime", __NR_timerfd_gettime}, +#endif +#endif +#ifdef SYS_timerfd_settime +#ifdef __NR_timerfd_settime + {"timerfd_settime", __NR_timerfd_settime}, +#endif +#endif +#ifdef SYS_times +#ifdef __NR_times + {"times", __NR_times}, +#endif +#endif +#ifdef SYS_tkill +#ifdef __NR_tkill + {"tkill", __NR_tkill}, +#endif +#endif +#ifdef SYS_truncate +#ifdef __NR_truncate + {"truncate", __NR_truncate}, +#endif +#endif +#ifdef SYS_tuxcall +#ifdef __NR_tuxcall + {"tuxcall", __NR_tuxcall}, +#endif +#endif +#ifdef SYS_umask +#ifdef __NR_umask + {"umask", __NR_umask}, +#endif +#endif +#ifdef SYS_umount2 +#ifdef __NR_umount2 + {"umount2", __NR_umount2}, +#endif +#endif +#ifdef SYS_uname +#ifdef __NR_uname + {"uname", __NR_uname}, +#endif +#endif +#ifdef SYS_unlink +#ifdef __NR_unlink + {"unlink", __NR_unlink}, +#endif +#endif +#ifdef SYS_unlinkat +#ifdef __NR_unlinkat + {"unlinkat", __NR_unlinkat}, +#endif +#endif +#ifdef SYS_unshare +#ifdef __NR_unshare + {"unshare", __NR_unshare}, +#endif +#endif +#ifdef SYS_uselib +#ifdef __NR_uselib + {"uselib", __NR_uselib}, +#endif +#endif +#ifdef SYS_ustat +#ifdef __NR_ustat + {"ustat", __NR_ustat}, +#endif +#endif +#ifdef SYS_utime +#ifdef __NR_utime + {"utime", __NR_utime}, +#endif +#endif +#ifdef SYS_utimensat +#ifdef __NR_utimensat + {"utimensat", __NR_utimensat}, +#endif +#endif +#ifdef SYS_utimes +#ifdef __NR_utimes + {"utimes", __NR_utimes}, +#endif +#endif +#ifdef SYS_vfork +#ifdef __NR_vfork + {"vfork", __NR_vfork}, +#endif +#endif +#ifdef SYS_vhangup +#ifdef __NR_vhangup + {"vhangup", __NR_vhangup}, +#endif +#endif +#ifdef SYS_vmsplice +#ifdef __NR_vmsplice + {"vmsplice", __NR_vmsplice}, +#endif +#endif +#ifdef SYS_vserver +#ifdef __NR_vserver + {"vserver", __NR_vserver}, +#endif +#endif +#ifdef SYS_wait4 +#ifdef __NR_wait4 + {"wait4", __NR_wait4}, +#endif +#endif +#ifdef SYS_waitid +#ifdef __NR_waitid + {"waitid", __NR_waitid}, +#endif +#endif +#ifdef SYS_write +#ifdef __NR_write + {"write", __NR_write}, +#endif +#endif +#ifdef SYS_writev +#ifdef __NR_writev + {"writev", __NR_writev}, +#endif +#endif +#endif +#if defined __x86_64__ && defined __ILP32__ +#ifdef SYS_accept +#ifdef __NR_accept + {"accept", __NR_accept}, +#endif +#endif +#ifdef SYS_accept4 +#ifdef __NR_accept4 + {"accept4", __NR_accept4}, +#endif +#endif +#ifdef SYS_access +#ifdef __NR_access + {"access", __NR_access}, +#endif +#endif +#ifdef SYS_acct +#ifdef __NR_acct + {"acct", __NR_acct}, +#endif +#endif +#ifdef SYS_add_key +#ifdef __NR_add_key + {"add_key", __NR_add_key}, +#endif +#endif +#ifdef SYS_adjtimex +#ifdef __NR_adjtimex + {"adjtimex", __NR_adjtimex}, +#endif +#endif +#ifdef SYS_afs_syscall +#ifdef __NR_afs_syscall + {"afs_syscall", __NR_afs_syscall}, +#endif +#endif +#ifdef SYS_alarm +#ifdef __NR_alarm + {"alarm", __NR_alarm}, +#endif +#endif +#ifdef SYS_arch_prctl +#ifdef __NR_arch_prctl + {"arch_prctl", __NR_arch_prctl}, +#endif +#endif +#ifdef SYS_bind +#ifdef __NR_bind + {"bind", __NR_bind}, +#endif +#endif +#ifdef SYS_brk +#ifdef __NR_brk + {"brk", __NR_brk}, +#endif +#endif +#ifdef SYS_capget +#ifdef __NR_capget + {"capget", __NR_capget}, +#endif +#endif +#ifdef SYS_capset +#ifdef __NR_capset + {"capset", __NR_capset}, +#endif +#endif +#ifdef SYS_chdir +#ifdef __NR_chdir + {"chdir", __NR_chdir}, +#endif +#endif +#ifdef SYS_chmod +#ifdef __NR_chmod + {"chmod", __NR_chmod}, +#endif +#endif +#ifdef SYS_chown +#ifdef __NR_chown + {"chown", __NR_chown}, +#endif +#endif +#ifdef SYS_chroot +#ifdef __NR_chroot + {"chroot", __NR_chroot}, +#endif +#endif +#ifdef SYS_clock_adjtime +#ifdef __NR_clock_adjtime + {"clock_adjtime", __NR_clock_adjtime}, +#endif +#endif +#ifdef SYS_clock_getres +#ifdef __NR_clock_getres + {"clock_getres", __NR_clock_getres}, +#endif +#endif +#ifdef SYS_clock_gettime +#ifdef __NR_clock_gettime + {"clock_gettime", __NR_clock_gettime}, +#endif +#endif +#ifdef SYS_clock_nanosleep +#ifdef __NR_clock_nanosleep + {"clock_nanosleep", __NR_clock_nanosleep}, +#endif +#endif +#ifdef SYS_clock_settime +#ifdef __NR_clock_settime + {"clock_settime", __NR_clock_settime}, +#endif +#endif +#ifdef SYS_clone +#ifdef __NR_clone + {"clone", __NR_clone}, +#endif +#endif +#ifdef SYS_close +#ifdef __NR_close + {"close", __NR_close}, +#endif +#endif +#ifdef SYS_connect +#ifdef __NR_connect + {"connect", __NR_connect}, +#endif +#endif +#ifdef SYS_creat +#ifdef __NR_creat + {"creat", __NR_creat}, +#endif +#endif +#ifdef SYS_delete_module +#ifdef __NR_delete_module + {"delete_module", __NR_delete_module}, +#endif +#endif +#ifdef SYS_dup +#ifdef __NR_dup + {"dup", __NR_dup}, +#endif +#endif +#ifdef SYS_dup2 +#ifdef __NR_dup2 + {"dup2", __NR_dup2}, +#endif +#endif +#ifdef SYS_dup3 +#ifdef __NR_dup3 + {"dup3", __NR_dup3}, +#endif +#endif +#ifdef SYS_epoll_create +#ifdef __NR_epoll_create + {"epoll_create", __NR_epoll_create}, +#endif +#endif +#ifdef SYS_epoll_create1 +#ifdef __NR_epoll_create1 + {"epoll_create1", __NR_epoll_create1}, +#endif +#endif +#ifdef SYS_epoll_ctl +#ifdef __NR_epoll_ctl + {"epoll_ctl", __NR_epoll_ctl}, +#endif +#endif +#ifdef SYS_epoll_pwait +#ifdef __NR_epoll_pwait + {"epoll_pwait", __NR_epoll_pwait}, +#endif +#endif +#ifdef SYS_epoll_wait +#ifdef __NR_epoll_wait + {"epoll_wait", __NR_epoll_wait}, +#endif +#endif +#ifdef SYS_eventfd +#ifdef __NR_eventfd + {"eventfd", __NR_eventfd}, +#endif +#endif +#ifdef SYS_eventfd2 +#ifdef __NR_eventfd2 + {"eventfd2", __NR_eventfd2}, +#endif +#endif +#ifdef SYS_execve +#ifdef __NR_execve + {"execve", __NR_execve}, +#endif +#endif +#ifdef SYS_exit +#ifdef __NR_exit + {"exit", __NR_exit}, +#endif +#endif +#ifdef SYS_exit_group +#ifdef __NR_exit_group + {"exit_group", __NR_exit_group}, +#endif +#endif +#ifdef SYS_faccessat +#ifdef __NR_faccessat + {"faccessat", __NR_faccessat}, +#endif +#endif +#ifdef SYS_fadvise64 +#ifdef __NR_fadvise64 + {"fadvise64", __NR_fadvise64}, +#endif +#endif +#ifdef SYS_fallocate +#ifdef __NR_fallocate + {"fallocate", __NR_fallocate}, +#endif +#endif +#ifdef SYS_fanotify_init +#ifdef __NR_fanotify_init + {"fanotify_init", __NR_fanotify_init}, +#endif +#endif +#ifdef SYS_fanotify_mark +#ifdef __NR_fanotify_mark + {"fanotify_mark", __NR_fanotify_mark}, +#endif +#endif +#ifdef SYS_fchdir +#ifdef __NR_fchdir + {"fchdir", __NR_fchdir}, +#endif +#endif +#ifdef SYS_fchmod +#ifdef __NR_fchmod + {"fchmod", __NR_fchmod}, +#endif +#endif +#ifdef SYS_fchmodat +#ifdef __NR_fchmodat + {"fchmodat", __NR_fchmodat}, +#endif +#endif +#ifdef SYS_fchown +#ifdef __NR_fchown + {"fchown", __NR_fchown}, +#endif +#endif +#ifdef SYS_fchownat +#ifdef __NR_fchownat + {"fchownat", __NR_fchownat}, +#endif +#endif +#ifdef SYS_fcntl +#ifdef __NR_fcntl + {"fcntl", __NR_fcntl}, +#endif +#endif +#ifdef SYS_fdatasync +#ifdef __NR_fdatasync + {"fdatasync", __NR_fdatasync}, +#endif +#endif +#ifdef SYS_fgetxattr +#ifdef __NR_fgetxattr + {"fgetxattr", __NR_fgetxattr}, +#endif +#endif +#ifdef SYS_finit_module +#ifdef __NR_finit_module + {"finit_module", __NR_finit_module}, +#endif +#endif +#ifdef SYS_flistxattr +#ifdef __NR_flistxattr + {"flistxattr", __NR_flistxattr}, +#endif +#endif +#ifdef SYS_flock +#ifdef __NR_flock + {"flock", __NR_flock}, +#endif +#endif +#ifdef SYS_fork +#ifdef __NR_fork + {"fork", __NR_fork}, +#endif +#endif +#ifdef SYS_fremovexattr +#ifdef __NR_fremovexattr + {"fremovexattr", __NR_fremovexattr}, +#endif +#endif +#ifdef SYS_fsetxattr +#ifdef __NR_fsetxattr + {"fsetxattr", __NR_fsetxattr}, +#endif +#endif +#ifdef SYS_fstat +#ifdef __NR_fstat + {"fstat", __NR_fstat}, +#endif +#endif +#ifdef SYS_fstatfs +#ifdef __NR_fstatfs + {"fstatfs", __NR_fstatfs}, +#endif +#endif +#ifdef SYS_fsync +#ifdef __NR_fsync + {"fsync", __NR_fsync}, +#endif +#endif +#ifdef SYS_ftruncate +#ifdef __NR_ftruncate + {"ftruncate", __NR_ftruncate}, +#endif +#endif +#ifdef SYS_futex +#ifdef __NR_futex + {"futex", __NR_futex}, +#endif +#endif +#ifdef SYS_futimesat +#ifdef __NR_futimesat + {"futimesat", __NR_futimesat}, +#endif +#endif +#ifdef SYS_get_mempolicy +#ifdef __NR_get_mempolicy + {"get_mempolicy", __NR_get_mempolicy}, +#endif +#endif +#ifdef SYS_get_robust_list +#ifdef __NR_get_robust_list + {"get_robust_list", __NR_get_robust_list}, +#endif +#endif +#ifdef SYS_getcpu +#ifdef __NR_getcpu + {"getcpu", __NR_getcpu}, +#endif +#endif +#ifdef SYS_getcwd +#ifdef __NR_getcwd + {"getcwd", __NR_getcwd}, +#endif +#endif +#ifdef SYS_getdents +#ifdef __NR_getdents + {"getdents", __NR_getdents}, +#endif +#endif +#ifdef SYS_getdents64 +#ifdef __NR_getdents64 + {"getdents64", __NR_getdents64}, +#endif +#endif +#ifdef SYS_getegid +#ifdef __NR_getegid + {"getegid", __NR_getegid}, +#endif +#endif +#ifdef SYS_geteuid +#ifdef __NR_geteuid + {"geteuid", __NR_geteuid}, +#endif +#endif +#ifdef SYS_getgid +#ifdef __NR_getgid + {"getgid", __NR_getgid}, +#endif +#endif +#ifdef SYS_getgroups +#ifdef __NR_getgroups + {"getgroups", __NR_getgroups}, +#endif +#endif +#ifdef SYS_getitimer +#ifdef __NR_getitimer + {"getitimer", __NR_getitimer}, +#endif +#endif +#ifdef SYS_getpeername +#ifdef __NR_getpeername + {"getpeername", __NR_getpeername}, +#endif +#endif +#ifdef SYS_getpgid +#ifdef __NR_getpgid + {"getpgid", __NR_getpgid}, +#endif +#endif +#ifdef SYS_getpgrp +#ifdef __NR_getpgrp + {"getpgrp", __NR_getpgrp}, +#endif +#endif +#ifdef SYS_getpid +#ifdef __NR_getpid + {"getpid", __NR_getpid}, +#endif +#endif +#ifdef SYS_getpmsg +#ifdef __NR_getpmsg + {"getpmsg", __NR_getpmsg}, +#endif +#endif +#ifdef SYS_getppid +#ifdef __NR_getppid + {"getppid", __NR_getppid}, +#endif +#endif +#ifdef SYS_getpriority +#ifdef __NR_getpriority + {"getpriority", __NR_getpriority}, +#endif +#endif +#ifdef SYS_getresgid +#ifdef __NR_getresgid + {"getresgid", __NR_getresgid}, +#endif +#endif +#ifdef SYS_getresuid +#ifdef __NR_getresuid + {"getresuid", __NR_getresuid}, +#endif +#endif +#ifdef SYS_getrlimit +#ifdef __NR_getrlimit + {"getrlimit", __NR_getrlimit}, +#endif +#endif +#ifdef SYS_getrusage +#ifdef __NR_getrusage + {"getrusage", __NR_getrusage}, +#endif +#endif +#ifdef SYS_getsid +#ifdef __NR_getsid + {"getsid", __NR_getsid}, +#endif +#endif +#ifdef SYS_getsockname +#ifdef __NR_getsockname + {"getsockname", __NR_getsockname}, +#endif +#endif +#ifdef SYS_getsockopt +#ifdef __NR_getsockopt + {"getsockopt", __NR_getsockopt}, +#endif +#endif +#ifdef SYS_gettid +#ifdef __NR_gettid + {"gettid", __NR_gettid}, +#endif +#endif +#ifdef SYS_gettimeofday +#ifdef __NR_gettimeofday + {"gettimeofday", __NR_gettimeofday}, +#endif +#endif +#ifdef SYS_getuid +#ifdef __NR_getuid + {"getuid", __NR_getuid}, +#endif +#endif +#ifdef SYS_getxattr +#ifdef __NR_getxattr + {"getxattr", __NR_getxattr}, +#endif +#endif +#ifdef SYS_init_module +#ifdef __NR_init_module + {"init_module", __NR_init_module}, +#endif +#endif +#ifdef SYS_inotify_add_watch +#ifdef __NR_inotify_add_watch + {"inotify_add_watch", __NR_inotify_add_watch}, +#endif +#endif +#ifdef SYS_inotify_init +#ifdef __NR_inotify_init + {"inotify_init", __NR_inotify_init}, +#endif +#endif +#ifdef SYS_inotify_init1 +#ifdef __NR_inotify_init1 + {"inotify_init1", __NR_inotify_init1}, +#endif +#endif +#ifdef SYS_inotify_rm_watch +#ifdef __NR_inotify_rm_watch + {"inotify_rm_watch", __NR_inotify_rm_watch}, +#endif +#endif +#ifdef SYS_io_cancel +#ifdef __NR_io_cancel + {"io_cancel", __NR_io_cancel}, +#endif +#endif +#ifdef SYS_io_destroy +#ifdef __NR_io_destroy + {"io_destroy", __NR_io_destroy}, +#endif +#endif +#ifdef SYS_io_getevents +#ifdef __NR_io_getevents + {"io_getevents", __NR_io_getevents}, +#endif +#endif +#ifdef SYS_io_setup +#ifdef __NR_io_setup + {"io_setup", __NR_io_setup}, +#endif +#endif +#ifdef SYS_io_submit +#ifdef __NR_io_submit + {"io_submit", __NR_io_submit}, +#endif +#endif +#ifdef SYS_ioctl +#ifdef __NR_ioctl + {"ioctl", __NR_ioctl}, +#endif +#endif +#ifdef SYS_ioperm +#ifdef __NR_ioperm + {"ioperm", __NR_ioperm}, +#endif +#endif +#ifdef SYS_iopl +#ifdef __NR_iopl + {"iopl", __NR_iopl}, +#endif +#endif +#ifdef SYS_ioprio_get +#ifdef __NR_ioprio_get + {"ioprio_get", __NR_ioprio_get}, +#endif +#endif +#ifdef SYS_ioprio_set +#ifdef __NR_ioprio_set + {"ioprio_set", __NR_ioprio_set}, +#endif +#endif +#ifdef SYS_kcmp +#ifdef __NR_kcmp + {"kcmp", __NR_kcmp}, +#endif +#endif +#ifdef SYS_kexec_load +#ifdef __NR_kexec_load + {"kexec_load", __NR_kexec_load}, +#endif +#endif +#ifdef SYS_keyctl +#ifdef __NR_keyctl + {"keyctl", __NR_keyctl}, +#endif +#endif +#ifdef SYS_kill +#ifdef __NR_kill + {"kill", __NR_kill}, +#endif +#endif +#ifdef SYS_lchown +#ifdef __NR_lchown + {"lchown", __NR_lchown}, +#endif +#endif +#ifdef SYS_lgetxattr +#ifdef __NR_lgetxattr + {"lgetxattr", __NR_lgetxattr}, +#endif +#endif +#ifdef SYS_link +#ifdef __NR_link + {"link", __NR_link}, +#endif +#endif +#ifdef SYS_linkat +#ifdef __NR_linkat + {"linkat", __NR_linkat}, +#endif +#endif +#ifdef SYS_listen +#ifdef __NR_listen + {"listen", __NR_listen}, +#endif +#endif +#ifdef SYS_listxattr +#ifdef __NR_listxattr + {"listxattr", __NR_listxattr}, +#endif +#endif +#ifdef SYS_llistxattr +#ifdef __NR_llistxattr + {"llistxattr", __NR_llistxattr}, +#endif +#endif +#ifdef SYS_lookup_dcookie +#ifdef __NR_lookup_dcookie + {"lookup_dcookie", __NR_lookup_dcookie}, +#endif +#endif +#ifdef SYS_lremovexattr +#ifdef __NR_lremovexattr + {"lremovexattr", __NR_lremovexattr}, +#endif +#endif +#ifdef SYS_lseek +#ifdef __NR_lseek + {"lseek", __NR_lseek}, +#endif +#endif +#ifdef SYS_lsetxattr +#ifdef __NR_lsetxattr + {"lsetxattr", __NR_lsetxattr}, +#endif +#endif +#ifdef SYS_lstat +#ifdef __NR_lstat + {"lstat", __NR_lstat}, +#endif +#endif +#ifdef SYS_madvise +#ifdef __NR_madvise + {"madvise", __NR_madvise}, +#endif +#endif +#ifdef SYS_mbind +#ifdef __NR_mbind + {"mbind", __NR_mbind}, +#endif +#endif +#ifdef SYS_migrate_pages +#ifdef __NR_migrate_pages + {"migrate_pages", __NR_migrate_pages}, +#endif +#endif +#ifdef SYS_mincore +#ifdef __NR_mincore + {"mincore", __NR_mincore}, +#endif +#endif +#ifdef SYS_mkdir +#ifdef __NR_mkdir + {"mkdir", __NR_mkdir}, +#endif +#endif +#ifdef SYS_mkdirat +#ifdef __NR_mkdirat + {"mkdirat", __NR_mkdirat}, +#endif +#endif +#ifdef SYS_mknod +#ifdef __NR_mknod + {"mknod", __NR_mknod}, +#endif +#endif +#ifdef SYS_mknodat +#ifdef __NR_mknodat + {"mknodat", __NR_mknodat}, +#endif +#endif +#ifdef SYS_mlock +#ifdef __NR_mlock + {"mlock", __NR_mlock}, +#endif +#endif +#ifdef SYS_mlockall +#ifdef __NR_mlockall + {"mlockall", __NR_mlockall}, +#endif +#endif +#ifdef SYS_mmap +#ifdef __NR_mmap + {"mmap", __NR_mmap}, +#endif +#endif +#ifdef SYS_modify_ldt +#ifdef __NR_modify_ldt + {"modify_ldt", __NR_modify_ldt}, +#endif +#endif +#ifdef SYS_mount +#ifdef __NR_mount + {"mount", __NR_mount}, +#endif +#endif +#ifdef SYS_move_pages +#ifdef __NR_move_pages + {"move_pages", __NR_move_pages}, +#endif +#endif +#ifdef SYS_mprotect +#ifdef __NR_mprotect + {"mprotect", __NR_mprotect}, +#endif +#endif +#ifdef SYS_mq_getsetattr +#ifdef __NR_mq_getsetattr + {"mq_getsetattr", __NR_mq_getsetattr}, +#endif +#endif +#ifdef SYS_mq_notify +#ifdef __NR_mq_notify + {"mq_notify", __NR_mq_notify}, +#endif +#endif +#ifdef SYS_mq_open +#ifdef __NR_mq_open + {"mq_open", __NR_mq_open}, +#endif +#endif +#ifdef SYS_mq_timedreceive +#ifdef __NR_mq_timedreceive + {"mq_timedreceive", __NR_mq_timedreceive}, +#endif +#endif +#ifdef SYS_mq_timedsend +#ifdef __NR_mq_timedsend + {"mq_timedsend", __NR_mq_timedsend}, +#endif +#endif +#ifdef SYS_mq_unlink +#ifdef __NR_mq_unlink + {"mq_unlink", __NR_mq_unlink}, +#endif +#endif +#ifdef SYS_mremap +#ifdef __NR_mremap + {"mremap", __NR_mremap}, +#endif +#endif +#ifdef SYS_msgctl +#ifdef __NR_msgctl + {"msgctl", __NR_msgctl}, +#endif +#endif +#ifdef SYS_msgget +#ifdef __NR_msgget + {"msgget", __NR_msgget}, +#endif +#endif +#ifdef SYS_msgrcv +#ifdef __NR_msgrcv + {"msgrcv", __NR_msgrcv}, +#endif +#endif +#ifdef SYS_msgsnd +#ifdef __NR_msgsnd + {"msgsnd", __NR_msgsnd}, +#endif +#endif +#ifdef SYS_msync +#ifdef __NR_msync + {"msync", __NR_msync}, +#endif +#endif +#ifdef SYS_munlock +#ifdef __NR_munlock + {"munlock", __NR_munlock}, +#endif +#endif +#ifdef SYS_munlockall +#ifdef __NR_munlockall + {"munlockall", __NR_munlockall}, +#endif +#endif +#ifdef SYS_munmap +#ifdef __NR_munmap + {"munmap", __NR_munmap}, +#endif +#endif +#ifdef SYS_name_to_handle_at +#ifdef __NR_name_to_handle_at + {"name_to_handle_at", __NR_name_to_handle_at}, +#endif +#endif +#ifdef SYS_nanosleep +#ifdef __NR_nanosleep + {"nanosleep", __NR_nanosleep}, +#endif +#endif +#ifdef SYS_newfstatat +#ifdef __NR_newfstatat + {"newfstatat", __NR_newfstatat}, +#endif +#endif +#ifdef SYS_open +#ifdef __NR_open + {"open", __NR_open}, +#endif +#endif +#ifdef SYS_open_by_handle_at +#ifdef __NR_open_by_handle_at + {"open_by_handle_at", __NR_open_by_handle_at}, +#endif +#endif +#ifdef SYS_openat +#ifdef __NR_openat + {"openat", __NR_openat}, +#endif +#endif +#ifdef SYS_pause +#ifdef __NR_pause + {"pause", __NR_pause}, +#endif +#endif +#ifdef SYS_perf_event_open +#ifdef __NR_perf_event_open + {"perf_event_open", __NR_perf_event_open}, +#endif +#endif +#ifdef SYS_personality +#ifdef __NR_personality + {"personality", __NR_personality}, +#endif +#endif +#ifdef SYS_pipe +#ifdef __NR_pipe + {"pipe", __NR_pipe}, +#endif +#endif +#ifdef SYS_pipe2 +#ifdef __NR_pipe2 + {"pipe2", __NR_pipe2}, +#endif +#endif +#ifdef SYS_pivot_root +#ifdef __NR_pivot_root + {"pivot_root", __NR_pivot_root}, +#endif +#endif +#ifdef SYS_poll +#ifdef __NR_poll + {"poll", __NR_poll}, +#endif +#endif +#ifdef SYS_ppoll +#ifdef __NR_ppoll + {"ppoll", __NR_ppoll}, +#endif +#endif +#ifdef SYS_prctl +#ifdef __NR_prctl + {"prctl", __NR_prctl}, +#endif +#endif +#ifdef SYS_pread64 +#ifdef __NR_pread64 + {"pread64", __NR_pread64}, +#endif +#endif +#ifdef SYS_preadv +#ifdef __NR_preadv + {"preadv", __NR_preadv}, +#endif +#endif +#ifdef SYS_prlimit64 +#ifdef __NR_prlimit64 + {"prlimit64", __NR_prlimit64}, +#endif +#endif +#ifdef SYS_process_vm_readv +#ifdef __NR_process_vm_readv + {"process_vm_readv", __NR_process_vm_readv}, +#endif +#endif +#ifdef SYS_process_vm_writev +#ifdef __NR_process_vm_writev + {"process_vm_writev", __NR_process_vm_writev}, +#endif +#endif +#ifdef SYS_pselect6 +#ifdef __NR_pselect6 + {"pselect6", __NR_pselect6}, +#endif +#endif +#ifdef SYS_ptrace +#ifdef __NR_ptrace + {"ptrace", __NR_ptrace}, +#endif +#endif +#ifdef SYS_putpmsg +#ifdef __NR_putpmsg + {"putpmsg", __NR_putpmsg}, +#endif +#endif +#ifdef SYS_pwrite64 +#ifdef __NR_pwrite64 + {"pwrite64", __NR_pwrite64}, +#endif +#endif +#ifdef SYS_pwritev +#ifdef __NR_pwritev + {"pwritev", __NR_pwritev}, +#endif +#endif +#ifdef SYS_quotactl +#ifdef __NR_quotactl + {"quotactl", __NR_quotactl}, +#endif +#endif +#ifdef SYS_read +#ifdef __NR_read + {"read", __NR_read}, +#endif +#endif +#ifdef SYS_readahead +#ifdef __NR_readahead + {"readahead", __NR_readahead}, +#endif +#endif +#ifdef SYS_readlink +#ifdef __NR_readlink + {"readlink", __NR_readlink}, +#endif +#endif +#ifdef SYS_readlinkat +#ifdef __NR_readlinkat + {"readlinkat", __NR_readlinkat}, +#endif +#endif +#ifdef SYS_readv +#ifdef __NR_readv + {"readv", __NR_readv}, +#endif +#endif +#ifdef SYS_reboot +#ifdef __NR_reboot + {"reboot", __NR_reboot}, +#endif +#endif +#ifdef SYS_recvfrom +#ifdef __NR_recvfrom + {"recvfrom", __NR_recvfrom}, +#endif +#endif +#ifdef SYS_recvmmsg +#ifdef __NR_recvmmsg + {"recvmmsg", __NR_recvmmsg}, +#endif +#endif +#ifdef SYS_recvmsg +#ifdef __NR_recvmsg + {"recvmsg", __NR_recvmsg}, +#endif +#endif +#ifdef SYS_remap_file_pages +#ifdef __NR_remap_file_pages + {"remap_file_pages", __NR_remap_file_pages}, +#endif +#endif +#ifdef SYS_removexattr +#ifdef __NR_removexattr + {"removexattr", __NR_removexattr}, +#endif +#endif +#ifdef SYS_rename +#ifdef __NR_rename + {"rename", __NR_rename}, +#endif +#endif +#ifdef SYS_renameat +#ifdef __NR_renameat + {"renameat", __NR_renameat}, +#endif +#endif +#ifdef SYS_request_key +#ifdef __NR_request_key + {"request_key", __NR_request_key}, +#endif +#endif +#ifdef SYS_restart_syscall +#ifdef __NR_restart_syscall + {"restart_syscall", __NR_restart_syscall}, +#endif +#endif +#ifdef SYS_rmdir +#ifdef __NR_rmdir + {"rmdir", __NR_rmdir}, +#endif +#endif +#ifdef SYS_rt_sigaction +#ifdef __NR_rt_sigaction + {"rt_sigaction", __NR_rt_sigaction}, +#endif +#endif +#ifdef SYS_rt_sigpending +#ifdef __NR_rt_sigpending + {"rt_sigpending", __NR_rt_sigpending}, +#endif +#endif +#ifdef SYS_rt_sigprocmask +#ifdef __NR_rt_sigprocmask + {"rt_sigprocmask", __NR_rt_sigprocmask}, +#endif +#endif +#ifdef SYS_rt_sigqueueinfo +#ifdef __NR_rt_sigqueueinfo + {"rt_sigqueueinfo", __NR_rt_sigqueueinfo}, +#endif +#endif +#ifdef SYS_rt_sigreturn +#ifdef __NR_rt_sigreturn + {"rt_sigreturn", __NR_rt_sigreturn}, +#endif +#endif +#ifdef SYS_rt_sigsuspend +#ifdef __NR_rt_sigsuspend + {"rt_sigsuspend", __NR_rt_sigsuspend}, +#endif +#endif +#ifdef SYS_rt_sigtimedwait +#ifdef __NR_rt_sigtimedwait + {"rt_sigtimedwait", __NR_rt_sigtimedwait}, +#endif +#endif +#ifdef SYS_rt_tgsigqueueinfo +#ifdef __NR_rt_tgsigqueueinfo + {"rt_tgsigqueueinfo", __NR_rt_tgsigqueueinfo}, +#endif +#endif +#ifdef SYS_sched_get_priority_max +#ifdef __NR_sched_get_priority_max + {"sched_get_priority_max", __NR_sched_get_priority_max}, +#endif +#endif +#ifdef SYS_sched_get_priority_min +#ifdef __NR_sched_get_priority_min + {"sched_get_priority_min", __NR_sched_get_priority_min}, +#endif +#endif +#ifdef SYS_sched_getaffinity +#ifdef __NR_sched_getaffinity + {"sched_getaffinity", __NR_sched_getaffinity}, +#endif +#endif +#ifdef SYS_sched_getparam +#ifdef __NR_sched_getparam + {"sched_getparam", __NR_sched_getparam}, +#endif +#endif +#ifdef SYS_sched_getscheduler +#ifdef __NR_sched_getscheduler + {"sched_getscheduler", __NR_sched_getscheduler}, +#endif +#endif +#ifdef SYS_sched_rr_get_interval +#ifdef __NR_sched_rr_get_interval + {"sched_rr_get_interval", __NR_sched_rr_get_interval}, +#endif +#endif +#ifdef SYS_sched_setaffinity +#ifdef __NR_sched_setaffinity + {"sched_setaffinity", __NR_sched_setaffinity}, +#endif +#endif +#ifdef SYS_sched_setparam +#ifdef __NR_sched_setparam + {"sched_setparam", __NR_sched_setparam}, +#endif +#endif +#ifdef SYS_sched_setscheduler +#ifdef __NR_sched_setscheduler + {"sched_setscheduler", __NR_sched_setscheduler}, +#endif +#endif +#ifdef SYS_sched_yield +#ifdef __NR_sched_yield + {"sched_yield", __NR_sched_yield}, +#endif +#endif +#ifdef SYS_security +#ifdef __NR_security + {"security", __NR_security}, +#endif +#endif +#ifdef SYS_select +#ifdef __NR_select + {"select", __NR_select}, +#endif +#endif +#ifdef SYS_semctl +#ifdef __NR_semctl + {"semctl", __NR_semctl}, +#endif +#endif +#ifdef SYS_semget +#ifdef __NR_semget + {"semget", __NR_semget}, +#endif +#endif +#ifdef SYS_semop +#ifdef __NR_semop + {"semop", __NR_semop}, +#endif +#endif +#ifdef SYS_semtimedop +#ifdef __NR_semtimedop + {"semtimedop", __NR_semtimedop}, +#endif +#endif +#ifdef SYS_sendfile +#ifdef __NR_sendfile + {"sendfile", __NR_sendfile}, +#endif +#endif +#ifdef SYS_sendmmsg +#ifdef __NR_sendmmsg + {"sendmmsg", __NR_sendmmsg}, +#endif +#endif +#ifdef SYS_sendmsg +#ifdef __NR_sendmsg + {"sendmsg", __NR_sendmsg}, +#endif +#endif +#ifdef SYS_sendto +#ifdef __NR_sendto + {"sendto", __NR_sendto}, +#endif +#endif +#ifdef SYS_set_mempolicy +#ifdef __NR_set_mempolicy + {"set_mempolicy", __NR_set_mempolicy}, +#endif +#endif +#ifdef SYS_set_robust_list +#ifdef __NR_set_robust_list + {"set_robust_list", __NR_set_robust_list}, +#endif +#endif +#ifdef SYS_set_tid_address +#ifdef __NR_set_tid_address + {"set_tid_address", __NR_set_tid_address}, +#endif +#endif +#ifdef SYS_setdomainname +#ifdef __NR_setdomainname + {"setdomainname", __NR_setdomainname}, +#endif +#endif +#ifdef SYS_setfsgid +#ifdef __NR_setfsgid + {"setfsgid", __NR_setfsgid}, +#endif +#endif +#ifdef SYS_setfsuid +#ifdef __NR_setfsuid + {"setfsuid", __NR_setfsuid}, +#endif +#endif +#ifdef SYS_setgid +#ifdef __NR_setgid + {"setgid", __NR_setgid}, +#endif +#endif +#ifdef SYS_setgroups +#ifdef __NR_setgroups + {"setgroups", __NR_setgroups}, +#endif +#endif +#ifdef SYS_sethostname +#ifdef __NR_sethostname + {"sethostname", __NR_sethostname}, +#endif +#endif +#ifdef SYS_setitimer +#ifdef __NR_setitimer + {"setitimer", __NR_setitimer}, +#endif +#endif +#ifdef SYS_setns +#ifdef __NR_setns + {"setns", __NR_setns}, +#endif +#endif +#ifdef SYS_setpgid +#ifdef __NR_setpgid + {"setpgid", __NR_setpgid}, +#endif +#endif +#ifdef SYS_setpriority +#ifdef __NR_setpriority + {"setpriority", __NR_setpriority}, +#endif +#endif +#ifdef SYS_setregid +#ifdef __NR_setregid + {"setregid", __NR_setregid}, +#endif +#endif +#ifdef SYS_setresgid +#ifdef __NR_setresgid + {"setresgid", __NR_setresgid}, +#endif +#endif +#ifdef SYS_setresuid +#ifdef __NR_setresuid + {"setresuid", __NR_setresuid}, +#endif +#endif +#ifdef SYS_setreuid +#ifdef __NR_setreuid + {"setreuid", __NR_setreuid}, +#endif +#endif +#ifdef SYS_setrlimit +#ifdef __NR_setrlimit + {"setrlimit", __NR_setrlimit}, +#endif +#endif +#ifdef SYS_setsid +#ifdef __NR_setsid + {"setsid", __NR_setsid}, +#endif +#endif +#ifdef SYS_setsockopt +#ifdef __NR_setsockopt + {"setsockopt", __NR_setsockopt}, +#endif +#endif +#ifdef SYS_settimeofday +#ifdef __NR_settimeofday + {"settimeofday", __NR_settimeofday}, +#endif +#endif +#ifdef SYS_setuid +#ifdef __NR_setuid + {"setuid", __NR_setuid}, +#endif +#endif +#ifdef SYS_setxattr +#ifdef __NR_setxattr + {"setxattr", __NR_setxattr}, +#endif +#endif +#ifdef SYS_shmat +#ifdef __NR_shmat + {"shmat", __NR_shmat}, +#endif +#endif +#ifdef SYS_shmctl +#ifdef __NR_shmctl + {"shmctl", __NR_shmctl}, +#endif +#endif +#ifdef SYS_shmdt +#ifdef __NR_shmdt + {"shmdt", __NR_shmdt}, +#endif +#endif +#ifdef SYS_shmget +#ifdef __NR_shmget + {"shmget", __NR_shmget}, +#endif +#endif +#ifdef SYS_shutdown +#ifdef __NR_shutdown + {"shutdown", __NR_shutdown}, +#endif +#endif +#ifdef SYS_sigaltstack +#ifdef __NR_sigaltstack + {"sigaltstack", __NR_sigaltstack}, +#endif +#endif +#ifdef SYS_signalfd +#ifdef __NR_signalfd + {"signalfd", __NR_signalfd}, +#endif +#endif +#ifdef SYS_signalfd4 +#ifdef __NR_signalfd4 + {"signalfd4", __NR_signalfd4}, +#endif +#endif +#ifdef SYS_socket +#ifdef __NR_socket + {"socket", __NR_socket}, +#endif +#endif +#ifdef SYS_socketpair +#ifdef __NR_socketpair + {"socketpair", __NR_socketpair}, +#endif +#endif +#ifdef SYS_splice +#ifdef __NR_splice + {"splice", __NR_splice}, +#endif +#endif +#ifdef SYS_stat +#ifdef __NR_stat + {"stat", __NR_stat}, +#endif +#endif +#ifdef SYS_statfs +#ifdef __NR_statfs + {"statfs", __NR_statfs}, +#endif +#endif +#ifdef SYS_swapoff +#ifdef __NR_swapoff + {"swapoff", __NR_swapoff}, +#endif +#endif +#ifdef SYS_swapon +#ifdef __NR_swapon + {"swapon", __NR_swapon}, +#endif +#endif +#ifdef SYS_symlink +#ifdef __NR_symlink + {"symlink", __NR_symlink}, +#endif +#endif +#ifdef SYS_symlinkat +#ifdef __NR_symlinkat + {"symlinkat", __NR_symlinkat}, +#endif +#endif +#ifdef SYS_sync +#ifdef __NR_sync + {"sync", __NR_sync}, +#endif +#endif +#ifdef SYS_sync_file_range +#ifdef __NR_sync_file_range + {"sync_file_range", __NR_sync_file_range}, +#endif +#endif +#ifdef SYS_syncfs +#ifdef __NR_syncfs + {"syncfs", __NR_syncfs}, +#endif +#endif +#ifdef SYS_sysfs +#ifdef __NR_sysfs + {"sysfs", __NR_sysfs}, +#endif +#endif +#ifdef SYS_sysinfo +#ifdef __NR_sysinfo + {"sysinfo", __NR_sysinfo}, +#endif +#endif +#ifdef SYS_syslog +#ifdef __NR_syslog + {"syslog", __NR_syslog}, +#endif +#endif +#ifdef SYS_tee +#ifdef __NR_tee + {"tee", __NR_tee}, +#endif +#endif +#ifdef SYS_tgkill +#ifdef __NR_tgkill + {"tgkill", __NR_tgkill}, +#endif +#endif +#ifdef SYS_time +#ifdef __NR_time + {"time", __NR_time}, +#endif +#endif +#ifdef SYS_timer_create +#ifdef __NR_timer_create + {"timer_create", __NR_timer_create}, +#endif +#endif +#ifdef SYS_timer_delete +#ifdef __NR_timer_delete + {"timer_delete", __NR_timer_delete}, +#endif +#endif +#ifdef SYS_timer_getoverrun +#ifdef __NR_timer_getoverrun + {"timer_getoverrun", __NR_timer_getoverrun}, +#endif +#endif +#ifdef SYS_timer_gettime +#ifdef __NR_timer_gettime + {"timer_gettime", __NR_timer_gettime}, +#endif +#endif +#ifdef SYS_timer_settime +#ifdef __NR_timer_settime + {"timer_settime", __NR_timer_settime}, +#endif +#endif +#ifdef SYS_timerfd_create +#ifdef __NR_timerfd_create + {"timerfd_create", __NR_timerfd_create}, +#endif +#endif +#ifdef SYS_timerfd_gettime +#ifdef __NR_timerfd_gettime + {"timerfd_gettime", __NR_timerfd_gettime}, +#endif +#endif +#ifdef SYS_timerfd_settime +#ifdef __NR_timerfd_settime + {"timerfd_settime", __NR_timerfd_settime}, +#endif +#endif +#ifdef SYS_times +#ifdef __NR_times + {"times", __NR_times}, +#endif +#endif +#ifdef SYS_tkill +#ifdef __NR_tkill + {"tkill", __NR_tkill}, +#endif +#endif +#ifdef SYS_truncate +#ifdef __NR_truncate + {"truncate", __NR_truncate}, +#endif +#endif +#ifdef SYS_tuxcall +#ifdef __NR_tuxcall + {"tuxcall", __NR_tuxcall}, +#endif +#endif +#ifdef SYS_umask +#ifdef __NR_umask + {"umask", __NR_umask}, +#endif +#endif +#ifdef SYS_umount2 +#ifdef __NR_umount2 + {"umount2", __NR_umount2}, +#endif +#endif +#ifdef SYS_uname +#ifdef __NR_uname + {"uname", __NR_uname}, +#endif +#endif +#ifdef SYS_unlink +#ifdef __NR_unlink + {"unlink", __NR_unlink}, +#endif +#endif +#ifdef SYS_unlinkat +#ifdef __NR_unlinkat + {"unlinkat", __NR_unlinkat}, +#endif +#endif +#ifdef SYS_unshare +#ifdef __NR_unshare + {"unshare", __NR_unshare}, +#endif +#endif +#ifdef SYS_ustat +#ifdef __NR_ustat + {"ustat", __NR_ustat}, +#endif +#endif +#ifdef SYS_utime +#ifdef __NR_utime + {"utime", __NR_utime}, +#endif +#endif +#ifdef SYS_utimensat +#ifdef __NR_utimensat + {"utimensat", __NR_utimensat}, +#endif +#endif +#ifdef SYS_utimes +#ifdef __NR_utimes + {"utimes", __NR_utimes}, +#endif +#endif +#ifdef SYS_vfork +#ifdef __NR_vfork + {"vfork", __NR_vfork}, +#endif +#endif +#ifdef SYS_vhangup +#ifdef __NR_vhangup + {"vhangup", __NR_vhangup}, +#endif +#endif +#ifdef SYS_vmsplice +#ifdef __NR_vmsplice + {"vmsplice", __NR_vmsplice}, +#endif +#endif +#ifdef SYS_wait4 +#ifdef __NR_wait4 + {"wait4", __NR_wait4}, +#endif +#endif +#ifdef SYS_waitid +#ifdef __NR_waitid + {"waitid", __NR_waitid}, +#endif +#endif +#ifdef SYS_write +#ifdef __NR_write + {"write", __NR_write}, +#endif +#endif +#ifdef SYS_writev +#ifdef __NR_writev + {"writev", __NR_writev}, +#endif +#endif +#endif + +// +// end of generated code +// +}; // end of syslist + +const char *syscall_find_nr(int nr) { + int i; + int elems = sizeof(syslist) / sizeof(syslist[0]); + for (i = 0; i < elems; i++) { + if (nr == syslist[i].nr) + return syslist[i].name; + } + + return "unknown"; +} + +// return -1 if error, or syscall number +static int syscall_find_name(const char *name) { + int i; + int elems = sizeof(syslist) / sizeof(syslist[0]); + for (i = 0; i < elems; i++) { + if (strcmp(name, syslist[i].name) == 0) + return syslist[i].nr; + } + + return -1; +} + +// return 1 if error, 0 if OK +int syscall_check_list(const char *slist, void (*callback)(int)) { + // don't allow empty lists + if (slist == NULL || *slist == '\0') { + fprintf(stderr, "Error: empty syscall lists are not allowed\n"); + return -1; + } + + // work on a copy of the string + char *str = strdup(slist); + if (!str) + errExit("strdup"); + + char *ptr = str; + char *start = str; + while (*ptr != '\0') { + if (islower(*ptr) || isdigit(*ptr) || *ptr == '_') + ; + else if (*ptr == ',') { + *ptr = '\0'; + int nr = syscall_find_name(start); + if (nr == -1) + fprintf(stderr, "Warning: syscall %s not found\n", start); + else if (callback != NULL) + callback(nr); + + start = ptr + 1; + } + ptr++; + } + if (*start != '\0') { + int nr = syscall_find_name(start); + if (nr == -1) + fprintf(stderr, "Warning: syscall %s not found\n", start); + else if (callback != NULL) + callback(nr); + } + + free(str); + return 0; +} + +void syscall_print(void) { + int i; + int elems = sizeof(syslist) / sizeof(syslist[0]); + for (i = 0; i < elems; i++) { + printf("%d\t- %s\n", syslist[i].nr, syslist[i].name); + } + printf("\n"); +} + +#endif // HAVE_SECCOMP diff --git a/src/firejail/usage.c b/src/firejail/usage.c new file mode 100644 index 00000000000..71ae203ffb2 --- /dev/null +++ b/src/firejail/usage.c @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firejail.h" + +void usage(void) { + printf("firejail - version %s\n\n", VERSION); + printf("Firejail is a SUID sandbox program that reduces the risk of security breaches by\n"); + printf("restricting the running environment of untrusted applications using Linux\n"); + printf("namespaces. It includes a sandbox profile for Mozilla Firefox.\n\n"); + printf("\n"); + printf("Usage: firejail [options] [program and arguments]\n\n"); + printf("\n"); + printf("Without any options, the sandbox consists of a filesystem chroot build from the\n"); + printf("current system directories mounted read-only, and new PID and IPC\n"); + printf("namespaces. If no program is specified as an argument, /bin/bash is started by\n"); + printf("default in the sandbox.\n\n"); + printf("\n"); + printf("Options:\n\n"); + printf("\t-- - signal the end of options and disables further option processing.\n\n"); + printf("\t--bandwidth=name - set bandwidth limits for the sandbox identified\n"); + printf("\t\tby name, see Traffic Shaping section for more details.\n\n"); + printf("\t--bandwidth=pid - set bandwidth limits for the sandbox identified\n"); + printf("\t\tby PID, see Traffic Shaping section for more details.\n\n"); +#ifdef HAVE_BIND + printf("\t--bind=dirname1,dirname2 - mount-bind dirname1 on top of dirname2.\n\n"); + printf("\t--bind=filename1,dirname2 - mount-bind filename1 on top of filename2.\n\n"); +#endif + printf("\t--blacklist=dirname_or_filename - blacklist directory or file.\n\n"); + printf("\t-c - execute command and exit.\n\n"); + printf("\t--caps - enable default Linux capabilities filter. The filter disables\n"); + printf("\t\tCAP_SYS_MODULE, CAP_SYS_RAWIO, CAP_SYS_BOOT, CAP_SYS_NICE,\n"); + printf("\t\tCAP_SYS_TTY_CONFIG, CAP_SYSLOG, CAP_MKNOD, CAP_SYS_ADMIN.\n\n"); + printf("\t--caps.drop=all - drop all capabilities.\n\n"); + printf("\t--caps.drop=capability,capability,capability - blacklist Linux\n"); + printf("\t\tcapabilities filter.\n\n"); + printf("\t--caps.keep=capability,capability,capability - whitelist Linux\n"); + printf("\t\tcapabilities filter.\n\n"); + printf("\t--caps.print=name - print the caps filter for the sandbox identified\n"); + printf("\t\tby name.\n\n"); + printf("\t--caps.print=pid - print the caps filter for the sandbox identified\n"); + printf("\t\tby PID.\n\n"); + printf("\t--cgroup=tasks-file - place the sandbox in the specified control group.\n"); + printf("\t\ttasks-file is the full path of cgroup tasks file.\n"); + printf("\t\tExample: --cgroup=/sys/fs/cgroup/g1/tasks\n\n"); +#ifdef HAVE_CHROOT + printf("\t--chroot=dirname - chroot into dirname directory.\n\n"); +#endif + printf("\t--cpu=cpu-number,cpu-number - set cpu affinity.\n"); + printf("\t\tExample: cpu=0,1,2\n\n"); + printf("\t--csh - use /bin/csh as default shell.\n\n"); + printf("\t--debug - print sandbox debug messages.\n\n"); + printf("\t--debug-syscalls - print all recognized system calls in the current\n"); + printf("\t\tFirejail software build and exit.\n\n"); + printf("\t--debug-caps - print all recognized capabilities in the current\n"); + printf("\t\tFirejail software build and exit.\n\n"); + printf("\t--defaultgw=address - use this address as default gateway in the new\n"); + printf("\t\tnetwork namespace.\n\n"); + printf("\t--dns=address - set a DNS server for the sandbox. Up to three DNS\n"); + printf("\t\tservers can be defined.\n\n"); + printf("\t--dns.print=name - print DNS configuration for the sandbox identified\n"); + printf("\t\tby name.\n\n"); + printf("\t--dns.print=pid - print DNS configuration of the sandbox identified.\n"); + printf("\t\tby PID.\n\n"); + printf("\t--help, -? - this help screen.\n\n"); + printf("\t--ip=address - set interface IP address.\n\n"); + printf("\t--ip=none - no IP address and no default gateway address are configured\n"); + printf("\t\tin the new network namespace. Use this option in case you intend\n"); + printf("\t\tto start an external DHCP client in the sandbox.\n\n"); + printf("\t--iprange=address,address - configure an IP address in this range\n\n"); + printf("\t--ipc-namespace - enable a new IPC namespace if the sandbox was started\n"); + printf("\t\tas a regular user. IPC namespace is enabled by default only if\n"); + printf("\t\tthe sandbox is started as root.\n\n"); + printf("\t--join=name - join the sandbox identified by name.\n\n"); + printf("\t--join=pid - join the sandbox identified by PID.\n\n"); + printf("\t--list - list all sandboxes.\n\n"); + printf("\t--mac=xx:xx:xx:xx:xx:xx - set interface MAC address.\n\n"); + printf("\t--name=name - set sandbox hostname.\n\n"); + printf("\t--net=bridgename - enable network namespaces and connect to this bridge\n"); + printf("\t\tdevice. Unless specified with option --ip and --defaultgw, an\n"); + printf("\t\tIP address and a default gateway will be assigned automatically\n"); + printf("\t\tto the sandbox. The IP address is checked using ARP before\n"); + printf("\t\tassignment. The IP address assigned as default gateway is the\n"); + printf("\t\tbridge device IP address. Up to four --net devices can\n"); + printf("\t\tbe defined. Mixing bridge and macvlan devices is allowed.\n\n"); + printf("\t--net=ethernet_interface - enable network namespaces and connect\n"); + printf("\t\tto this ethernet_interface using the standard Linux macvlan\n"); + printf("\t\tdriver. Unless specified with option --ip and --defaultgw, an\n"); + printf("\t\tIP address and a default gateway will be assigned automatically\n"); + printf("\t\tto the sandbox. The IP address is checked using ARP before\n"); + printf("\t\tassignment. The IP address assigned as default gateway is the\n"); + printf("\t\tdefault gateway of the host. Up to four --net devices can\n"); + printf("\t\tbe defined. Mixing bridge and macvlan devices is allowed.\n\n"); + printf("\t--net=none - enable a new, unconnected network namespace.\n\n"); + + printf("\t--netfilter - enable the default client network filter in the new\n"); + printf("\t\tnetwork namespace:\n\n"); + printf("\t\t*filter\n"); + printf("\t\t:INPUT DROP [0:0]\n"); + printf("\t\t:FORWARD DROP [0:0]\n"); + printf("\t\t:OUTPUT ACCEPT [0:0]\n"); + printf("\t\t-A INPUT -i lo -j ACCEPT\n"); + printf("\t\t-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT\n"); + printf("\t\t-A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT\n"); + printf("\t\t-A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT\n"); + printf("\t\t-A INPUT -p icmp --icmp-type echo-request -j ACCEPT \n"); + printf("\t\tCOMMIT\n\n"); + printf("\t--netfilter=filename - enable the network filter specified by\n"); + printf("\t\tfilename in the new network namespace. The filter file format\n"); + printf("\t\tis the format of iptables-save and iptable-restore commands.\n\n"); + + printf("\t--netstats - monitor network statistics for sandboxes creating a new\n"); + printf("\t\tnetwork namespace.\n\n"); + printf("\t--nogroups - disable supplementary groups. Without this option,\n"); + printf("\t\tsupplementary groups are enabled for the user starting the\n"); + printf("\t\tsandbox. For root user supplementary groups are always\n"); + printf("\t\tdisabled.\n\n"); + + printf("\t--noroot - install a user namespace with a single user - the current\n"); + printf("\t\tuser. root user does not exist in the new namespace. This option\n"); + printf("\t\tis not supported for --chroot and --overlay configurations.\n\n"); + + printf("\t--output=logfile - stdout logging and log rotation. Copy stdout to\n"); + printf("\t\tlogfile, and keep the size of the file under 500KB using log\n"); + printf("\t\trotation. Five files with prefixes .1 to .5 are used in\n"); + printf("\t\trotation.\n\n"); + printf("\t--overlay - mount a filesystem overlay on top of the current filesystem.\n"); + printf("\t\t(OverlayFS support is required in Linux kernel for this option\n"); + printf("\t\tto work)\n\n"); + + printf("\t--private - mount new /root and /home/user directories in temporary\n"); + printf("\t\tfilesystems. All modifications are discarded when the sandbox is\n"); + printf("\t\tclosed.\n\n"); + printf("\t--private=directory - use directory as user home.\n\n"); + printf("\t--private.keep=file,directory - build a new user home in a temporary\n"); + printf("\t\tfilesystem, and copy the files and directories in the list in\n"); + printf("\t\tthe new home. All modifications are discarded when the sandbox\n"); + printf("\t\tis closed.\n\n"); + printf("\t--private-dev - create a new /dev directory. Only null, full, zero, tty,\n"); + printf("\t\tpst, ptms, random, urandom and shm devices are available.\n\n"); + + printf("\t--profile=filename - use a custom profile.\n\n"); + printf("\t--read-only=dirname_or_filename - set directory or file read-only.\n\n"); + printf("\t--rlimit-fsize=number - set the maximum file size that can be created\n"); + printf("\t\tby a process.\n\n"); + printf("\t--rlimit-nofile=number - set the maximum number of files that can be\n"); + printf("\t\topened by a process.\n\n"); + printf("\t--rlimit-nproc=number - set the maximum number of processes that can be\n"); + printf("\t\tcreated for the real user ID of the calling process.\n\n"); + printf("\t--rlimit-sigpending=number - set the maximum number of pending signals\n"); + printf("\t\tfor a process.\n\n"); + + printf("\t--scan - ARP-scan all the networks from inside a network namespace.\n"); + printf("\t\tThis makes it possible to detect macvlan kernel device drivers\n"); + printf("\t\trunning on the current host.\n\n"); + +#ifdef HAVE_SECCOMP + printf("\t--seccomp - enable seccomp filter and blacklist the syscalls in the\n"); + printf("\t\tlist. The default list is as follows: mount, umount2,\n"); + printf("\t\tptrace, kexec_load, open_by_handle_at, init_module,\n"); + printf("\t\tfinit_module, delete_module, iopl, ioperm, swapon, swapoff,\n"); + printf("\t\tmknode, syslog, process_vm_readv and process_vm_writev\n"); + printf("\t\tsysfs,_sysctl, adjtimex, clock_adjtime, lookup_dcookie,\n"); + printf("\t\tperf_event_open, fanotify_init and kcmp.\n\n"); + + printf("\t--seccomp=syscall,syscall,syscall - enable seccomp filter, blacklist the\n"); + printf("\t\tdefault syscall list and the syscalls specified by the command.\n\n"); + + printf("\t--seccomp.drop=syscall,syscall,syscall - enable seccomp filter, and\n"); + printf("\t\tblacklist the syscalls specified by the command.\n\n"); + + printf("\t--seccomp.keep=syscall,syscall,syscall - enable seccomp filter, and\n"); + printf("\t\twhitelist the syscalls specified by the command.\n\n"); + + printf("\t--seccomp.print=name - print the seccomp filter for the sandbox\n"); + printf("\t\tidentified by name.\n\n"); + printf("\t--seccomp.print=pid - print the seccomp filter for the sandbox\n"); + printf("\t\tidentified by PID.\n\n"); +#endif + + printf("\t--shell=none - run the program directly without a user shell.\n\n"); + printf("\t--shell=program - set default user shell.\n\n"); + printf("\t--shutdown=name - shutdown the sandbox identified by name.\n\n"); + printf("\t--shutdown=pid - shutdown the sandbox identified by PID.\n\n"); + printf("\t--tmpfs=dirname - mount a tmpfs filesystem on directory dirname.\n\n"); + printf("\t--top - monitor the most CPU-intensive sandboxes.\n\n"); + printf("\t--trace - trace open, access and connect system calls.\n\n"); + printf("\t--tree - print a tree of all sandboxed processes.\n\n"); + printf("\t--version - print program version and exit.\n\n"); + printf("\t--zsh - use /usr/bin/zsh as default shell.\n\n"); + printf("\n"); + printf("\n"); + + + printf("Traffic Shaping\n\n"); + + printf("Network bandwidth is an expensive resource shared among all sandboxes\n"); + printf("running on a system. Traffic shaping allows the user to increase network\n"); + printf("performance by controlling the amount of data that flows into and out of the\n"); + printf("sandboxes. Firejail implements a simple rate-limiting shaper based on Linux\n"); + printf("command tc. The shaper works at sandbox level, and can be used only for\n"); + printf("sandboxes configured with new network namespaces.\n\n"); + + printf("Set rate-limits:\n"); + printf("\tfirejail --bandwidth={name|pid} set network-name down-speed up-speed\n\n"); + printf("Clear rate-limits:\n"); + printf("\tfirejail --bandwidth={name|pid} clear network-name\n\n"); + printf("Status:\n"); + printf("\tfirejail --bandwidth={name|pid} status\n\n"); + printf("where:\n"); + printf("\tname - sandbox name\n"); + printf("\tpid - sandbox pid\n"); + printf("\tnetwork-name - network name as used by --net option\n"); + printf("\tdown-speed - download speed in KB/s (decimal kilobyte per second)\n"); + printf("\tup-speed - upload speed in KB/s (decimal kilobyte per second)\n"); + printf("\n"); + printf("Example:\n"); + printf("\t$ firejail --name=mybrowser --net=eth0 firefox &\n"); + printf("\t$ firejail --bandwidth=mybrowser set eth0 80 20\n"); + printf("\t$ firejail --bandwidth=mybrowser status\n"); + printf("\t$ firejail --bandwidth=mybrowser clear eth0\n"); + printf("\n"); + printf("\n"); + + + + printf("Monitoring\n\n"); + + printf("Option --list prints a list of all sandboxes. The format for each entry is as\n"); + printf("follows:\n\n"); + printf("\tPID:USER:Command\n\n"); + + printf("Option --tree prints the tree of processes running in the sandbox. The format\n"); + printf("for each process entry is as follows:\n\n"); + printf("\tPID:USER:Command\n\n"); + + printf("Option --top is similar to the UNIX top command, however it applies only to\n"); + printf("sandboxes. Listed below are the available fields (columns) in alphabetical\n"); + printf("order:\n\n"); + printf("\tCommand - command used to start the sandbox.\n"); + printf("\tCPU%% - CPU usage, the sandbox share of the elapsed CPU time since the\n"); + printf("\t last screen update\n"); + printf("\tPID - Unique process ID for the task controlling the sandbox.\n"); + printf("\tPrcs - number of processes running in sandbox, including the controlling\n"); + printf("\t process.\n"); + printf("\tRES - Resident Memory Size (KiB), sandbox non-swapped physical memory.\n"); + printf("\t It is a sum of the RES values for all processes running in the\n"); + printf("\t sandbox.\n"); + printf("\tSHR - Shared Memory Size (KiB), it reflects memory shared with other\n"); + printf("\t processes. It is a sum of the SHR values for all processes running\n"); + printf("\t in the sandbox, including the controlling process.\n"); + printf("\tUptime - sandbox running time in hours:minutes:seconds format.\n"); + printf("\tUser - The owner of the sandbox.\n"); + printf("\n"); + printf("\n"); + printf("Profile files\n\n"); + printf("Several command line configuration options can be passed to the program using\n"); + printf("profile files. Default Firejail profile files are stored in /etc/firejail\n"); + printf("directory, user profile files are stored in ~/.config/firejail directory. See\n"); + printf("man 5 firejail-profile for more information.\n\n"); + printf("\n"); + printf("Restricted shell\n\n"); + printf("To configure a restricted shell, replace /bin/bash with /usr/bin/firejail i\n"); + printf("/etc/password file for each user that needs to be restricted.\n"); + printf("Alternatively, you can specify /usr/bin/firejail in adduser command:\n\n"); + printf(" adduser --shell /usr/bin/firejail username\n\n"); + printf("Arguments to be passed to firejail executable upon login are declared in\n"); + printf("/etc/firejail/login.users file.\n\n"); + printf("\n"); + printf("Examples:\n\n"); + printf(" $ firejail\n"); + printf(" start a regular /bin/bash session in sandbox\n"); + printf(" $ firejail firefox\n"); + printf(" start Mozilla Firefox\n"); + printf(" $ firejail --seccomp firefox\n"); + printf(" start Mozilla Firefox in a seccomp sandbox\n"); + printf(" $ firejail --caps firefox\n"); + printf(" start Mozilla Firefox in a Linux capabilities sandbox\n"); + printf(" $ firejail --debug firefox\n"); + printf(" debug Firefox sandbox\n"); + printf(" $ firejail --private\n"); + printf(" start a /bin/bash session with a new tmpfs home directory\n"); + printf(" $ firejail --net=br0 ip=10.10.20.10\n"); + printf(" start a /bin/bash session in a new network namespace; the session is\n"); + printf(" connected to the main network using br0 bridge device, an IP address\n"); + printf(" of 10.10.20.10 is assigned to the sandbox\n"); + printf(" $ firejail --net=br0 --net=br1 --net=br2\n"); + printf(" start a /bin/bash session in a new network namespace and connect it\n"); + printf(" to br0, br1, and br2 host bridge devices\n"); + printf(" $ firejail --list\n"); + printf(" list all running sandboxes\n"); + printf("\n"); + printf("License GPL version 2 or later\n"); + printf("Homepage: http://firejail.sourceforge.net\n"); + printf("\n"); +} diff --git a/src/firejail/util.c b/src/firejail/util.c new file mode 100644 index 00000000000..2c50caf1788 --- /dev/null +++ b/src/firejail/util.c @@ -0,0 +1,480 @@ +/* + * Copyright (C) 2014, 2015 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include "firejail.h" +#include +#include +#include +#include +#include +#include + +#define MAX_GROUPS 1024 +// drop privileges +// - for root group or if nogroups is set, supplementary groups are not configured +void drop_privs(int nogroups) { + gid_t gid = getgid(); + + // configure supplementary groups + if (gid == 0 || nogroups) { + if (setgroups(0, NULL) < 0) + errExit("setgroups"); + if (arg_debug) + printf("Username %s, no supplementary groups\n", cfg.username); + } + else { + assert(cfg.username); + gid_t groups[MAX_GROUPS]; + int ngroups = MAX_GROUPS; + int rv = getgrouplist(cfg.username, gid, groups, &ngroups); + + if (arg_debug && rv) { + printf("Username %s, groups ", cfg.username); + int i; + for (i = 0; i < ngroups; i++) + printf("%u, ", groups[i]); + printf("\n"); + } + + if (rv == -1) { + fprintf(stderr, "Warning: cannot extract supplementary group list, dropping them\n"); + if (setgroups(0, NULL) < 0) + errExit("setgroups"); + } + else { + rv = setgroups(ngroups, groups); + if (rv) { + fprintf(stderr, "Warning: cannot set supplementary group list, dropping them\n"); + if (setgroups(0, NULL) < 0) + errExit("setgroups"); + } + } + } + + // set uid/gid + if (setgid(getgid()) < 0) + errExit("setgid/getgid"); + if (setuid(getuid()) < 0) + errExit("setuid/getuid"); +} + + +void logsignal(int s) { + if (!arg_debug) + return; + + openlog("firejail", LOG_NDELAY | LOG_PID, LOG_USER); + syslog(LOG_INFO, "Signal %d caught", s); + closelog(); +} + + +void logmsg(const char *msg) { + if (!arg_debug) + return; + + openlog("firejail", LOG_NDELAY | LOG_PID, LOG_USER); + syslog(LOG_INFO, "%s\n", msg); + closelog(); +} + + +void logargs(int argc, char **argv) { + if (!arg_debug) + return; + + int i; + int len = 0; + + // calculate message length + for (i = 0; i < argc; i++) + len += strlen(argv[i]) + 1; // + ' ' + + // build message + char msg[len + 1]; + char *ptr = msg; + for (i = 0; i < argc; i++) { + sprintf(ptr, "%s ", argv[i]); + ptr += strlen(ptr); + } + + // log message + logmsg(msg); +} + + +void logerr(const char *msg) { + if (!arg_debug) + return; + + openlog("firejail", LOG_NDELAY | LOG_PID, LOG_USER); + syslog(LOG_ERR, "%s\n", msg); + closelog(); +} + + +// return -1 if error, 0 if no error +int copy_file(const char *srcname, const char *destname) { + assert(srcname); + assert(destname); + + // open source + int src = open(srcname, O_RDONLY); + if (src < 0) { + fprintf(stderr, "Warning: cannot open %s, file not copied\n", srcname); + return -1; + } + + // open destination + int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (dst < 0) { + fprintf(stderr, "Warning: cannot open %s, file not copied\n", destname); + close(src); + return -1; + } + + // copy + ssize_t len; + static const int BUFLEN = 1024; + unsigned char buf[BUFLEN]; + while ((len = read(src, buf, BUFLEN)) > 0) { + int done = 0; + while (done != len) { + int rv = write(dst, buf + done, len - done); + if (rv == -1) { + close(src); + close(dst); + return -1; + } + + done += rv; + } + } + + close(src); + close(dst); + return 0; +} + + +char *get_link(const char *fname) { + assert(fname); + struct stat sb; + char *linkname; + ssize_t r; + + if (lstat(fname, &sb) == -1) + return NULL; + + linkname = malloc(sb.st_size + 1); + if (linkname == NULL) + return NULL; + memset(linkname, 0, sb.st_size + 1); + + r = readlink(fname, linkname, sb.st_size + 1); + if (r < 0) { + free(linkname); + return NULL; + } + return linkname; +} + + +// return 1 if the file is a directory +int is_dir(const char *fname) { + assert(fname); + if (*fname == '\0') + return 0; + + // if fname doesn't end in '/', add one + int rv; + struct stat s; + if (fname[strlen(fname) - 1] == '/') + rv = stat(fname, &s); + else { + char *tmp; + if (asprintf(&tmp, "%s/", fname) == -1) { + fprintf(stderr, "Error: cannot allocate memory, %s:%d\n", __FILE__, __LINE__); + errExit("asprintf"); + } + rv = stat(tmp, &s); + free(tmp); + } + + if (rv == -1) + return 0; + + if (S_ISDIR(s.st_mode)) + return 1; + + return 0; +} + +// return 1 if the file is a link +int is_link(const char *fname) { + assert(fname); + if (*fname == '\0') + return 0; + + struct stat s; + if (lstat(fname, &s) == 0) { + if (S_ISLNK(s.st_mode)) + return 1; + } + + return 0; +} + + +// remove multiple spaces and return allocated memory +char *line_remove_spaces(const char *buf) { + assert(buf); + if (strlen(buf) == 0) + return NULL; + + // allocate memory for the new string + char *rv = malloc(strlen(buf) + 1); + if (rv == NULL) + errExit("malloc"); + + // remove space at start of line + const char *ptr1 = buf; + while (*ptr1 == ' ' || *ptr1 == '\t') + ptr1++; + + // copy data and remove additional spaces + char *ptr2 = rv; + int state = 0; + while (*ptr1 != '\0') { + if (*ptr1 == '\n' || *ptr1 == '\r') + break; + + if (state == 0) { + if (*ptr1 != ' ' && *ptr1 != '\t') + *ptr2++ = *ptr1++; + else { + *ptr2++ = ' '; + ptr1++; + state = 1; + } + } + else { // state == 1 + while (*ptr1 == ' ' || *ptr1 == '\t') + ptr1++; + state = 0; + } + } + + // strip last blank character if any + if (*(ptr2 - 1) == ' ') + --ptr2; + *ptr2 = '\0'; + // if (arg_debug) + // printf("Processing line #%s#\n", rv); + + return rv; +} + + +char *split_comma(char *str) { + if (str == NULL || *str == '\0') + return NULL; + char *ptr = strchr(str, ','); + if (!ptr) + return NULL; + *ptr = '\0'; + ptr++; + if (*ptr == '\0') + return NULL; + return ptr; +} + + +int not_unsigned(const char *str) { + int rv = 0; + const char *ptr = str; + while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0') { + if (!isdigit(*ptr)) { + rv = 1; + break; + } + ptr++; + } + + return rv; +} + + +#define BUFLEN 4096 +// find the first child for this parent; return 1 if error +int find_child(pid_t parent, pid_t *child) { + *child = 0; // use it to flag a found child + + DIR *dir; + if (!(dir = opendir("/proc"))) { + // sleep 2 seconds and try again + sleep(2); + if (!(dir = opendir("/proc"))) { + fprintf(stderr, "Error: cannot open /proc directory\n"); + exit(1); + } + } + + struct dirent *entry; + char *end; + while (*child == 0 && (entry = readdir(dir))) { + pid_t pid = strtol(entry->d_name, &end, 10); + if (end == entry->d_name || *end) + continue; + if (pid == parent) + continue; + + // open stat file + char *file; + if (asprintf(&file, "/proc/%u/status", pid) == -1) { + perror("asprintf"); + exit(1); + } + FILE *fp = fopen(file, "r"); + if (!fp) { + free(file); + continue; + } + + // look for firejail executable name + char buf[BUFLEN]; + while (fgets(buf, BUFLEN - 1, fp)) { + if (strncmp(buf, "PPid:", 5) == 0) { + char *ptr = buf + 5; + while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) { + ptr++; + } + if (*ptr == '\0') { + fprintf(stderr, "Error: cannot read /proc file\n"); + exit(1); + } + if (parent == atoi(ptr)) + *child = pid; + break; // stop reading the file + } + } + fclose(fp); + free(file); + } + closedir(dir); + + return (*child)? 0:1; // 0 = found, 1 = not found +} + + + +void extract_command_name(const char *str) { + assert(str); + cfg.command_name = strdup(str); + if (!cfg.command_name) + errExit("strdup"); + + // restrict the command name to the first word + char *ptr = cfg.command_name; + while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0') + ptr++; + *ptr = '\0'; + + // remove the path: /usr/bin/firefox becomes firefox + ptr = strrchr(cfg.command_name, '/'); + if (ptr) { + ptr++; + if (*ptr == '\0') { + fprintf(stderr, "Error: invalid command name\n"); + exit(1); + } + + char *tmp = strdup(ptr); + if (!tmp) + errExit("strdup"); + free(cfg.command_name); + cfg.command_name = tmp; + } +} + + +void update_map(char *mapping, char *map_file) { + int fd, j; + size_t map_len; /* Length of 'mapping' */ + + /* Replace commas in mapping string with newlines */ + + map_len = strlen(mapping); + for (j = 0; j < map_len; j++) + if (mapping[j] == ',') + mapping[j] = '\n'; + + fd = open(map_file, O_RDWR); + if (fd == -1) { + fprintf(stderr, "Error: cannot open %s: %s\n", map_file, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (write(fd, mapping, map_len) != map_len) { + fprintf(stderr, "Error: cannot write to %s: %s\n", map_file, strerror(errno)); + exit(EXIT_FAILURE); + } + + close(fd); +} + + +void wait_for_other(int fd) { + //**************************** + // wait for the parent to be initialized + //**************************** + char childstr[BUFLEN + 1]; + int newfd = dup(fd); + if (newfd == -1) + errExit("dup"); + FILE* stream; + stream = fdopen(newfd, "r"); + *childstr = '\0'; + if (fgets(childstr, BUFLEN, stream)) { + // remove \n) + char *ptr = childstr; + while(*ptr !='\0' && *ptr != '\n') + ptr++; + if (*ptr == '\0') + errExit("fgets"); + *ptr = '\0'; + } + else { + fprintf(stderr, "Error: cannot establish communication with the parent, exiting...\n"); + exit(1); + } + fclose(stream); +} + + +void notify_other(int fd) { + FILE* stream; + int newfd = dup(fd); + if (newfd == -1) + errExit("dup"); + stream = fdopen(newfd, "w"); + fprintf(stream, "%u\n", getpid()); + fflush(stream); + fclose(stream); +} diff --git a/src/firejail/veth.c b/src/firejail/veth.c new file mode 100644 index 00000000000..ecc31f18ded --- /dev/null +++ b/src/firejail/veth.c @@ -0,0 +1,191 @@ +/* code based on iproute2 ip/iplink.c, modified to be included in firejail project + * + * Original source code: + * + * Information: + * http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2 + * + * Download: + * http://www.kernel.org/pub/linux/utils/net/iproute2/ + * + * Repository: + * git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git + * + * License: GPL v2 + * + * Original copyright header + * + * iplink.c "ip link". + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Alexey Kuznetsov, + * + */ + /* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "firejail.h" +#include "../include/libnetlink.h" +#include + +struct iplink_req +{ + struct nlmsghdr n; + struct ifinfomsg i; + char buf[1024]; +}; + +static struct rtnl_handle rth = { .fd = -1 }; + +int net_create_veth(const char *dev, const char *nsdev, unsigned pid) { + int len; + struct iplink_req req; + + if (arg_debug) + printf("create veth %s/%s/%u\n", dev, nsdev, pid); + assert(dev); + assert(nsdev); + assert(pid); + + if (rtnl_open(&rth, 0) < 0) { + fprintf(stderr, "cannot open netlink\n"); + exit(1); + } + + memset(&req, 0, sizeof(req)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; + req.n.nlmsg_type = RTM_NEWLINK; + req.i.ifi_family = 0; + + if (dev) { + len = strlen(dev) + 1; + addattr_l(&req.n, sizeof(req), IFLA_IFNAME, dev, len); + } + + struct rtattr *linkinfo = NLMSG_TAIL(&req.n); + addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); + addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, "veth", strlen("veth")); + + struct rtattr * data = NLMSG_TAIL(&req.n); + addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); + + struct rtattr * peerdata = NLMSG_TAIL(&req.n); + addattr_l (&req.n, sizeof(req), VETH_INFO_PEER, NULL, 0); + req.n.nlmsg_len += sizeof(struct ifinfomsg); + + // place the link in the child namespace + addattr_l (&req.n, sizeof(req), IFLA_NET_NS_PID, &pid, 4); + + if (nsdev) { + int len = strlen(nsdev) + 1; + addattr_l(&req.n, sizeof(req), IFLA_IFNAME, nsdev, len); + } + peerdata->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)peerdata; + + data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; + linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; + + // send message + if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) + exit(2); + + return 0; +} + + +int net_create_macvlan(const char *dev, const char *parent, unsigned pid) { + int len; + struct iplink_req req; + if (arg_debug) + printf("create macvlan %s, parent %s\n", dev, parent); + assert(dev); + assert(parent); + + if (rtnl_open(&rth, 0) < 0) { + fprintf(stderr, "cannot open netlink\n"); + exit(1); + } + + memset(&req, 0, sizeof(req)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; + req.n.nlmsg_type = RTM_NEWLINK; + req.i.ifi_family = 0; + + // we start with the parent + int parent_ifindex = 2; + addattr_l(&req.n, sizeof(req), IFLA_LINK, &parent_ifindex, 4); + + // add new interface name + len = strlen(dev) + 1; + addattr_l(&req.n, sizeof(req), IFLA_IFNAME, dev, len); + + // place the interface in child namespace + addattr_l (&req.n, sizeof(req), IFLA_NET_NS_PID, &pid, 4); + + + // add link info for the new interface + struct rtattr *linkinfo = NLMSG_TAIL(&req.n); + addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); + addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, "macvlan", strlen("macvlan")); + + // set macvlan bridge mode + struct rtattr * data = NLMSG_TAIL(&req.n); + addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); + int macvlan_type = MACVLAN_MODE_BRIDGE; + addattr_l (&req.n, sizeof(req), IFLA_INFO_KIND, &macvlan_type, 4); + + data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; +// req.n.nlmsg_len += sizeof(struct ifinfomsg); + + + data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; + linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; + + // send message + if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) + exit(2); + + return 0; +} + +/* +int main(int argc, char **argv) { + printf("Hello\n"); + + + char *dev = argv[3]; + char *nsdev = argv[8]; + unsigned pid; + sscanf(argv[10], "%u", &pid); + + + net_create_veth(dev, nsdev, pid); + + return 0; +} +*/ \ No newline at end of file diff --git a/src/firemon/Makefile.in b/src/firemon/Makefile.in new file mode 100644 index 00000000000..4252896955f --- /dev/null +++ b/src/firemon/Makefile.in @@ -0,0 +1,24 @@ +all: firemon + +PREFIX=@prefix@ +VERSION=@PACKAGE_VERSION@ +NAME=@PACKAGE_NAME@ + +H_FILE_LIST = $(wildcard *.[h]) +C_FILE_LIST = $(wildcard *.c) +OBJS = $(C_FILE_LIST:.c=.o) +BINOBJS = $(foreach file, $(OBJS), $file) +CFLAGS += -ggdb -O2 -DVERSION='"$(VERSION)"' -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security +LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now + +%.o : %.c $(H_FILE_LIST) + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +firemon: $(OBJS) ../lib/common.o ../lib/pid.o + $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/common.o ../lib/pid.o $(LIBS) + +clean:; rm -f *.o firemon + +distclean: clean + rm -fr Makefile + diff --git a/src/firemon/arp.c b/src/firemon/arp.c new file mode 100644 index 00000000000..71beb0630fd --- /dev/null +++ b/src/firemon/arp.c @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firemon.h" +#define MAXBUF 4096 + +static void print_arp(const char *fname) { + FILE *fp = fopen(fname, "r"); + if (!fp) + return; + + printf(" ARP Table:\n"); + char buf[MAXBUF]; + while (fgets(buf, MAXBUF, fp)) { + // remove blanks, \n + char *ptr = buf; + while (*ptr == ' ' || *ptr == '\t') + ptr++; + char *start = ptr; + if (*start == '\0') + continue; + ptr = strchr(ptr, '\n'); + if (ptr) + *ptr = '\0'; + + // remove table header + //IP address HW type Flags HW address Mask Device + if (strncmp(start, "IP address", 10) == 0) + continue; + + // extract data + char ip[64]; + char type[64]; + char flags[64]; + char mac[64]; + char mask[64]; + char device[64]; + int rv = sscanf(start, "%s %s %s %s %s %s\n", ip, type, flags, mac, mask, device); + if (rv != 6) + continue; + + // destination ip + unsigned a, b, c, d; + if (sscanf(ip, "%u.%u.%u.%u", &a, &b, &c, &d) != 4 || a > 255 || b > 255 || c > 255 || d > 255) + continue; + uint32_t destip = a * 0x1000000 + b * 0x10000 + c * 0x100 + d; + if (strcmp(flags, "0x0") == 0) + printf(" %d.%d.%d.%d dev %s FAILED\n", + PRINT_IP(destip), device); + else + printf(" %d.%d.%d.%d dev %s lladdr %s REACHABLE\n", + PRINT_IP(destip), device, mac); + } + + fclose(fp); + +} + +void arp(pid_t pid) { + if (getuid() == 0) + firemon_drop_privs(); + + pid_read(pid); + + // print processes + int i; + for (i = 0; i < max_pids; i++) { + if (pids[i].level == 1) { + pid_print_list(i, 0); + int child = find_child(i); + if (child != -1) { + char *fname; + if (asprintf(&fname, "/proc/%d/net/arp", child) == -1) + errExit("asprintf"); + print_arp(fname); + free(fname); + printf("\n"); + } + } + } +} + + diff --git a/src/firemon/caps.c b/src/firemon/caps.c new file mode 100644 index 00000000000..4ae9ab28d5d --- /dev/null +++ b/src/firemon/caps.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firemon.h" +#define MAXBUF 4098 + +static void print_caps(int pid) { + char *file; + if (asprintf(&file, "/proc/%d/status", pid) == -1) { + errExit("asprintf"); + exit(1); + } + + FILE *fp = fopen(file, "r"); + if (!fp) { + printf(" Error: cannot open %s\n", file); + free(file); + return; + } + + char buf[MAXBUF]; + while (fgets(buf, MAXBUF, fp)) { + if (strncmp(buf, "CapBnd:", 7) == 0) { + printf(" %s", buf); + fflush(0); + free(file); + fclose(fp); + return; + } + } + fclose(fp); + free(file); +} + +void caps(pid_t pid) { + if (getuid() == 0) + firemon_drop_privs(); + + pid_read(pid); // include all processes + + // print processes + int i; + for (i = 0; i < max_pids; i++) { + if (pids[i].level == 1) { + pid_print_list(i, 0); + int child = find_child(i); + if (child != -1) + print_caps(child); + } + } + printf("\n"); +} + diff --git a/src/firemon/cgroup.c b/src/firemon/cgroup.c new file mode 100644 index 00000000000..214aefaf981 --- /dev/null +++ b/src/firemon/cgroup.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firemon.h" +#define MAXBUF 4098 + +static void print_cgroup(int pid) { + char *file; + if (asprintf(&file, "/proc/%d/cgroup", pid) == -1) { + errExit("asprintf"); + exit(1); + } + + FILE *fp = fopen(file, "r"); + if (!fp) { + printf(" Error: cannot open %s\n", file); + free(file); + return; + } + + char buf[MAXBUF]; + if (fgets(buf, MAXBUF, fp)) { + printf(" %s", buf); + fflush(0); + } + + fclose(fp); + free(file); +} + +void cgroup(pid_t pid) { + if (getuid() == 0) + firemon_drop_privs(); + + pid_read(pid); + + // print processes + int i; + for (i = 0; i < max_pids; i++) { + if (pids[i].level == 1) { + pid_print_list(i, 0); + int child = find_child(i); + if (child != -1) + print_cgroup(child); + } + } +} + diff --git a/src/firemon/cpu.c b/src/firemon/cpu.c new file mode 100644 index 00000000000..d5d20d1b8ec --- /dev/null +++ b/src/firemon/cpu.c @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firemon.h" +#define MAXBUF 4098 + +static void print_cpu(int pid) { + char *file; + if (asprintf(&file, "/proc/%d/status", pid) == -1) { + errExit("asprintf"); + exit(1); + } + + FILE *fp = fopen(file, "r"); + if (!fp) { + printf(" Error: cannot open %s\n", file); + free(file); + return; + } + + char buf[MAXBUF]; + while (fgets(buf, MAXBUF, fp)) { + if (strncmp(buf, "Cpus_allowed_list:", 18) == 0) { + printf(" %s", buf); + fflush(0); + free(file); + fclose(fp); + return; + } + } + fclose(fp); + free(file); +} + +void cpu(pid_t pid) { + if (getuid() == 0) + firemon_drop_privs(); + + pid_read(pid); + + // print processes + int i; + for (i = 0; i < max_pids; i++) { + if (pids[i].level == 1) { + pid_print_list(i, 0); + int child = find_child(i); + if (child != -1) + print_cpu(child); + } + } +} + diff --git a/src/firemon/firemon.c b/src/firemon/firemon.c new file mode 100644 index 00000000000..d77d11a7a34 --- /dev/null +++ b/src/firemon/firemon.c @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firemon.h" +#include +#include +#include +#include +#include + + +static int arg_route = 0; +static int arg_arp = 0; +static int arg_tree = 0; +static int arg_interface = 0; +static int arg_seccomp = 0; +static int arg_caps = 0; +static int arg_cpu = 0; +static int arg_cgroup = 0; +int arg_nowrap = 0; + +static struct termios tlocal; // startup terminal setting +static struct termios twait; // no wait on key press +static int terminal_set = 0; + +static void my_handler(int s){ + if (terminal_set) + tcsetattr(0, TCSANOW, &tlocal); + exit(0); +} + +// find the first child process for the specified pid +// return -1 if not found +int find_child(int id) { + int i; + for (i = 0; i < max_pids; i++) { + if (pids[i].level == 2 && pids[i].parent == id) + return i; + } + + return -1; +} + +// drop privileges +void firemon_drop_privs(void) { + // drop privileges + if (setgroups(0, NULL) < 0) + errExit("setgroups"); + if (setgid(getgid()) < 0) + errExit("setgid/getgid"); + if (setuid(getuid()) < 0) + errExit("setuid/getuid"); +} + +// sleep and wait for a key to be pressed +void firemon_sleep(int st) { + if (terminal_set == 0) { + tcgetattr(0, &twait); // get current terminal attirbutes; 0 is the file descriptor for stdin + memcpy(&tlocal, &twait, sizeof(tlocal)); + twait.c_lflag &= ~ICANON; // disable canonical mode + twait.c_lflag &= ~ECHO; // no echo + twait.c_cc[VMIN] = 1; // wait until at least one keystroke available + twait.c_cc[VTIME] = 0; // no timeout + terminal_set = 1; + } + tcsetattr(0, TCSANOW, &twait); + + + fd_set fds; + FD_ZERO(&fds); + FD_SET(0,&fds); + int maxfd = 1; + + struct timeval ts; + ts.tv_sec = st; + ts.tv_usec = 0; + + int ready = select(maxfd, &fds, (fd_set *) 0, (fd_set *) 0, &ts); + (void) ready; + if( FD_ISSET(0, &fds)) { + getchar(); + tcsetattr(0, TCSANOW, &tlocal); + printf("\n"); + exit(0); + } + tcsetattr(0, TCSANOW, &tlocal); +} + + +int main(int argc, char **argv) { + unsigned pid = 0; + int i; + + // handle CTRL-C + signal (SIGINT, my_handler); + signal (SIGTERM, my_handler); + + for (i = 1; i < argc; i++) { + // default options + if (strcmp(argv[i], "--help") == 0 || + strcmp(argv[i], "-?") == 0) { + usage(); + return 0; + } + else if (strcmp(argv[i], "--version") == 0) { + printf("firemon version %s\n\n", VERSION); + return 0; + } + + // options without a pid argument + else if (strcmp(argv[i], "--top") == 0) { + top(); // never to return + } + else if (strcmp(argv[i], "--list") == 0) { + list(); + return 0; + } + else if (strcmp(argv[i], "--netstats") == 0) { + netstats(); + return 0; + } + + + // cumulative options with or without a pid argument + else if (strcmp(argv[i], "--cgroup") == 0) { + arg_cgroup = 1; + } + else if (strcmp(argv[i], "--cpu") == 0) { + arg_cpu = 1; + } + else if (strcmp(argv[i], "--seccomp") == 0) { + arg_seccomp = 1; + } + else if (strcmp(argv[i], "--caps") == 0) { + arg_caps = 1; + } + else if (strcmp(argv[i], "--tree") == 0) { + arg_tree = 1; + } + else if (strcmp(argv[i], "--interface") == 0) { + arg_interface = 1; + } + else if (strcmp(argv[i], "--route") == 0) { + arg_route = 1; + } + else if (strcmp(argv[i], "--arp") == 0) { + arg_arp = 1; + } + + else if (strncmp(argv[i], "--name=", 7) == 0) { + char *name = argv[i] + 7; + if (name2pid(name, (pid_t *) &pid)) { + fprintf(stderr, "Error: cannot find sandbox %s\n", name); + return 1; + } + } + + // etc + else if (strcmp(argv[i], "--nowrap") == 0) + arg_nowrap = 1; + + // invalid option + else if (*argv[i] == '-') { + fprintf(stderr, "Error: invalid option\n"); + return 1; + } + + // PID argument + else { + // this should be a pid number + char *ptr = argv[i]; + while (*ptr != '\0') { + if (!isdigit(*ptr)) { + fprintf(stderr, "Error: not a valid PID number\n"); + exit(1); + } + ptr++; + } + + sscanf(argv[i], "%u", &pid); + break; + } + } + + if (arg_tree) + tree((pid_t) pid); + if (arg_interface) + interface((pid_t) pid); + if (arg_route) + route((pid_t) pid); + if (arg_arp) + arp((pid_t) pid); + if (arg_seccomp) + seccomp((pid_t) pid); + if (arg_caps) + caps((pid_t) pid); + if (arg_cpu) + cpu((pid_t) pid); + if (arg_cgroup) + cgroup((pid_t) pid); + + if (!arg_route && !arg_arp && !arg_interface && !arg_tree && !arg_caps && !arg_seccomp) + procevent((pid_t) pid); // never to return + + return 0; +} diff --git a/src/firemon/firemon.h b/src/firemon/firemon.h new file mode 100644 index 00000000000..59b1f352cfc --- /dev/null +++ b/src/firemon/firemon.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef FIREMON_H +#define FIREMON_H +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include "../include/pid.h" +#include "../include/common.h" + +// clear screen +static inline void firemon_clrscr(void) { + printf("\033[2J\033[1;1H"); + fflush(0); +} + +// firemon.c +extern int arg_nowrap; +int find_child(int id); +void firemon_drop_privs(void); +void firemon_sleep(int st); + + +// procevent.c +void procevent(pid_t pid); + +// usage.c +void usage(void); + +// top.c +void top(void); + +// list.c +void list(void); + +// interface.c +void interface(pid_t pid); + +// arp.c +void arp(pid_t pid); + +// route.c +void route(pid_t pid); + +// caps.c +void caps(pid_t pid); + +// seccomp.c +void seccomp(pid_t pid); + +// cpu.c +void cpu(pid_t pid); + +// cgroup.c +void cgroup(pid_t pid); + +// tree.c +void tree(pid_t pid); + +// netstats.c +void netstats(void); + +#endif diff --git a/src/firemon/interface.c b/src/firemon/interface.c new file mode 100644 index 00000000000..52a9c33cd07 --- /dev/null +++ b/src/firemon/interface.c @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firemon.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#include +//#include + +// print IP addresses for all interfaces +static void net_ifprint(void) { + uint32_t ip; + uint32_t mask; + struct ifaddrs *ifaddr, *ifa; + + int fd; + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + fprintf(stderr, "Error: cannot open AF_INET socket\n"); + exit(1); + } + + if (getifaddrs(&ifaddr) == -1) + errExit("getifaddrs"); + + // walk through the linked list + printf(" Link status:\n"); + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) + continue; + + if (ifa->ifa_addr->sa_family == AF_PACKET) { + if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP) { + if (ifa->ifa_data != NULL) { + struct rtnl_link_stats *stats = ifa->ifa_data; + + // extract mac address + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ); + int rv = ioctl (fd, SIOCGIFHWADDR, &ifr); + + if (rv == 0) + printf(" %s UP, %02x:%02x:%02x:%02x:%02x:%02x\n", + ifa->ifa_name, PRINT_MAC((unsigned char *) &ifr.ifr_hwaddr.sa_data)); + else + printf(" %s UP\n", ifa->ifa_name); + + printf(" tx/rx: %u/%u packets, %u/%u bytes\n", + stats->tx_packets, stats->rx_packets, + stats->tx_bytes, stats->rx_bytes); + } + } + else + printf(" %s DOWN\n", ifa->ifa_name); + } + } + + + // walk through the linked list + printf(" IPv4 status:\n"); + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) + continue; + + if (ifa->ifa_addr->sa_family == AF_INET) { + struct sockaddr_in *si = (struct sockaddr_in *) ifa->ifa_netmask; + mask = ntohl(si->sin_addr.s_addr); + si = (struct sockaddr_in *) ifa->ifa_addr; + ip = ntohl(si->sin_addr.s_addr); + + char *status; + if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP) + status = "UP"; + else + status = "DOWN"; + + printf(" %s %s, %d.%d.%d.%d/%u\n", + ifa->ifa_name, status, PRINT_IP(ip), mask2bits(mask)); + } + } + + + // walk through the linked list + printf(" IPv6 status:\n"); + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) + continue; + + if (ifa->ifa_addr->sa_family == AF_INET6) { + char host[NI_MAXHOST]; + int s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), + host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); + if (s == 0) { + char *ptr; + if ((ptr = strchr(host, '%')) != NULL) + *ptr = '\0'; + char *status; + if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP) + status = "UP"; + else + status = "DOWN"; + + printf(" %s %s, %s\n", ifa->ifa_name, status, host); + } + } + } + + freeifaddrs(ifaddr); + close(fd); +} + +static void print_sandbox(pid_t pid) { + pid_t child = fork(); + if (child == -1) + return; + + if (child == 0) { + int rv = join_namespace(pid, "net"); + if (rv) + return; + net_ifprint(); + printf("\n"); + exit(0); + } + + // wait for the child to finish + waitpid(child, NULL, 0); +} + +void interface(pid_t pid) { + if (getuid() != 0) { + fprintf(stderr, "Error: you need to be root to run this command\n"); + exit(1); + } + + pid_read(pid); // a pid of 0 will include all processes + + // print processes + int i; + for (i = 0; i < max_pids; i++) { + if (pids[i].level == 1) { + pid_print_list(i, 0); + int child = find_child(i); + if (child != -1) { + print_sandbox(child); + } + } + } +} + diff --git a/src/firemon/list.c b/src/firemon/list.c new file mode 100644 index 00000000000..6a997bde1a9 --- /dev/null +++ b/src/firemon/list.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firemon.h" + +void list(void) { + if (getuid() == 0) + firemon_drop_privs(); + + pid_read(0); // include all processes + + // print processes + int i; + for (i = 0; i < max_pids; i++) { + if (pids[i].level == 1) + pid_print_list(i, 0); + } +} + diff --git a/src/firemon/netstats.c b/src/firemon/netstats.c new file mode 100644 index 00000000000..6c4a767f15c --- /dev/null +++ b/src/firemon/netstats.c @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firemon.h" +#include +#include +#include +#include +#include + +#define MAXBUF 4096 + +static char *get_header(void) { + char *rv; + if (asprintf(&rv, "%-5.5s %-9.9s %-10.10s %-10.10s %s", + "PID", "User", "RX(KB/s)", "TX(KB/s)", "Command") == -1) + errExit("asprintf"); + + return rv; +} + +void get_stats(int parent) { + // find the first child + int child = -1; + for (child = parent + 1; child < max_pids; child++) { + if (pids[child].parent == parent) + break; + } + + if (child == -1) + goto errexit; + + // open /proc/child/net/dev file and read rx and tx + char *fname; + if (asprintf(&fname, "/proc/%d/net/dev", child) == -1) + errExit("asprintf"); + FILE *fp = fopen(fname, "r"); + if (!fp) { + free(fname); + goto errexit; + } + + char buf[MAXBUF]; + long long unsigned rx = 0; + long long unsigned tx = 0; + while (fgets(buf, MAXBUF, fp)) { + if (strncmp(buf, "Inter", 5) == 0) + continue; + if (strncmp(buf, " face", 5) == 0) + continue; + + char *ptr = buf; + while (*ptr != '\0' && *ptr != ':') { + ptr++; + } + + if (*ptr == '\0') { + fclose(fp); + free(fname); + goto errexit; + } + ptr++; + + long long unsigned rxval; + long long unsigned txval; + unsigned a, b, c, d, e, f, g; + sscanf(ptr, "%llu %u %u %u %u %u %u %u %llu", + &rxval, &a, &b, &c, &d, &e, &f, &g, &txval); + rx += rxval; + tx += txval; + } + + // store data + pids[parent].rx_delta = rx - pids[parent].rx; + pids[parent].rx = rx; + pids[parent].tx_delta = tx - pids[parent].tx; + pids[parent].tx = tx; + + + free(fname); + fclose(fp); + return; + +errexit: + pids[parent].rx = 0; + pids[parent].tx = 0; + pids[parent].rx_delta = 0; + pids[parent].tx_delta = 0; +} + + +static void print_proc(int index, int itv, int col) { + // command + char *cmd = pid_proc_cmdline(index); + char *ptrcmd; + if (cmd == NULL) { + if (pids[index].zombie) + ptrcmd = "(zombie)"; + else + ptrcmd = ""; + } + else + ptrcmd = cmd; + // if the command doesn't have a --net= option, don't print + if (strstr(ptrcmd, "--net=") == NULL) { + if (cmd) + free(cmd); + return; + } + + // pid + char pidstr[10]; + snprintf(pidstr, 10, "%u", index); + + // user + char *user = pid_get_user_name(pids[index].uid); + char *ptruser; + if (user) + ptruser = user; + else + ptruser = ""; + + + float rx_kbps = ((float) pids[index].rx_delta / 1000) / itv; + char ptrrx[15]; + sprintf(ptrrx, "%.03f", rx_kbps); + + float tx_kbps = ((float) pids[index].tx_delta / 1000) / itv; + char ptrtx[15]; + sprintf(ptrtx, "%.03f", tx_kbps); + + char buf[1024 + 1]; + snprintf(buf, 1024, "%-5.5s %-9.9s %-10.10s %-10.10s %s", + pidstr, ptruser, ptrrx, ptrtx, ptrcmd); + if (col < 1024) + buf[col] = '\0'; + printf("%s\n", buf); + + if (cmd) + free(cmd); + if (user) + free(user); + +} + +void netstats(void) { + if (getuid() == 0) + firemon_drop_privs(); + + pid_read(0); // include all processes + + printf("Displaying network statistics only for sandboxes using a new network namespace.\n"); + + // print processes + while (1) { + // set pid table + int i; + int itv = 5; // 5 second interval + pid_read(0); // todo: preserve the last calculation if any, so we don't have to do get_stats() + + // start rx/tx measurements + for (i = 0; i < max_pids; i++) { + if (pids[i].level == 1) + get_stats(i); + } + + // wait 5 seconds + firemon_sleep(itv); + + // grab screen size + struct winsize sz; + int row = 24; + int col = 80; + if (!ioctl(0, TIOCGWINSZ, &sz)) { + col = sz.ws_col; + row = sz.ws_row; + } + + // start printing + firemon_clrscr(); + char *header = get_header(); + if (strlen(header) > col) + header[col] = '\0'; + printf("%s\n", header); + if (row > 0) + row--; + free(header); + + // start rx/tx measurements + for (i = 0; i < max_pids; i++) { + if (pids[i].level == 1) { + get_stats(i); + print_proc(i, itv, col); + } + } + } +} + diff --git a/src/firemon/procevent.c b/src/firemon/procevent.c new file mode 100644 index 00000000000..d2b5f7bbfcc --- /dev/null +++ b/src/firemon/procevent.c @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firemon.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define PIDS_BUFLEN 4096 +#define SERVER_PORT 889 // 889-899 is left unassigned by IANA + +static int pid_is_firejail(pid_t pid) { + uid_t rv = 0; + + // open stat file + char *file; + if (asprintf(&file, "/proc/%u/status", pid) == -1) { + perror("asprintf"); + exit(1); + } + FILE *fp = fopen(file, "r"); + if (!fp) { + free(file); + return 0; + } + + // look for firejail executable name + char buf[PIDS_BUFLEN]; + while (fgets(buf, PIDS_BUFLEN - 1, fp)) { + if (strncmp(buf, "Name:", 5) == 0) { + char *ptr = buf + 5; + while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) { + ptr++; + } + if (*ptr == '\0') + goto doexit; + if (strncmp(ptr, "firejail", 8) == 0) + rv = 1; +// if (strncmp(ptr, "lxc-execute", 11) == 0) +// rv = 1; + break; + } + } +doexit: + fclose(fp); + free(file); + return rv; +} + + +static int procevent_netlink_setup(void) { + // open socket for process event connector + int sock; + if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR)) < 0) { + fprintf(stderr, "Error: cannot open netlink socket\n"); + exit(1); + } + + // bind socket + struct sockaddr_nl addr; + memset(&addr, 0, sizeof(addr)); + addr.nl_pid = getpid(); + addr.nl_family = AF_NETLINK; + addr.nl_groups = CN_IDX_PROC; + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + fprintf(stderr, "Error: cannot bind to netlink socket\n"); + exit(1); + } + + // send monitoring message + struct nlmsghdr nlmsghdr; + memset(&nlmsghdr, 0, sizeof(nlmsghdr)); + nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct cn_msg) + sizeof(enum proc_cn_mcast_op)); + nlmsghdr.nlmsg_pid = getpid(); + nlmsghdr.nlmsg_type = NLMSG_DONE; + + struct cn_msg cn_msg; + memset(&cn_msg, 0, sizeof(cn_msg)); + cn_msg.id.idx = CN_IDX_PROC; + cn_msg.id.val = CN_VAL_PROC; + cn_msg.len = sizeof(enum proc_cn_mcast_op); + + struct iovec iov[3]; + iov[0].iov_base = &nlmsghdr; + iov[0].iov_len = sizeof(nlmsghdr); + iov[1].iov_base = &cn_msg; + iov[1].iov_len = sizeof(cn_msg); + + enum proc_cn_mcast_op op = PROC_CN_MCAST_LISTEN; + iov[2].iov_base = &op; + iov[2].iov_len = sizeof(op); + + if (writev(sock, iov, 3) == -1) { + fprintf(stderr, "Error: cannot write to netlink socket\n"); + exit(1); + } + + return sock; +} + + +static int procevent_monitor(const int sock, pid_t mypid) { + ssize_t len; + struct nlmsghdr *nlmsghdr; + + // timeout in order to re-enable firejail module trace + struct timeval tv; + tv.tv_sec = 30; + tv.tv_usec = 0; + + while (1) { +#define BUFFSIZE 4096 + char __attribute__ ((aligned(NLMSG_ALIGNTO)))buf[BUFFSIZE]; + + fd_set readfds; + int max; + FD_ZERO(&readfds); + FD_SET(sock, &readfds); + max = sock; + max++; + + int rv = select(max, &readfds, NULL, NULL, &tv); + if (rv == -1) { + fprintf(stderr, "recv: %s\n", strerror(errno)); + return -1; + } + + // timeout + if (rv == 0) { + tv.tv_sec = 30; + tv.tv_usec = 0; + continue; + } + + + if ((len = recv(sock, buf, sizeof(buf), 0)) == 0) { + return 0; + } + if (len == -1) { + if (errno == EINTR) { + return 0; + } else { + fprintf(stderr,"recv: %s\n", strerror(errno)); + return -1; + } + } + + for (nlmsghdr = (struct nlmsghdr *)buf; + NLMSG_OK (nlmsghdr, len); + nlmsghdr = NLMSG_NEXT (nlmsghdr, len)) { + + struct cn_msg *cn_msg; + struct proc_event *proc_ev; + struct tm tm; + time_t now; + + if ((nlmsghdr->nlmsg_type == NLMSG_ERROR) || + (nlmsghdr->nlmsg_type == NLMSG_NOOP)) + continue; + + cn_msg = NLMSG_DATA(nlmsghdr); + if ((cn_msg->id.idx != CN_IDX_PROC) || + (cn_msg->id.val != CN_VAL_PROC)) + continue; + + (void)time(&now); + (void)localtime_r(&now, &tm); + char line[PIDS_BUFLEN]; + char *lineptr = line; + sprintf(lineptr, "%2.2d:%2.2d:%2.2d", tm.tm_hour, tm.tm_min, tm.tm_sec); + lineptr += strlen(lineptr); + + proc_ev = (struct proc_event *)cn_msg->data; + pid_t pid = 0; + pid_t child = 0; + int remove_pid = 0; + switch (proc_ev->what) { + case PROC_EVENT_FORK: + if (proc_ev->event_data.fork.child_pid != + proc_ev->event_data.fork.child_tgid) + continue; // this is a thread, not a process + pid = proc_ev->event_data.fork.parent_tgid; + if (pids[pid].level > 0) { + child = proc_ev->event_data.fork.child_tgid; + child %= max_pids; + pids[child].level = pids[pid].level + 1; + pids[child].uid = pid_get_uid(child); + } + sprintf(lineptr, " fork"); + break; + case PROC_EVENT_EXEC: + pid = proc_ev->event_data.exec.process_tgid; + sprintf(lineptr, " exec"); + break; + + case PROC_EVENT_EXIT: + if (proc_ev->event_data.exit.process_pid != + proc_ev->event_data.exit.process_tgid) + continue; // this is a thread, not a process + + pid = proc_ev->event_data.exit.process_tgid; + remove_pid = 1; + sprintf(lineptr, " exit"); + break; + + case PROC_EVENT_UID: + pid = proc_ev->event_data.id.process_tgid; + sprintf(lineptr, " uid "); + break; + + case PROC_EVENT_GID: + pid = proc_ev->event_data.id.process_tgid; + sprintf(lineptr, " gid "); + break; + + case PROC_EVENT_SID: + pid = proc_ev->event_data.sid.process_tgid; + sprintf(lineptr, " sid "); + break; + + default: + sprintf(lineptr, "\n"); + continue; + } + + int add_new = 0; + if (pids[pid].level < 0) // not a firejail process + continue; + else if (pids[pid].level == 0) { // new porcess, do we track it? + if (pid_is_firejail(pid) && mypid == 0) { + pids[pid].level = 1; + add_new = 1; + } + else { + pids[pid].level = -1; + continue; + } + } + + lineptr += strlen(lineptr); + sprintf(lineptr, " %u", pid); + lineptr += strlen(lineptr); + + char *user = pids[pid].user; + if (!user) + user = pid_get_user_name(pids[pid].uid); + if (user) { + pids[pid].user = user; + sprintf(lineptr, " (%s)", user); + lineptr += strlen(lineptr); + } + + + int sandbox_closed = 0; // exit sandbox flag + char *cmd = pids[pid].cmd; + if (!cmd) { + cmd = pid_proc_cmdline(pid); + } + if (add_new) { + if (!cmd) + sprintf(lineptr, " NEW SANDBOX\n"); + else + sprintf(lineptr, " NEW SANDBOX: %s\n", cmd); + lineptr += strlen(lineptr); + } + else if (proc_ev->what == PROC_EVENT_EXIT && pids[pid].level == 1) { + sprintf(lineptr, " EXIT SANDBOX\n"); + lineptr += strlen(lineptr); + if (mypid == pid) + sandbox_closed = 1; + } + else { + if (!cmd) { + cmd = pid_proc_cmdline(pid); + } + if (cmd == NULL) + sprintf(lineptr, "\n"); + else { + sprintf(lineptr, " %s\n", cmd); + free(cmd); + } + lineptr += strlen(lineptr); + } + (void) lineptr; + + // print the event + printf("%s", line); + fflush(0); + + // unflag pid for exit events + if (remove_pid) { + if (pids[pid].user) + free(pids[pid].user); + if (pids[pid].cmd) + free(pids[pid].cmd); + memset(&pids[pid], 0, sizeof(Process)); + } + + // print forked child + if (child) { + cmd = pid_proc_cmdline(child); + if (cmd) { + printf("\tchild %u %s\n", child, cmd); + free(cmd); + } + else + printf("\tchild %u\n", child); + } + + // on uid events the uid is changing + if (proc_ev->what == PROC_EVENT_UID) { + if (pids[pid].user) + free(pids[pid].user); + pids[pid].user = 0; + pids[pid].uid = pid_get_uid(pid); + } + + if (sandbox_closed) + exit(0); + } + } + return 0; +} + +static void procevent_print_pids(void) { + // print files + int i; + for (i = 0; i < max_pids; i++) { + if (pids[i].level == 1) + pid_print_tree(i, 0, 1); + } + printf("\n"); +} + +void procevent(pid_t pid) { + // need to be root for this + if (getuid() != 0) { + fprintf(stderr, "Error: you need to be root to get process events\n"); + exit(1); + } + + // read and print sandboxed processes + pid_read(pid); + procevent_print_pids(); + + // monitor using netlink + int sock = procevent_netlink_setup(); + if (sock < 0) { + fprintf(stderr, "Error: cannot open netlink socket\n"); + exit(1); + } + + procevent_monitor(sock, pid); // it will never return from here + assert(0); + close(sock); // quiet static analyzers +} diff --git a/src/firemon/route.c b/src/firemon/route.c new file mode 100644 index 00000000000..7f559c7b509 --- /dev/null +++ b/src/firemon/route.c @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firemon.h" +#include +#include +#define MAXBUF 4096 + +typedef struct iflist_t { + struct iflist_t *next; + uint32_t ip; +} IfList; +static IfList *ifs = NULL; +static char last_start[MAXBUF + 1]; + +static IfList *list_find(uint32_t ip, uint32_t mask) { + IfList *ptr = ifs; + while (ptr) { + if ((ptr->ip & mask) == (ip & mask)) + return ptr; + ptr = ptr->next; + } + + return NULL; +} + +static void extract_if(const char *fname) { + // clear interface list + while (ifs) { + IfList *tmp = ifs->next; + free(ifs); + ifs = tmp; + } + assert(ifs == NULL); + + FILE *fp = fopen(fname, "r"); + if (!fp) + return; + + char buf[MAXBUF]; + int state = 0; // 0 -wait for Local + // + while (fgets(buf, MAXBUF, fp)) { + // remove blanks, \n + char *ptr = buf; + while (*ptr == ' ' || *ptr == '\t') + ptr++; + char *start = ptr; + if (*start == '\0') + continue; + ptr = strchr(ptr, '\n'); + if (ptr) + *ptr = '\0'; + + if (state == 0) { + if (strncmp(buf, "Local:", 6) == 0) { + state = 1; + continue; + } + } + else if (state == 1) { + // remove broadcast addresses + if (strstr(start,"BROADCAST")) + continue; + else if (*start == '+') + continue; + else if (*start == '|') { + memset(last_start, 0, MAXBUF + 1); + strncpy(last_start, start, MAXBUF); + continue; + } + else if (strstr(buf, "LOCAL")) { +// printf("%s %s\n", last_start, start); + unsigned mbits; + sscanf(start, "/%u", &mbits); + if (mbits != 32) + continue; + + unsigned a, b, c, d; + if (sscanf(last_start, "|-- %u.%u.%u.%u", &a, &b, &c, &d) != 4 || a > 255 || b > 255 || c > 255 || d > 255) + continue; + + IfList *newif = malloc(sizeof(IfList)); + if (!newif) + errExit("malloc"); + newif->ip = a * 0x1000000 + b * 0x10000 + c * 0x100 + d; + newif->next = ifs; + ifs = newif; + } + } + } + + fclose(fp); + + +} + +static void print_route(const char *fname) { + FILE *fp = fopen(fname, "r"); + if (!fp) + return; + + printf(" Route table:\n"); + char buf[MAXBUF]; + while (fgets(buf, MAXBUF, fp)) { + // remove blanks, \n + char *ptr = buf; + while (*ptr == ' ' || *ptr == '\t') + ptr++; + char *start = ptr; + if (*start == '\0') + continue; + ptr = strchr(ptr, '\n'); + if (ptr) + *ptr = '\0'; + + // remove table header + //Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT + if (strncmp(start, "Iface", 5) == 0) + continue; + + // extract data + char ifname[64]; + char destination[64]; + char gateway[64]; + char flags[64]; + char refcnt[64]; + char use[64]; + char metric[64]; + char mask[64]; + int rv = sscanf(start, "%s %s %s %s %s %s %s %s\n", ifname, destination, gateway, flags, refcnt, use, metric, mask); + if (rv != 8) + continue; + + // destination ip + uint32_t destip; + sscanf(destination, "%x", &destip); + destip = ntohl(destip); + uint32_t destmask; + sscanf(mask, "%x", &destmask); + destmask = ntohl(destmask); + uint32_t gw; + sscanf(gateway, "%x", &gw); + gw = ntohl(gw); + +// printf("#%s# #%s# #%s# #%s# #%s# #%s# #%s# #%s#\n", ifname, destination, gateway, flags, refcnt, use, metric, mask); + if (gw != 0) + printf(" %u.%u.%u.%u/%u via %u.%u.%u.%u, dev %s, metric %s\n", + PRINT_IP(destip), mask2bits(destmask), + PRINT_IP(gw), + ifname, + metric); + else { // this is an interface + IfList *ifentry = list_find(destip, destmask); + if (ifentry) { + printf(" %u.%u.%u.%u/%u, dev %s, scope link src %d.%d.%d.%d\n", + PRINT_IP(destip), mask2bits(destmask), + ifname, + PRINT_IP(ifentry->ip)); + } + } + } + + fclose(fp); + +} + +void route(pid_t pid) { + if (getuid() == 0) + firemon_drop_privs(); + + pid_read(pid); + + // print processes + int i; + for (i = 0; i < max_pids; i++) { + if (pids[i].level == 1) { + pid_print_list(i, 0); + int child = find_child(i); + if (child != -1) { + char *fname; + if (asprintf(&fname, "/proc/%d/net/fib_trie", child) == -1) + errExit("asprintf"); + extract_if(fname); + free(fname); + + if (asprintf(&fname, "/proc/%d/net/route", child) == -1) + errExit("asprintf"); + print_route(fname); + free(fname); + printf("\n"); + } + } + } +} + + diff --git a/src/firemon/seccomp.c b/src/firemon/seccomp.c new file mode 100644 index 00000000000..4ffc93f2e85 --- /dev/null +++ b/src/firemon/seccomp.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firemon.h" + +#define MAXBUF 4098 +static void print_seccomp(int pid) { + char *file; + if (asprintf(&file, "/proc/%d/status", pid) == -1) { + errExit("asprintf"); + exit(1); + } + + FILE *fp = fopen(file, "r"); + if (!fp) { + printf(" Error: cannot open %s\n", file); + free(file); + return; + } + + char buf[MAXBUF]; + while (fgets(buf, MAXBUF, fp)) { + if (strncmp(buf, "Seccomp:", 8) == 0) { + printf(" %s", buf); + fflush(0); + fclose(fp); + free(file); + return; + } + } + fclose(fp); + free(file); +} + +void seccomp(pid_t pid) { + if (getuid() == 0) + firemon_drop_privs(); + + pid_read(pid); // include all processes + + // print processes + int i; + for (i = 0; i < max_pids; i++) { + if (pids[i].level == 1) { + pid_print_list(i, 0); + int child = find_child(i); + if (child != -1) + print_seccomp(child); + } + } + printf("\n"); +} + diff --git a/src/firemon/top.c b/src/firemon/top.c new file mode 100644 index 00000000000..1eb7536941e --- /dev/null +++ b/src/firemon/top.c @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firemon.h" +#include +#include +#include +#include +#include + +static unsigned pgs_rss = 0; +static unsigned pgs_shared = 0; +static unsigned clocktick = 0; +static unsigned long long sysuptime = 0; + +static char *get_header(void) { + char *rv; + if (asprintf(&rv, "%-5.5s %-9.9s %-8.8s %-8.8s %-5.5s %-4.4s %-9.9s %s", + "PID", "User", "RES(KiB)", "SHR(KiB)", "CPU%", "Prcs", "Uptime", "Command") == -1) + errExit("asprintf"); + + return rv; +} + + +// recursivity!!! +static char *print_top(unsigned index, unsigned parent, unsigned *utime, unsigned *stime, unsigned itv, float *cpu, int *cnt) { + char *rv = NULL; + + char procdir[20]; + snprintf(procdir, 20, "/proc/%u", index); + struct stat s; + if (stat(procdir, &s) == -1) + return NULL; + + if (pids[index].level == 1) { + pgs_rss = 0; + pgs_shared = 0; + *utime = 0; + *stime = 0; + *cnt = 0; + } + + (*cnt)++; + pid_getmem(index, &pgs_rss, &pgs_shared); + unsigned utmp; + unsigned stmp; + pid_get_cpu_time(index, &utmp, &stmp); + *utime += utmp; + *stime += stmp; + + + int i; + for (i = index + 1; i < max_pids; i++) { + if (pids[i].parent == index) + print_top(i, index, utime, stime, itv, cpu, cnt); + } + + if (pids[index].level == 1) { + // pid + char pidstr[10]; + snprintf(pidstr, 10, "%u", index); + + // command + char *cmd = pid_proc_cmdline(index); + char *ptrcmd; + if (cmd == NULL) { + if (pids[index].zombie) + ptrcmd = "(zombie)"; + else + ptrcmd = ""; + } + else + ptrcmd = cmd; + + // user + char *user = pid_get_user_name(pids[index].uid); + char *ptruser; + if (user) + ptruser = user; + else + ptruser = ""; + + // memory + int pgsz = getpagesize(); + char rss[10]; + snprintf(rss, 10, "%u", pgs_rss * pgsz / 1024); + char shared[10]; + snprintf(shared, 10, "%u", pgs_shared * pgsz / 1024); + + // uptime + unsigned long long uptime = pid_get_start_time(index); + if (clocktick == 0) + clocktick = sysconf(_SC_CLK_TCK); + uptime /= clocktick; + uptime = sysuptime - uptime; + unsigned sec = uptime % 60; + uptime -= sec; + uptime /= 60; + unsigned min = uptime % 60; + uptime -= min; + uptime /= 60; + unsigned hour = uptime; + char uptime_str[50]; + snprintf(uptime_str, 50, "%02u:%02u:%02u", hour, min, sec); + + // cpu + itv *= clocktick; + float ud = (float) (*utime - pids[index].utime) / itv * 100; + float sd = (float) (*stime - pids[index].stime) / itv * 100; + float cd = ud + sd; + *cpu = cd; + char cpu_str[10]; + snprintf(cpu_str, 10, "%2.1f", cd); + + // process count + char prcs_str[10]; + snprintf(prcs_str, 10, "%d", *cnt); + + if (asprintf(&rv, "%-5.5s %-9.9s %-8.8s %-8.8s %-5.5s %-4.4s %-9.9s %s", + pidstr, ptruser, rss, shared, cpu_str, prcs_str, uptime_str, ptrcmd) == -1) + errExit("asprintf"); + + if (cmd) + free(cmd); + if (user) + free(user); + + } + + return rv; +} + + +typedef struct node_t { + struct node_t *next; + char *line; + float cpu; +} Node; + +static Node *head = NULL; + +static void head_clear(void) { + Node *ptr = head; + while (ptr) { + if (ptr->line) + free(ptr->line); + Node *next = ptr->next; + free(ptr); + ptr = next; + } + + head = NULL; +} + +static void head_add(float cpu, char *line) { + // allocate a new node structure + Node *node = malloc(sizeof(Node)); + if (!node) + errExit("malloc"); + node->line = line; + node->cpu = cpu; + node->next = NULL; + + // insert in first list position + if (head == NULL || head->cpu < cpu) { + node->next = head; + head = node; + return; + } + + // insert in the right place + Node *ptr = head; + while (1) { + // last position + Node *current = ptr->next; + if (current == NULL) { + ptr->next = node; + return; + } + + // current position + if (current->cpu < cpu) { + ptr->next = node; + node->next = current; + return; + } + + ptr = current; + } +} + +void head_print(int col, int row) { + Node *ptr = head; + int current = 0; + while (ptr) { + if (current >= row) + break; + + if (strlen(ptr->line) > col) + ptr->line[col] = '\0'; + + if (ptr->next == NULL || current == (row - 1)) { + printf("%s", ptr->line); + fflush(0); + } + else + printf("%s\n", ptr->line); + + ptr = ptr->next; + current++; + } +} + +void top(void) { + if (getuid() == 0) + firemon_drop_privs(); + + while (1) { + // clear linked list + head_clear(); + + // set pid table + int i; + int itv = 5; // 5 second interval + pid_read(0); + + // start cpu measurements + unsigned utime = 0; + unsigned stime = 0; + for (i = 0; i < max_pids; i++) { + if (pids[i].level == 1) + pid_store_cpu(i, 0, &utime, &stime); + } + + // wait 5 seconds + firemon_sleep(itv); + + // grab screen size + struct winsize sz; + int row = 24; + int col = 80; + if (!ioctl(0, TIOCGWINSZ, &sz)) { + col = sz.ws_col; + row = sz.ws_row; + } + + // start printing + firemon_clrscr(); + char *header = get_header(); + if (strlen(header) > col) + header[col] = '\0'; + printf("%s\n", header); + if (row > 0) + row--; + free(header); + + // find system uptime + FILE *fp = fopen("/proc/uptime", "r"); + if (fp) { + float f; + int rv = fscanf(fp, "%f", &f); + (void) rv; + sysuptime = (unsigned long long) f; + fclose(fp); + } + + // print processes + for (i = 0; i < max_pids; i++) { + if (pids[i].level == 1) { + float cpu = 0; + int cnt = 0; // process count + char *line = print_top(i, 0, &utime, &stime, itv, &cpu, &cnt); + if (line) + head_add(cpu, line); + } + } + head_print(col, row); + } +} + diff --git a/src/firemon/tree.c b/src/firemon/tree.c new file mode 100644 index 00000000000..97e0e1f131b --- /dev/null +++ b/src/firemon/tree.c @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firemon.h" + +void tree(pid_t pid) { + if (getuid() == 0) + firemon_drop_privs(); + + pid_read(pid); // include all processes + + // print processes + int i; + for (i = 0; i < max_pids; i++) { + if (pids[i].level == 1) + pid_print_tree(i, 0, arg_nowrap); + } + printf("\n"); +} + diff --git a/src/firemon/usage.c b/src/firemon/usage.c new file mode 100644 index 00000000000..52788807ad9 --- /dev/null +++ b/src/firemon/usage.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firemon.h" + +void usage(void) { + printf("firemon - version %s\n", VERSION); + printf("Usage: firemon [OPTIONS] [PID]\n\n"); + printf("Monitor processes started in a Firejail sandbox. Without any PID specified,\n"); + printf("all processes started by Firejail are monitored. Descendants of these processes\n"); + printf("are also being monitored.\n\n"); + printf("Options:\n"); + printf("\t--arp - print ARP table for each sandbox.\n\n"); + printf("\t--caps - print capabilities configuration for each sandbox.\n\n"); + printf("\t--cgroup - print control group information for each sandbox.\n\n"); + printf("\t--cpu - print CPU affinity for each sandbox.\n\n"); + printf("\t--help, -? - this help screen.\n\n"); + printf("\t--interface - print network interface information for each sandbox.\n\n"); + printf("\t--list - list all sandboxes.\n\n"); + printf("\t--name=name - print information only about named sandbox.\n\n"); + printf("\t--netstats - monitor network statistics for sandboxes creating a new\n"); + printf("\t\tnetwork namespace.\n\n"); + printf("\t--route - print route table for each sandbox.\n\n"); + printf("\t--seccomp - print seccomp configuration for each sandbox.\n\n"); + printf("\t--tree - print a tree of all sandboxed processes.\n\n"); + printf("\t--top - monitor the most CPU-intensive sandboxes.\n\n"); + printf("\t--version - print program version and exit.\n\n"); + + printf("Without any options, firemon monitors all fork, exec, id change, and exit events\n"); + printf("in the sandbox. Monitoring a specific PID is also supported.\n\n"); + + printf("Option --list prints a list of all sandboxes. The format for each entry is as\n"); + printf("follows:\n\n"); + printf("\tPID:USER:Command\n\n"); + + printf("Option --tree prints the tree of processes running in the sandbox. The format\n"); + printf("for each process entry is as follows:\n\n"); + printf("\tPID:USER:Command\n\n"); + + printf("Option --top is similar to the UNIX top command, however it applies only to\n"); + printf("sandboxes. Listed below are the available fields (columns) in alphabetical\n"); + printf("order:\n\n"); + printf("\tCommand - command used to start the sandbox.\n"); + printf("\tCPU%% - CPU usage, the sandbox share of the elapsed CPU time since the\n"); + printf("\t last screen update\n"); + printf("\tPID - Unique process ID for the task controlling the sandbox.\n"); + printf("\tPrcs - number of processes running in sandbox, including the controlling\n"); + printf("\t process.\n"); + printf("\tRES - Resident Memory Size (KiB), sandbox non-swapped physical memory.\n"); + printf("\t It is a sum of the RES values for all processes running in the\n"); + printf("\t sandbox.\n"); + printf("\tSHR - Shared Memory Size (KiB), it reflects memory shared with other\n"); + printf("\t processes. It is a sum of the SHR values for all processes running\n"); + printf("\t in the sandbox, including the controlling process.\n"); + printf("\tUptime - sandbox running time in hours:minutes:seconds format.\n"); + printf("\tUser - The owner of the sandbox.\n"); + printf("\n"); + printf("License GPL version 2 or later\n"); + printf("Homepage: http://firejail.sourceforge.net\n"); + printf("\n"); +} diff --git a/src/fshaper/fshaper.sh b/src/fshaper/fshaper.sh new file mode 100755 index 00000000000..4045fd5a458 --- /dev/null +++ b/src/fshaper/fshaper.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +usage() { + echo "Usage:" + echo " fshaper.sh --status" + echo " fshaper.sh --clear device" + echo " fshaper.sh --set device download-speed upload-speed" +} + +if [ "$1" = "--status" ]; then + /sbin/tc -s qdisc ls + /sbin/tc -s class ls + exit +fi + +if [ "$1" = "--clear" ]; then + if [ $# -ne 2 ]; then + echo "Error: invalid command" + usage + exit + fi + + DEV=$2 + echo "Removing bandwith limits" + /sbin/tc qdisc del dev $DEV root 2> /dev/null > /dev/null + /sbin/tc qdisc del dev $DEV ingress 2> /dev/null > /dev/null + exit + +fi + +if [ "$1" = "--set" ]; then + DEV=$2 + echo "Removing bandwith limit" + /sbin/tc qdisc del dev $DEV ingress #2> /dev/null > /dev/null + + if [ $# -ne 4 ]; then + echo "Error: missing parameters" + usage + exit + fi + + DEV=$2 + echo "Configuring interface $DEV " + + IN=$3 + IN=$((${IN} * 8)) + echo "Download speed ${IN}kbps" + + OUT=$4 + OUT=$((${OUT} * 8)) + echo "Upload speed ${OUT}kbps" + + echo "cleaning limits" + /sbin/tc qdisc del dev $DEV root 2> /dev/null > /dev/null + /sbin/tc qdisc del dev $DEV ingress 2> /dev/null > /dev/null + + echo "configuring tc ingress" + /sbin/tc qdisc add dev $DEV handle ffff: ingress #2> /dev/null > /dev/null + /sbin/tc filter add dev $DEV parent ffff: protocol ip prio 50 u32 match ip src \ + 0.0.0.0/0 police rate ${IN}kbit burst 10k drop flowid :1 #2> /dev/null > /dev/null + + echo "configuring tc egress" + /sbin/tc qdisc add dev $DEV root tbf rate ${OUT}kbit latency 25ms burst 10k #2> /dev/null > /dev/null + exit +fi + +echo "Error: missing parameters" +usage +exit 1 diff --git a/src/ftee/Makefile.in b/src/ftee/Makefile.in new file mode 100644 index 00000000000..6911f0a3cb4 --- /dev/null +++ b/src/ftee/Makefile.in @@ -0,0 +1,24 @@ +all: ftee + +PREFIX=@prefix@ +VERSION=@PACKAGE_VERSION@ +NAME=@PACKAGE_NAME@ + +H_FILE_LIST = $(wildcard *.[h]) +C_FILE_LIST = $(wildcard *.c) +OBJS = $(C_FILE_LIST:.c=.o) +BINOBJS = $(foreach file, $(OBJS), $file) +CFLAGS += -ggdb -O2 -DVERSION='"$(VERSION)"' -DPREFIX='"$(PREFIX)"' -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security +LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread + +%.o : %.c $(H_FILE_LIST) + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +ftee: $(OBJS) + $(CC) $(LDFLAGS) -o $@ $(OBJS) + +clean:; rm -f *.o ftee + +distclean: clean + rm -fr Makefile + diff --git a/src/ftee/ftee.h b/src/ftee/ftee.h new file mode 100644 index 00000000000..a28cc5bb5a1 --- /dev/null +++ b/src/ftee/ftee.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef FTEE_H +#define FTEE_H +#include "../include/common.h" + +#endif \ No newline at end of file diff --git a/src/ftee/main.c b/src/ftee/main.c new file mode 100644 index 00000000000..4dca3cf4803 --- /dev/null +++ b/src/ftee/main.c @@ -0,0 +1,228 @@ +#include "ftee.h" +#include +#include +#include +#include +#define MAXBUF 512 + +static unsigned char buf[MAXBUF]; + +static FILE *out_fp = NULL; +static int out_cnt = 0; +static int out_max = 500 * 1024; + +static void log_close(void) { + if (out_fp) { + fclose(out_fp); + out_fp = NULL; + } +} + +static void log_rotate(const char *fname) { + struct stat s; + int index = strlen(fname); + char *name1 = malloc(index + 2 + 1); + char *name2 = malloc(index + 2 + 1); + if (!name1 || !name2) + errExit("malloc"); + strcpy(name1, fname); + strcpy(name2, fname); + fflush(0); + + // delete filename.5 + sprintf(name1 + index, ".5"); + if (stat(name1, &s) == 0) { + int rv = unlink(name1); + if (rv == -1) + perror("unlink"); + } + + // move files 1 to 4 down one position + sprintf(name2 + index, ".4"); + if (stat(name2, &s) == 0) { + int rv = rename(name2, name1); + if (rv == -1) + perror("rename"); + } + + sprintf(name1 + index, ".3"); + if (stat(name1, &s) == 0) { + int rv = rename(name1, name2); + if (rv == -1) + perror("rename"); + } + + sprintf(name2 + index, ".2"); + if (stat(name2, &s) == 0) { + /* coverity[toctou] */ + int rv = rename(name2, name1); + if (rv == -1) + perror("rename"); + } + + sprintf(name1 + index, ".1"); + if (stat(name1, &s) == 0) { + int rv = rename(name1, name2); + if (rv == -1) + perror("rename"); + } + + // move the first file + if (out_fp) + fclose(out_fp); + + out_fp = NULL; + if (stat(fname, &s) == 0) { + int rv = rename(fname, name1); + if (rv == -1) + perror("rename"); + } + + free(name1); + free(name2); +} + +static void log_write(const unsigned char *str, int len, const char *fname) { + assert(fname); + + if (out_fp == NULL) { + out_fp = fopen(fname, "w"); + if (!out_fp) { + fprintf(stderr, "Error: cannot open log file %s\n", fname); + exit(1); + } + out_cnt = 0; + } + + // rotate files + out_cnt += len; + if (out_cnt >= out_max) { + log_rotate(fname); + + // reopen the first file + if (out_fp) + fclose(out_fp); + out_fp = fopen(fname, "w"); + if (!out_fp) { + fprintf(stderr, "Error: cannot open log file %s\n", fname); + exit(1); + } + out_cnt = len; + } + + fwrite(str, len, 1, out_fp); + fflush(0); +} + + +// return 1 if the file is a directory +static int is_dir(const char *fname) { + assert(fname); + if (*fname == '\0') + return 0; + + // if fname doesn't end in '/', add one + int rv; + struct stat s; + if (fname[strlen(fname) - 1] == '/') + rv = stat(fname, &s); + else { + char *tmp; + if (asprintf(&tmp, "%s/", fname) == -1) { + fprintf(stderr, "Error: cannot allocate memory, %s:%d\n", __FILE__, __LINE__); + exit(1); + } + rv = stat(tmp, &s); + free(tmp); + } + + if (rv == -1) + return 0; + + if (S_ISDIR(s.st_mode)) + return 1; + + return 0; +} + +// return 1 if the file is a link +static int is_link(const char *fname) { + assert(fname); + if (*fname == '\0') + return 0; + + struct stat s; + if (lstat(fname, &s) == 0) { + if (S_ISLNK(s.st_mode)) + return 1; + } + + return 0; +} + + + + + +static void usage(void) { + printf("Usage: ftee filename\n"); +} + +int main(int argc, char **argv) { + if (argc < 2) { + fprintf(stderr, "Error: please provide a filename to store the program output\n"); + usage(); + exit(1); + } + char *fname = argv[1]; + + + // do not accept directories, links, and files with ".." + if (strstr(fname, "..") || is_link(fname) || is_dir(fname)) { + fprintf(stderr, "Error: invalid output file. Links, directories and files with \"..\" are not allowed.\n"); + exit(1); + } + + struct stat s; + if (stat(fname, &s) == 0) { + // check permissions + if (s.st_uid != getuid() || s.st_gid != getgid()) { + fprintf(stderr, "Error: the output file needs to be owned by the current user.\n"); + exit(1); + } + + // check hard links + if (s.st_nlink != 1) { + fprintf(stderr, "Error: no hard links allowed.\n"); + exit(1); + } + } + + // check if we can append to this file + /* coverity[toctou] */ + FILE *fp = fopen(fname, "a"); + if (!fp) { + fprintf(stderr, "Error: cannot open output file %s\n", fname); + exit(1); + } + fclose(fp); + + + // preserve the last log file + log_rotate(fname); + + setvbuf (stdout, NULL, _IONBF, 0); + while(1) { + int n = read(0, buf, sizeof(buf)); + if (n < 0 && errno == EINTR) + continue; + if (n <= 0) + break; + + fwrite(buf, n, 1, stdout); + log_write(buf, n, fname); + } + + log_close(); + return 0; +} diff --git a/src/include/common.h b/src/include/common.h new file mode 100644 index 00000000000..7ce1e929060 --- /dev/null +++ b/src/include/common.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef COMMON_H +#define COMMON_H +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define errExit(msg) do { char msgout[500]; sprintf(msgout, "Error %s:%s(%d)", msg, __FUNCTION__, __LINE__); perror(msgout); exit(1);} while (0) + +// macro to print ip addresses in a printf statement +#define PRINT_IP(A) \ +((int) (((A) >> 24) & 0xFF)), ((int) (((A) >> 16) & 0xFF)), ((int) (((A) >> 8) & 0xFF)), ((int) ( (A) & 0xFF)) + +// macro to print a mac addresses in a printf statement +#define PRINT_MAC(A) \ +((unsigned) (*(A)) & 0xff), ((unsigned) (*((A) + 1) & 0xff)), ((unsigned) (*((A) + 2) & 0xff)), \ +((unsigned) (*((A) + 3)) & 0xff), ((unsigned) (*((A) + 4) & 0xff)), ((unsigned) (*((A) + 5)) & 0xff) + +// the number of bits in a network mask +static inline uint8_t mask2bits(uint32_t mask) { + uint32_t tmp = 0x80000000; + int i; + uint8_t rv = 0; + + for (i = 0; i < 32; i++, tmp >>= 1) { + if (tmp & mask) + rv++; + else + break; + } + return rv; +} + +// read an IPv4 address and convert it to uint32_t +static inline int atoip(const char *str, uint32_t *ip) { + unsigned a, b, c, d; + + if (sscanf(str, "%u.%u.%u.%u", &a, &b, &c, &d) != 4 || a > 255 || b > 255 || c > 255 || d > 255) + return 1; + + *ip = a * 0x1000000 + b * 0x10000 + c * 0x100 + d; + return 0; +} + +// verify an ip address is in the network range given by ifip and mask +static inline char *in_netrange(uint32_t ip, uint32_t ifip, uint32_t ifmask) { + if ((ip & ifmask) != (ifip & ifmask)) + return "Error: the IP address is not in the interface range\n"; + else if ((ip & ifmask) == ip) + return "Error: the IP address is a network address\n"; + else if ((ip | ~ifmask) == ip) + return "Error: the IP address is a network address\n"; + return NULL; +} + +// read a mac address +static inline int atomac(char *str, unsigned char macAddr[6]) { + unsigned mac[6]; + + if (sscanf(str, "%2x:%2x:%2x:%2x:%2x:%2x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) != 6) + return 1; + + int i; + for (i = 0; i < 6; i++) { + if (mac[i] > 0xff) + return 1; + + macAddr[i] = (unsigned char) mac[i]; + } + + return 0; +} + +// check a mac address is configured +static inline int mac_not_zero(const unsigned char mac[6]) { + int i; + for (i = 0; i < 6; i++) { + if (mac[i] != 0) + return 1; + } + + return 0; +} + +int join_namespace(pid_t pid, char *type); +int name2pid(const char *name, pid_t *pid); +char *pid_proc_comm(const pid_t pid); +char *pid_proc_cmdline(const pid_t pid); +#endif diff --git a/src/include/libnetlink.h b/src/include/libnetlink.h new file mode 100644 index 00000000000..e9cd6b186f9 --- /dev/null +++ b/src/include/libnetlink.h @@ -0,0 +1,163 @@ +/* file extracted from iproute2 software package + * + * Original source code: + * + * Information: + * http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2 + * + * Download: + * http://www.kernel.org/pub/linux/utils/net/iproute2/ + * + * Repository: + * git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git + * + * License: GPL v2 + */ + + +#ifndef __LIBNETLINK_H__ +#define __LIBNETLINK_H__ 1 + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct rtnl_handle +{ + int fd; + struct sockaddr_nl local; + struct sockaddr_nl peer; + __u32 seq; + __u32 dump; +}; + +extern int rcvbuf; + +extern int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions); +extern int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, int protocol); +extern void rtnl_close(struct rtnl_handle *rth); +extern int rtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type); +extern int rtnl_wilddump_req_filter(struct rtnl_handle *rth, int fam, int type, + __u32 filt_mask); +extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len); + +typedef int (*rtnl_filter_t)(const struct sockaddr_nl *, + struct nlmsghdr *n, void *); + +struct rtnl_dump_filter_arg +{ + rtnl_filter_t filter; + void *arg1; +}; + +extern int rtnl_dump_filter_l(struct rtnl_handle *rth, + const struct rtnl_dump_filter_arg *arg); +extern int rtnl_dump_filter(struct rtnl_handle *rth, rtnl_filter_t filter, + void *arg); +extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, + unsigned groups, struct nlmsghdr *answer); +extern int rtnl_send(struct rtnl_handle *rth, const void *buf, int); +extern int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int); + +extern int addattr(struct nlmsghdr *n, int maxlen, int type); +extern int addattr8(struct nlmsghdr *n, int maxlen, int type, __u8 data); +extern int addattr16(struct nlmsghdr *n, int maxlen, int type, __u16 data); +extern int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data); +extern int addattr64(struct nlmsghdr *n, int maxlen, int type, __u64 data); +extern int addattrstrz(struct nlmsghdr *n, int maxlen, int type, const char *data); + +extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, int alen); +extern int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len); +extern struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type); +extern int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest); +extern struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type, const void *data, int len); +extern int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *nest); +extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data); +extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, const void *data, int alen); + +extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len); +extern int parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta, + int len, unsigned short flags); +extern int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len); +extern int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta, int len); + +#define parse_rtattr_nested(tb, max, rta) \ + (parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta))) + +#define parse_rtattr_nested_compat(tb, max, rta, data, len) \ + ({ data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \ + __parse_rtattr_nested_compat(tb, max, rta, len); }) + +static inline __u8 rta_getattr_u8(const struct rtattr *rta) +{ + return *(__u8 *)RTA_DATA(rta); +} +static inline __u16 rta_getattr_u16(const struct rtattr *rta) +{ + return *(__u16 *)RTA_DATA(rta); +} +static inline __u32 rta_getattr_u32(const struct rtattr *rta) +{ + return *(__u32 *)RTA_DATA(rta); +} +static inline __u64 rta_getattr_u64(const struct rtattr *rta) +{ + __u64 tmp; + memcpy(&tmp, RTA_DATA(rta), sizeof(__u64)); + return tmp; +} +static inline const char *rta_getattr_str(const struct rtattr *rta) +{ + return (const char *)RTA_DATA(rta); +} + +extern int rtnl_listen(struct rtnl_handle *, rtnl_filter_t handler, + void *jarg); +extern int rtnl_from_file(FILE *, rtnl_filter_t handler, + void *jarg); + +#define NLMSG_TAIL(nmsg) \ + ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) + +#ifndef IFA_RTA +#define IFA_RTA(r) \ + ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)))) +#endif +#ifndef IFA_PAYLOAD +#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg)) +#endif + +#ifndef IFLA_RTA +#define IFLA_RTA(r) \ + ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) +#endif +#ifndef IFLA_PAYLOAD +#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) +#endif + +#ifndef NDA_RTA +#define NDA_RTA(r) \ + ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) +#endif +#ifndef NDA_PAYLOAD +#define NDA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndmsg)) +#endif + +#ifndef NDTA_RTA +#define NDTA_RTA(r) \ + ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndtmsg)))) +#endif +#ifndef NDTA_PAYLOAD +#define NDTA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndtmsg)) +#endif + +#endif /* __LIBNETLINK_H__ */ + diff --git a/src/include/pid.h b/src/include/pid.h new file mode 100644 index 00000000000..aaadaa542f6 --- /dev/null +++ b/src/include/pid.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef PID_H +#define PID_H +extern int max_pids; + + +#define _GNU_SOURCE +#include +#include +#include +typedef struct { + short level; // -1 not a firejail process, 0 not investigated yet, 1 firejail process, > 1 firejail child + unsigned char zombie; + pid_t parent; + uid_t uid; + char *user; + char *cmd; + unsigned utime; + unsigned stime; + unsigned long long rx; // network rx, bytes + unsigned long long tx; // networking tx, bytes + unsigned rx_delta; + unsigned tx_delta; +} Process; +//extern Process pids[max_pids]; +extern Process *pids; + +// pid functions +void pid_getmem(unsigned pid, unsigned *rss, unsigned *shared); +void pid_get_cpu_time(unsigned pid, unsigned *utime, unsigned *stime); +unsigned long long pid_get_start_time(unsigned pid); +uid_t pid_get_uid(pid_t pid); +char *pid_get_user_name(uid_t uid); +// print functions +void pid_print_tree(unsigned index, unsigned parent, int nowrap); +void pid_print_list(unsigned index, int nowrap); +void pid_store_cpu(unsigned index, unsigned parent, unsigned *utime, unsigned *stime); +void pid_read(pid_t mon_pid); + +#endif diff --git a/src/lib/Makefile.in b/src/lib/Makefile.in new file mode 100644 index 00000000000..6e6be1910ec --- /dev/null +++ b/src/lib/Makefile.in @@ -0,0 +1,20 @@ +PREFIX=@prefix@ +VERSION=@PACKAGE_VERSION@ +NAME=@PACKAGE_NAME@ + +H_FILE_LIST = $(wildcard *.[h]) +C_FILE_LIST = $(wildcard *.c) +OBJS = $(C_FILE_LIST:.c=.o) +BINOBJS = $(foreach file, $(OBJS), $file) +CFLAGS += -ggdb -O2 -DVERSION='"$(VERSION)"' -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIC -Wformat -Wformat-security +LDFLAGS:=-pic -Wl,-z,relro -Wl,-z,now + +all: $(OBJS) + +%.o : %.c $(H_FILE_LIST) + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +clean:; rm -f $(OBJS) + +distclean: clean + rm -fr Makefile diff --git a/src/lib/common.c b/src/lib/common.c new file mode 100644 index 00000000000..6d928abbbb1 --- /dev/null +++ b/src/lib/common.c @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/common.h" + +int join_namespace(pid_t pid, char *type) { + char *path; + if (asprintf(&path, "/proc/%u/ns/%s", pid, type) == -1) + errExit("asprintf"); + + int fd = open(path, O_RDONLY); + if (fd < 0) { + free(path); + fprintf(stderr, "Error: cannot open /proc/%u/ns/%s.\n", pid, type); + return -1; + } + + if (syscall(__NR_setns, fd, 0) < 0) { + free(path); + fprintf(stderr, "Error: cannot join namespace %s.\n", type); + close(fd); + return -1; + } + + close(fd); + free(path); + return 0; +} + +// return 1 if error +int name2pid(const char *name, pid_t *pid) { + pid_t parent = getpid(); + + DIR *dir; + if (!(dir = opendir("/proc"))) { + // sleep 2 seconds and try again + sleep(2); + if (!(dir = opendir("/proc"))) { + fprintf(stderr, "Error: cannot open /proc directory\n"); + exit(1); + } + } + + struct dirent *entry; + char *end; + while ((entry = readdir(dir))) { + pid_t newpid = strtol(entry->d_name, &end, 10); + if (end == entry->d_name || *end) + continue; + if (newpid == parent) + continue; + + // check if this is a firejail executable + char *comm = pid_proc_comm(newpid); + if (comm) { + // remove \n + char *ptr = strchr(comm, '\n'); + if (ptr) + *ptr = '\0'; + if (strcmp(comm, "firejail")) { + free(comm); + continue; + } + free(comm); + } + + char *cmd = pid_proc_cmdline(newpid); + if (cmd) { + // mark the end of the name + char *ptr = strstr(cmd, "--name="); + char *start = ptr; + if (!ptr) { + free(cmd); + continue; + } + while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0') + ptr++; + *ptr = '\0'; + int rv = strcmp(start + 7, name); + if (rv == 0) { + free(cmd); + *pid = newpid; + closedir(dir); + return 0; + } + free(cmd); + } + } + closedir(dir); + return 1; +} + +#define BUFLEN 4096 +char *pid_proc_comm(const pid_t pid) { + // open /proc/pid/cmdline file + char *fname; + int fd; + if (asprintf(&fname, "/proc/%d//comm", pid) == -1) + return NULL; + if ((fd = open(fname, O_RDONLY)) < 0) { + free(fname); + return NULL; + } + free(fname); + + // read file + unsigned char buffer[BUFLEN]; + ssize_t len; + if ((len = read(fd, buffer, sizeof(buffer) - 1)) <= 0) { + close(fd); + return NULL; + } + buffer[len] = '\0'; + close(fd); + + // return a malloc copy of the command line + char *rv = strdup((char *) buffer); + if (strlen(rv) == 0) { + free(rv); + return NULL; + } + return rv; +} + +char *pid_proc_cmdline(const pid_t pid) { + // open /proc/pid/cmdline file + char *fname; + int fd; + if (asprintf(&fname, "/proc/%d/cmdline", pid) == -1) + return NULL; + if ((fd = open(fname, O_RDONLY)) < 0) { + free(fname); + return NULL; + } + free(fname); + + // read file + unsigned char buffer[BUFLEN]; + ssize_t len; + if ((len = read(fd, buffer, sizeof(buffer) - 1)) <= 0) { + close(fd); + return NULL; + } + buffer[len] = '\0'; + close(fd); + + // clean data + int i; + for (i = 0; i < len; i++) { + if (buffer[i] == '\0') + buffer[i] = ' '; + if (buffer[i] >= 0x80) // execv in progress!!! + return NULL; + } + + // return a malloc copy of the command line + char *rv = strdup((char *) buffer); + if (strlen(rv) == 0) { + free(rv); + return NULL; + } + return rv; +} diff --git a/src/lib/libnetlink.c b/src/lib/libnetlink.c new file mode 100644 index 00000000000..264632a01b7 --- /dev/null +++ b/src/lib/libnetlink.c @@ -0,0 +1,803 @@ +/* file extracted from iproute2 software package + * + * Original source code: + * + * Information: + * http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2 + * + * Download: + * http://www.kernel.org/pub/linux/utils/net/iproute2/ + * + * Repository: + * git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git + * + * License: GPL v2 + * + * Original copyright header + * + * libnetlink.c RTnetlink service routines. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Alexey Kuznetsov, + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../include/libnetlink.h" + +int rcvbuf = 1024 * 1024; + +void rtnl_close(struct rtnl_handle *rth) +{ + if (rth->fd >= 0) { + close(rth->fd); + rth->fd = -1; + } +} + +int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions, + int protocol) +{ + socklen_t addr_len; + int sndbuf = 32768; + + memset(rth, 0, sizeof(*rth)); + + rth->fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol); + if (rth->fd < 0) { + perror("Cannot open netlink socket"); + return -1; + } + + if (setsockopt(rth->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) { + perror("SO_SNDBUF"); + return -1; + } + + if (setsockopt(rth->fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf)) < 0) { + perror("SO_RCVBUF"); + return -1; + } + + memset(&rth->local, 0, sizeof(rth->local)); + rth->local.nl_family = AF_NETLINK; + rth->local.nl_groups = subscriptions; + + if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) { + perror("Cannot bind netlink socket"); + return -1; + } + addr_len = sizeof(rth->local); + if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) { + perror("Cannot getsockname"); + return -1; + } + if (addr_len != sizeof(rth->local)) { + fprintf(stderr, "Wrong address length %d\n", addr_len); + return -1; + } + if (rth->local.nl_family != AF_NETLINK) { + fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family); + return -1; + } + rth->seq = time(NULL); + return 0; +} + +int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions) +{ + return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE); +} + +int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) +{ + return rtnl_wilddump_req_filter(rth, family, type, RTEXT_FILTER_VF); +} + +int rtnl_wilddump_req_filter(struct rtnl_handle *rth, int family, int type, + __u32 filt_mask) +{ + struct { + struct nlmsghdr nlh; + struct ifinfomsg ifm; + /* attribute has to be NLMSG aligned */ + struct rtattr ext_req __attribute__ ((aligned(NLMSG_ALIGNTO))); + __u32 ext_filter_mask; + } req; + + memset(&req, 0, sizeof(req)); + req.nlh.nlmsg_len = sizeof(req); + req.nlh.nlmsg_type = type; + req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST; + req.nlh.nlmsg_pid = 0; + req.nlh.nlmsg_seq = rth->dump = ++rth->seq; + req.ifm.ifi_family = family; + + req.ext_req.rta_type = IFLA_EXT_MASK; + req.ext_req.rta_len = RTA_LENGTH(sizeof(__u32)); + req.ext_filter_mask = filt_mask; + + return send(rth->fd, (void*)&req, sizeof(req), 0); +} + +int rtnl_send(struct rtnl_handle *rth, const void *buf, int len) +{ + return send(rth->fd, buf, len, 0); +} + +int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len) +{ + struct nlmsghdr *h; + int status; + char resp[1024]; + + status = send(rth->fd, buf, len, 0); + if (status < 0) + return status; + + /* Check for immediate errors */ + status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK); + if (status < 0) { + if (errno == EAGAIN) + return 0; + return -1; + } + + for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status); + h = NLMSG_NEXT(h, status)) { + if (h->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); + if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) + fprintf(stderr, "ERROR truncated\n"); + else + errno = -err->error; + return -1; + } + } + + return 0; +} + +int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) +{ + struct nlmsghdr nlh; + struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK }; + struct iovec iov[2] = { + { .iov_base = &nlh, .iov_len = sizeof(nlh) }, + { .iov_base = req, .iov_len = len } + }; + struct msghdr msg = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = iov, + .msg_iovlen = 2, + }; + + nlh.nlmsg_len = NLMSG_LENGTH(len); + nlh.nlmsg_type = type; + nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST; + nlh.nlmsg_pid = 0; + nlh.nlmsg_seq = rth->dump = ++rth->seq; + + return sendmsg(rth->fd, &msg, 0); +} + +int rtnl_dump_filter_l(struct rtnl_handle *rth, + const struct rtnl_dump_filter_arg *arg) +{ + struct sockaddr_nl nladdr; + struct iovec iov; + struct msghdr msg = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + char buf[16384]; + int dump_intr = 0; + + iov.iov_base = buf; + while (1) { + int status; + const struct rtnl_dump_filter_arg *a; + int found_done = 0; + int msglen = 0; + + iov.iov_len = sizeof(buf); + status = recvmsg(rth->fd, &msg, 0); + + if (status < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + fprintf(stderr, "netlink receive error %s (%d)\n", + strerror(errno), errno); + return -1; + } + + if (status == 0) { + fprintf(stderr, "EOF on netlink\n"); + return -1; + } + + for (a = arg; a->filter; a++) { + struct nlmsghdr *h = (struct nlmsghdr*)buf; + msglen = status; + + while (NLMSG_OK(h, msglen)) { + int err; + + if (nladdr.nl_pid != 0 || + h->nlmsg_pid != rth->local.nl_pid || + h->nlmsg_seq != rth->dump) + goto skip_it; + + if (h->nlmsg_flags & NLM_F_DUMP_INTR) + dump_intr = 1; + + if (h->nlmsg_type == NLMSG_DONE) { + found_done = 1; + break; /* process next filter */ + } + if (h->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); + if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { + fprintf(stderr, + "ERROR truncated\n"); + } else { + errno = -err->error; + perror("RTNETLINK answers"); + } + return -1; + } + err = a->filter(&nladdr, h, a->arg1); + if (err < 0) + return err; + +skip_it: + h = NLMSG_NEXT(h, msglen); + } + } + + if (found_done) { + if (dump_intr) + fprintf(stderr, + "Dump was interrupted and may be inconsistent.\n"); + return 0; + } + + if (msg.msg_flags & MSG_TRUNC) { + fprintf(stderr, "Message truncated\n"); + continue; + } + if (msglen) { + fprintf(stderr, "!!!Remnant of size %d\n", msglen); + exit(1); + } + } +} + +int rtnl_dump_filter(struct rtnl_handle *rth, + rtnl_filter_t filter, + void *arg1) +{ + const struct rtnl_dump_filter_arg a[2] = { + { .filter = filter, .arg1 = arg1, }, + { .filter = NULL, .arg1 = NULL, }, + }; + + return rtnl_dump_filter_l(rth, a); +} + +int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, + unsigned groups, struct nlmsghdr *answer) +{ + int status; + unsigned seq; + struct nlmsghdr *h; + struct sockaddr_nl nladdr; + struct iovec iov = { + .iov_base = (void*) n, + .iov_len = n->nlmsg_len + }; + struct msghdr msg = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + char buf[16384]; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pid = peer; + nladdr.nl_groups = groups; + + n->nlmsg_seq = seq = ++rtnl->seq; + + if (answer == NULL) + n->nlmsg_flags |= NLM_F_ACK; + + status = sendmsg(rtnl->fd, &msg, 0); + + if (status < 0) { + perror("Cannot talk to rtnetlink"); + return -1; + } + + memset(buf,0,sizeof(buf)); + + iov.iov_base = buf; + + while (1) { + iov.iov_len = sizeof(buf); + status = recvmsg(rtnl->fd, &msg, 0); + + if (status < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + fprintf(stderr, "netlink receive error %s (%d)\n", + strerror(errno), errno); + return -1; + } + if (status == 0) { + fprintf(stderr, "EOF on netlink\n"); + return -1; + } + if (msg.msg_namelen != sizeof(nladdr)) { + fprintf(stderr, "sender address length == %d\n", msg.msg_namelen); + exit(1); + } + for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { + int len = h->nlmsg_len; + int l = len - sizeof(*h); + + if (l < 0 || len>status) { + if (msg.msg_flags & MSG_TRUNC) { + fprintf(stderr, "Truncated message\n"); + return -1; + } + fprintf(stderr, "!!!malformed message: len=%d\n", len); + exit(1); + } + + if (nladdr.nl_pid != peer || + h->nlmsg_pid != rtnl->local.nl_pid || + h->nlmsg_seq != seq) { + /* Don't forget to skip that message. */ + status -= NLMSG_ALIGN(len); + h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); + continue; + } + + if (h->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); + if (l < sizeof(struct nlmsgerr)) { + fprintf(stderr, "ERROR truncated\n"); + } else { + if (!err->error) { + if (answer) + memcpy(answer, h, h->nlmsg_len); + return 0; + } + + fprintf(stderr, "RTNETLINK answers: %s\n", strerror(-err->error)); + errno = -err->error; + } + return -1; + } + if (answer) { + memcpy(answer, h, h->nlmsg_len); + return 0; + } + + fprintf(stderr, "Unexpected reply!!!\n"); + + status -= NLMSG_ALIGN(len); + h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); + } + if (msg.msg_flags & MSG_TRUNC) { + fprintf(stderr, "Message truncated\n"); + continue; + } + if (status) { + fprintf(stderr, "!!!Remnant of size %d\n", status); + exit(1); + } + } +} + +int rtnl_listen(struct rtnl_handle *rtnl, + rtnl_filter_t handler, + void *jarg) +{ + int status; + struct nlmsghdr *h; + struct sockaddr_nl nladdr; + struct iovec iov; + struct msghdr msg = { + .msg_name = &nladdr, + .msg_namelen = sizeof(nladdr), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + char buf[8192]; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pid = 0; + nladdr.nl_groups = 0; + + iov.iov_base = buf; + while (1) { + iov.iov_len = sizeof(buf); + status = recvmsg(rtnl->fd, &msg, 0); + + if (status < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + fprintf(stderr, "netlink receive error %s (%d)\n", + strerror(errno), errno); + if (errno == ENOBUFS) + continue; + return -1; + } + if (status == 0) { + fprintf(stderr, "EOF on netlink\n"); + return -1; + } + if (msg.msg_namelen != sizeof(nladdr)) { + fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen); + exit(1); + } + for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { + int err; + int len = h->nlmsg_len; + int l = len - sizeof(*h); + + if (l<0 || len>status) { + if (msg.msg_flags & MSG_TRUNC) { + fprintf(stderr, "Truncated message\n"); + return -1; + } + fprintf(stderr, "!!!malformed message: len=%d\n", len); + exit(1); + } + + err = handler(&nladdr, h, jarg); + if (err < 0) + return err; + + status -= NLMSG_ALIGN(len); + h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); + } + if (msg.msg_flags & MSG_TRUNC) { + fprintf(stderr, "Message truncated\n"); + continue; + } + if (status) { + fprintf(stderr, "!!!Remnant of size %d\n", status); + exit(1); + } + } +} + +int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler, + void *jarg) +{ + int status; + struct sockaddr_nl nladdr; + char buf[8192]; + struct nlmsghdr *h = (void*)buf; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pid = 0; + nladdr.nl_groups = 0; + + while (1) { + int err, len; + int l; + + status = fread(&buf, 1, sizeof(*h), rtnl); + + if (status < 0) { + if (errno == EINTR) + continue; + perror("rtnl_from_file: fread"); + return -1; + } + if (status == 0) + return 0; + + len = h->nlmsg_len; + l = len - sizeof(*h); + + if (l<0 || len>sizeof(buf)) { + fprintf(stderr, "!!!malformed message: len=%d @%lu\n", + len, ftell(rtnl)); + return -1; + } + + status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl); + + if (status < 0) { + perror("rtnl_from_file: fread"); + return -1; + } + if (status < l) { + fprintf(stderr, "rtnl-from_file: truncated message\n"); + return -1; + } + + err = handler(&nladdr, h, jarg); + if (err < 0) + return err; + } +} + +int addattr(struct nlmsghdr *n, int maxlen, int type) +{ + return addattr_l(n, maxlen, type, NULL, 0); +} + +int addattr8(struct nlmsghdr *n, int maxlen, int type, __u8 data) +{ + return addattr_l(n, maxlen, type, &data, sizeof(__u8)); +} + +int addattr16(struct nlmsghdr *n, int maxlen, int type, __u16 data) +{ + return addattr_l(n, maxlen, type, &data, sizeof(__u16)); +} + +int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data) +{ + return addattr_l(n, maxlen, type, &data, sizeof(__u32)); +} + +int addattr64(struct nlmsghdr *n, int maxlen, int type, __u64 data) +{ + return addattr_l(n, maxlen, type, &data, sizeof(__u64)); +} + +int addattrstrz(struct nlmsghdr *n, int maxlen, int type, const char *str) +{ + return addattr_l(n, maxlen, type, str, strlen(str)+1); +} + + + +int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, + int alen) +{ + +#if 0 +printf("%d: %s\n", __LINE__, __FUNCTION__); +printf("\ttype %d - ", type); +if (type == IFLA_LINK) { + printf("IFLA_LINK\n"); + int i; + printf("\tdata - "); + for (i = 0; i < alen; i++) + printf("%02x, ", *((unsigned char *)data + i)); + printf("\n"); +} +else if (type == IFLA_IFNAME) { + printf("IFLA_IFNAME\n"); + printf("\tdata - #%s#\n", data); +} +else if (type == IFLA_LINKINFO) printf("IFLA_LINKINFO\n"); +else if (type == IFLA_ADDRESS) { + printf("IFLA_ADDRESS or IFLA_INFO_KIND\n"); + int i; + printf("\tdata - "); + for (i = 0; i < alen; i++) + printf("%02x, ", *((unsigned char *)data + i)); + printf("\n"); +} +else if (type == IFLA_BROADCAST) printf("IFLA_BROADCAST or IFLA_INFO_DATA\n"); + +printf("\tdata length: %d\n", alen); +#endif + + int len = RTA_LENGTH(alen); + struct rtattr *rta; + + if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { + fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen); + return -1; + } + rta = NLMSG_TAIL(n); + rta->rta_type = type; + rta->rta_len = len; + memcpy(RTA_DATA(rta), data, alen); + n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); + return 0; +} + +#if 0 +int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, + int alen) +{ +printf("%s: adding type %d, length %d ", __FUNCTION__, type, alen); +if (type == IFLA_INFO_KIND) { +if (alen) + printf("(IFLA_INFO_KIND %s)\n", (char *)data); +else +printf("(VETH_INFO_PEER)\n"); +} +else if (type == IFLA_IFNAME) { +printf("(IFLA_IFNAME %s)\n", (char *) data); +} +else if (type == IFLA_NET_NS_PID) { +printf("(IFLA_NET_NS_PID %u)\n", *((unsigned *) data)); +} +else if (type == IFLA_LINKINFO) +printf("(IFLA_LINKINFO)\n"); +else if (type == IFLA_INFO_DATA) +printf("(IFLA_INFO_DATA)\n"); +else + printf("\n"); + + int len = RTA_LENGTH(alen); + struct rtattr *rta; + + if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) { + fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen); + return -1; + } + rta = NLMSG_TAIL(n); + rta->rta_type = type; + rta->rta_len = len; + memcpy(RTA_DATA(rta), data, alen); + n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); + return 0; +} +#endif + +int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len) +{ + if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) { + fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen); + return -1; + } + + memcpy(NLMSG_TAIL(n), data, len); + memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len); + n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len); + return 0; +} + +struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type) +{ + struct rtattr *nest = NLMSG_TAIL(n); + + addattr_l(n, maxlen, type, NULL, 0); + return nest; +} + +int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest) +{ + nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest; + return n->nlmsg_len; +} + +struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type, + const void *data, int len) +{ + struct rtattr *start = NLMSG_TAIL(n); + + addattr_l(n, maxlen, type, data, len); + addattr_nest(n, maxlen, type); + return start; +} + +int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start) +{ + struct rtattr *nest = (void *)start + NLMSG_ALIGN(start->rta_len); + + start->rta_len = (void *)NLMSG_TAIL(n) - (void *)start; + addattr_nest_end(n, nest); + return n->nlmsg_len; +} + +int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data) +{ + int len = RTA_LENGTH(4); + struct rtattr *subrta; + + if (RTA_ALIGN(rta->rta_len) + len > maxlen) { + fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen); + return -1; + } + subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); + subrta->rta_type = type; + subrta->rta_len = len; + memcpy(RTA_DATA(subrta), &data, 4); + rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len; + return 0; +} + +int rta_addattr_l(struct rtattr *rta, int maxlen, int type, + const void *data, int alen) +{ + struct rtattr *subrta; + int len = RTA_LENGTH(alen); + + if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) { + fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen); + return -1; + } + subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); + subrta->rta_type = type; + subrta->rta_len = len; + memcpy(RTA_DATA(subrta), data, alen); + rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len); + return 0; +} + +int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) +{ + return parse_rtattr_flags(tb, max, rta, len, 0); +} + +int parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta, + int len, unsigned short flags) +{ + unsigned short type; + + memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); + while (RTA_OK(rta, len)) { + type = rta->rta_type & ~flags; + if ((type <= max) && (!tb[type])) + tb[type] = rta; + rta = RTA_NEXT(rta,len); + } + if (len) + fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); + return 0; +} + +int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len) +{ + int i = 0; + + memset(tb, 0, sizeof(struct rtattr *) * max); + while (RTA_OK(rta, len)) { + if (rta->rta_type <= max && i < max) + tb[i++] = rta; + rta = RTA_NEXT(rta,len); + } + if (len) + fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); + return i; +} + +int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta, + int len) +{ + if (RTA_PAYLOAD(rta) < len) + return -1; + if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) { + rta = RTA_DATA(rta) + RTA_ALIGN(len); + return parse_rtattr_nested(tb, max, rta); + } + memset(tb, 0, sizeof(struct rtattr *) * (max + 1)); + return 0; +} diff --git a/src/lib/pid.c b/src/lib/pid.c new file mode 100644 index 00000000000..a0261ead273 --- /dev/null +++ b/src/lib/pid.c @@ -0,0 +1,392 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "../include/common.h" +#include "../include/pid.h" +#include +#include +#include +#include +#include + +#define PIDS_BUFLEN 4096 +//Process pids[max_pids]; +Process *pids = NULL; +int max_pids=32769; +#define PIDS_BUFLEN 4096 + +// get the memory associated with this pid +void pid_getmem(unsigned pid, unsigned *rss, unsigned *shared) { + // open stat file + char *file; + if (asprintf(&file, "/proc/%u/statm", pid) == -1) { + perror("asprintf"); + exit(1); + } + FILE *fp = fopen(file, "r"); + if (!fp) { + free(file); + return; + } + free(file); + + unsigned a, b, c; + if (3 != fscanf(fp, "%u %u %u", &a, &b, &c)) { + fclose(fp); + return; + } + *rss += b; + *shared += c; + fclose(fp); +} + + +void pid_get_cpu_time(unsigned pid, unsigned *utime, unsigned *stime) { + // open stat file + char *file; + if (asprintf(&file, "/proc/%u/stat", pid) == -1) { + perror("asprintf"); + exit(1); + } + FILE *fp = fopen(file, "r"); + if (!fp) { + free(file); + return; + } + free(file); + + char line[PIDS_BUFLEN]; + if (fgets(line, PIDS_BUFLEN - 1, fp)) { + char *ptr = line; + // jump 13 fields + int i; + for (i = 0; i < 13; i++) { + while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0') + ptr++; + if (*ptr == '\0') + goto myexit; + ptr++; + } + if (2 != sscanf(ptr, "%u %u", utime, stime)) + goto myexit; + } + +myexit: + fclose(fp); +} + +unsigned long long pid_get_start_time(unsigned pid) { + // open stat file + char *file; + if (asprintf(&file, "/proc/%u/stat", pid) == -1) { + perror("asprintf"); + exit(1); + } + FILE *fp = fopen(file, "r"); + if (!fp) { + free(file); + return 0; + } + free(file); + + char line[PIDS_BUFLEN]; + unsigned long long retval = 0; + if (fgets(line, PIDS_BUFLEN - 1, fp)) { + char *ptr = line; + // jump 21 fields + int i; + for (i = 0; i < 21; i++) { + while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0') + ptr++; + if (*ptr == '\0') + goto myexit; + ptr++; + } + if (1 != sscanf(ptr, "%llu", &retval)) + goto myexit; + } + +myexit: + fclose(fp); + return retval; +} + +char *pid_get_user_name(uid_t uid) { + struct passwd *pw = getpwuid(uid); + if (pw) + return strdup(pw->pw_name); + return NULL; +} + +uid_t pid_get_uid(pid_t pid) { + uid_t rv = 0; + + // open stat file + char *file; + if (asprintf(&file, "/proc/%u/status", pid) == -1) { + perror("asprintf"); + exit(1); + } + FILE *fp = fopen(file, "r"); + if (!fp) { + free(file); + return 0; + } + + // look for firejail executable name + char buf[PIDS_BUFLEN]; + while (fgets(buf, PIDS_BUFLEN - 1, fp)) { + if (strncmp(buf, "Uid:", 4) == 0) { + char *ptr = buf + 5; + while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) { + ptr++; + } + if (*ptr == '\0') + goto doexit; + + rv = atoi(ptr); + break; // break regardless! + } + } +doexit: + fclose(fp); + free(file); + return rv; +} + +static void print_elem(unsigned index, int nowrap) { + // get terminal size + struct winsize sz; + int col = 0; + if (isatty(STDIN_FILENO)) { + if (!ioctl(0, TIOCGWINSZ, &sz)) + col = sz.ws_col; + } + + // indent + char indent[(pids[index].level - 1) * 2 + 1]; + memset(indent, ' ', sizeof(indent)); + indent[(pids[index].level - 1) * 2] = '\0'; + + // get data + uid_t uid = pids[index].uid; + char *cmd = pid_proc_cmdline(index); + char *user = pid_get_user_name(uid); + char *allocated = user; + if (user ==NULL) + user = ""; + if (cmd) { + if (col < 4 || nowrap) + printf("%s%u:%s:%s\n", indent, index, user, cmd); + else { + char *out; + if (asprintf(&out, "%s%u:%s:%s\n", indent, index, user, cmd) == -1) + errExit("asprintf"); + int len = strlen(out); + if (len > col) { + out[col] = '\0'; + out[col - 1] = '\n'; + } + printf("%s", out); + free(out); + } + + free(cmd); + } + else { + if (pids[index].zombie) + printf("%s%u: (zombie)\n", indent, index); + else + printf("%s%u:\n", indent, index); + } + if (allocated) + free(allocated); +} + +// recursivity!!! +void pid_print_tree(unsigned index, unsigned parent, int nowrap) { + print_elem(index, nowrap); + + int i; + for (i = index + 1; i < max_pids; i++) { + if (pids[i].parent == index) + pid_print_tree(i, index, nowrap); + } + + for (i = 0; i < index; i++) { + if (pids[i].parent == index) + pid_print_tree(i, index, nowrap); + } +} + +void pid_print_list(unsigned index, int nowrap) { + print_elem(index, nowrap); +} + +// recursivity!!! +void pid_store_cpu(unsigned index, unsigned parent, unsigned *utime, unsigned *stime) { + if (pids[index].level == 1) { + *utime = 0; + *stime = 0; + } + + unsigned utmp = 0; + unsigned stmp = 0; + pid_get_cpu_time(index, &utmp, &stmp); + *utime += utmp; + *stime += stmp; + + int i; + for (i = index + 1; i < max_pids; i++) { + if (pids[i].parent == index) + pid_store_cpu(i, index, utime, stime); + } + + if (pids[index].level == 1) { + pids[index].utime = *utime; + pids[index].stime = *stime; + } +} + +// mon_pid: pid of sandbox to be monitored, 0 if all sandboxes are included +void pid_read(pid_t mon_pid) { + if (pids == NULL) { + FILE *fp = fopen("/proc/sys/kernel/pid_max", "r"); + if (fp) { + int val; + if (fscanf(fp, "%d", &val) == 1) { + if (val >= max_pids) + max_pids = val + 1; + } + fclose(fp); + } + pids = malloc(sizeof(Process) * max_pids); + if (pids == NULL) + errExit("malloc"); + } + memset(pids, 0, sizeof(Process) * max_pids); + pid_t mypid = getpid(); + + DIR *dir; + if (!(dir = opendir("/proc"))) { + // sleep 2 seconds and try again + sleep(2); + if (!(dir = opendir("/proc"))) { + fprintf(stderr, "Error: cannot open /proc directory\n"); + exit(1); + } + } + + pid_t child = -1; + struct dirent *entry; + char *end; + while (child < 0 && (entry = readdir(dir))) { + pid_t pid = strtol(entry->d_name, &end, 10); + pid %= max_pids; + if (end == entry->d_name || *end) + continue; + if (pid == mypid) + continue; + + // open stat file + char *file; + if (asprintf(&file, "/proc/%u/status", pid) == -1) { + perror("asprintf"); + exit(1); + } + FILE *fp = fopen(file, "r"); + if (!fp) { + free(file); + continue; + } + + // look for firejail executable name + char buf[PIDS_BUFLEN]; + while (fgets(buf, PIDS_BUFLEN - 1, fp)) { + if (strncmp(buf, "Name:", 5) == 0) { + char *ptr = buf + 5; + while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) { + ptr++; + } + if (*ptr == '\0') { + fprintf(stderr, "Error: cannot read /proc file\n"); + exit(1); + } + + if (mon_pid == 0 && strncmp(ptr, "firejail", 8) == 0) { + pids[pid].level = 1; + } + else if (mon_pid == pid && strncmp(ptr, "firejail", 8) == 0) { + pids[pid].level = 1; + } +// else if (mon_pid == 0 && strncmp(ptr, "lxc-execute", 11) == 0) { +// pids[pid].level = 1; +// } +// else if (mon_pid == pid && strncmp(ptr, "lxc-execute", 11) == 0) { +// pids[pid].level = 1; +// } + else + pids[pid].level = -1; + } + if (strncmp(buf, "State:", 6) == 0) { + if (strstr(buf, "(zombie)")) + pids[pid].zombie = 1; + } + else if (strncmp(buf, "PPid:", 5) == 0) { + char *ptr = buf + 5; + while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) { + ptr++; + } + if (*ptr == '\0') { + fprintf(stderr, "Error: cannot read /proc file\n"); + exit(1); + } + unsigned parent = atoi(ptr); + parent %= max_pids; + if (pids[parent].level > 0) { + pids[pid].level = pids[parent].level + 1; + } + pids[pid].parent = parent; + } + else if (strncmp(buf, "Uid:", 4) == 0) { + char *ptr = buf + 5; + while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) { + ptr++; + } + if (*ptr == '\0') { + fprintf(stderr, "Error: cannot read /proc file\n"); + exit(1); + } + pids[pid].uid = atoi(ptr); + break; + } + } + fclose(fp); + free(file); + } + closedir(dir); + + pid_t pid; + for (pid = 0; pid < max_pids; pid++) { + int parent = pids[pid].parent; + if (pids[parent].level > 0) { + pids[pid].level = pids[parent].level + 1; + } + } +} diff --git a/src/libtrace/Makefile.in b/src/libtrace/Makefile.in new file mode 100644 index 00000000000..8848fc08c84 --- /dev/null +++ b/src/libtrace/Makefile.in @@ -0,0 +1,25 @@ +PREFIX=@prefix@ +VERSION=@PACKAGE_VERSION@ +NAME=@PACKAGE_NAME@ + +H_FILE_LIST = $(wildcard *.[h]) +C_FILE_LIST = $(wildcard *.c) +OBJS = $(C_FILE_LIST:.c=.o) +BINOBJS = $(foreach file, $(OBJS), $file) +CFLAGS += -ggdb -O2 -DVERSION='"$(VERSION)"' -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIC -Wformat -Wformat-security +LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now + +all: libtrace.so + +%.o : %.c $(H_FILE_LIST) + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +# gcc -shared -fPIC -ldl traceopen.c -o traceopen.so +libtrace.so: $(OBJS) + $(CC) $(LDFLAGS) -shared -fPIC -z relro -o $@ $(OBJS) -ldl + + +clean:; rm -f $(OBJS) libtrace.so + +distclean: clean + rm -fr Makefile diff --git a/src/libtrace/libtrace.c b/src/libtrace/libtrace.c new file mode 100644 index 00000000000..a785ec698a9 --- /dev/null +++ b/src/libtrace/libtrace.c @@ -0,0 +1,609 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// break recursivity on fopen call +typedef FILE *(*orig_fopen_t)(const char *pathname, const char *mode); +static orig_fopen_t orig_fopen = NULL; +typedef FILE *(*orig_fopen64_t)(const char *pathname, const char *mode); +static orig_fopen64_t orig_fopen64 = NULL; + +// +// pid +// +static pid_t mypid = 0; +static inline pid_t pid(void) { + if (!mypid) + mypid = getpid(); + return mypid; +} + +// +// process name +// +#define MAXNAME 16 +static char myname[MAXNAME]; +static int nameinit = 0; +static char *name(void) { + if (!nameinit) { + // initialize the name of the process based on /proc/PID/comm + memset(myname, 0, MAXNAME); + + pid_t p = pid(); + char *fname; + if (asprintf(&fname, "/proc/%u/comm", p) == -1) + return "unknown"; + + // read file + if (!orig_fopen) + orig_fopen = (orig_fopen_t)dlsym(RTLD_NEXT, "fopen"); + FILE *fp = orig_fopen(fname, "r"); + if (!fp) + return "unknown"; + if (fgets(myname, MAXNAME, fp) == NULL) { + fclose(fp); + free(fname); + return "unknown"; + } + + // clean '\n' + char *ptr = strchr(myname, '\n'); + if (ptr) + *ptr = '\0'; + + fclose(fp); + free(fname); + nameinit = 1; + } + + return myname; +} + +// +// network +// +typedef struct { + int val; + char *name; +} XTable; + +static XTable socket_type[] = { +#ifdef SOCK_STREAM + { SOCK_STREAM, "SOCK_STREAM" }, +#endif +#ifdef SOCK_DGRAM + { SOCK_DGRAM, "SOCK_DGRAM" }, +#endif +#ifdef SOCK_RAW + { SOCK_RAW, "SOCK_RAW" }, +#endif +#ifdef SOCK_RDM + { SOCK_RDM, "SOCK_RDM" }, +#endif +#ifdef SOCK_SEQPACKET + { SOCK_SEQPACKET, "SOCK_SEQPACKET" }, +#endif +#ifdef SOCK_DCCP + { SOCK_DCCP, "SOCK_DCCP" }, +#endif + { 0, NULL} // NULL terminated +}; + +static XTable socket_domain[] = { +#ifdef AF_INET + { AF_INET, "AF_INET" }, +#endif +#ifdef AF_INET6 + { AF_INET6, "AF_INET6" }, +#endif +#ifdef AF_LOCAL + { AF_LOCAL, "AF_LOCAL" }, +#endif +#ifdef AF_PACKET + { AF_PACKET, "AF_PACKET" }, +#endif +#ifdef AF_IPX + { AF_IPX, "AF_IPX" }, +#endif +#ifdef AF_NETLINK + { AF_NETLINK, "AF_NETLINK" }, +#endif +#ifdef AF_X25 + { AF_X25, "AF_X25" }, +#endif +#ifdef AF_AX25 + { AF_AX25, "AF_AX25" }, +#endif +#ifdef AF_ATMPVC + { AF_ATMPVC, "AF_ATMPVC" }, +#endif +#ifdef AF_APPLETALK + { AF_APPLETALK, "AF_APPLETALK" }, +#endif + { 0, NULL} // NULL terminated +}; + +static XTable socket_protocol[] = { +#ifdef IPPROTO_IP + { IPPROTO_IP, "IPPROTO_IP" }, +#endif +#ifdef IPPROTO_ICMP + { IPPROTO_ICMP, "IPPROTO_ICMP" }, +#endif +#ifdef IPPROTO_IGMP + { IPPROTO_IGMP, "IPPROTO_IGMP" }, +#endif +#ifdef IPPROTO_IPIP + { IPPROTO_IPIP, "IPPROTO_IPIP" }, +#endif +#ifdef IPPROTO_TCP + { IPPROTO_TCP, "IPPROTO_TCP" }, +#endif +#ifdef IPPROTO_EGP + { IPPROTO_EGP, "IPPROTO_EGP" }, +#endif +#ifdef IPPROTO_PUP + { IPPROTO_PUP, "IPPROTO_PUP" }, +#endif +#ifdef IPPROTO_UDP + { IPPROTO_UDP, "IPPROTO_UDP" }, +#endif +#ifdef IPPROTO_IDP + { IPPROTO_IDP, "IPPROTO_IDP" }, +#endif +#ifdef IPPROTO_DCCP + { IPPROTO_DCCP, "IPPROTO_DCCP" }, +#endif +#ifdef IPPROTO_RSVP + { IPPROTO_RSVP, "IPPROTO_RSVP" }, +#endif +#ifdef IPPROTO_GRE + { IPPROTO_GRE, "IPPROTO_GRE" }, +#endif +#ifdef IPPROTO_IPV6 + { IPPROTO_IPV6, "IPPROTO_IPV6" }, +#endif +#ifdef IPPROTO_ESP + { IPPROTO_ESP, "IPPROTO_ESP" }, +#endif +#ifdef IPPROTO_AH + { IPPROTO_AH, "IPPROTO_AH" }, +#endif +#ifdef IPPROTO_BEETPH + { IPPROTO_BEETPH, "IPPROTO_BEETPH" }, +#endif +#ifdef IPPROTO_PIM + { IPPROTO_PIM, "IPPROTO_PIM" }, +#endif +#ifdef IPPROTO_COMP + { IPPROTO_COMP, "IPPROTO_COMP" }, +#endif +#ifdef IPPROTO_SCTP + { IPPROTO_SCTP, "IPPROTO_SCTP" }, +#endif +#ifdef IPPROTO_UDPLITE + { IPPROTO_UDPLITE, "IPPROTO_UDPLITE" }, +#endif +#ifdef IPPROTO_RAW + { IPPROTO_RAW, "IPPROTO_RAW" }, +#endif + { 0, NULL} // NULL terminated +}; + +static char *translate(XTable *table, int val) { + while (table->name != NULL) { + if (val == table->val) + return table->name; + table++; + } + + return NULL; +} + +static void print_sockaddr(const char *call, const struct sockaddr *addr) { + if (addr->sa_family == AF_INET) { + struct sockaddr_in *a = (struct sockaddr_in *) addr; + printf("%u:%s:%s %s:%u\n", pid(), name(), call, inet_ntoa(a->sin_addr), ntohs(a->sin_port)); + } + else if (addr->sa_family == AF_INET6) { + struct sockaddr_in6 *a = (struct sockaddr_in6 *) addr; + char str[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &(a->sin6_addr), str, INET6_ADDRSTRLEN); + printf("%u:%s:%s %s\n", pid(), name(), call, str); + } + else if (addr->sa_family == AF_UNIX) { + struct sockaddr_un *a = (struct sockaddr_un *) addr; + if (a->sun_path[0]) + printf("%u:%s:%s %s\n", pid(), name(), call, a->sun_path); + else + printf("%u:%s:%s @%s\n", pid(), name(), call, a->sun_path + 1); + } + else { + printf("%u:%s:%s family %d\n", pid(), name(), call, addr->sa_family); + } +} + +// +// syscalls +// + +// open +typedef int (*orig_open_t)(const char *pathname, int flags, mode_t mode); +static orig_open_t orig_open = NULL; +int open(const char *pathname, int flags, mode_t mode) { + if (!orig_open) + orig_open = (orig_open_t)dlsym(RTLD_NEXT, "open"); + + int rv = orig_open(pathname, flags, mode); + printf("%u:%s:open %s\n", pid(), name(), pathname); + return rv; +} + +typedef int (*orig_open64_t)(const char *pathname, int flags, mode_t mode); +static orig_open64_t orig_open64 = NULL; +int open64(const char *pathname, int flags, mode_t mode) { + if (!orig_open64) + orig_open64 = (orig_open64_t)dlsym(RTLD_NEXT, "open64"); + + int rv = orig_open64(pathname, flags, mode); + printf("%u:%s:open64 %s\n", pid(), name(), pathname); + return rv; +} + +// openat +typedef int (*orig_openat_t)(int dirfd, const char *pathname, int flags, mode_t mode); +static orig_openat_t orig_openat = NULL; +int openat(int dirfd, const char *pathname, int flags, mode_t mode) { + if (!orig_openat) + orig_openat = (orig_openat_t)dlsym(RTLD_NEXT, "openat"); + + int rv = orig_openat(dirfd, pathname, flags, mode); + printf("%u:%s:openat %s\n", pid(), name(), pathname); + return rv; +} + +typedef int (*orig_openat64_t)(int dirfd, const char *pathname, int flags, mode_t mode); +static orig_openat64_t orig_openat64 = NULL; +int openat64(int dirfd, const char *pathname, int flags, mode_t mode) { + if (!orig_openat64) + orig_openat64 = (orig_openat64_t)dlsym(RTLD_NEXT, "openat64"); + + int rv = orig_openat64(dirfd, pathname, flags, mode); + printf("%u:%s:openat64 %s\n", pid(), name(), pathname); + return rv; +} + + +// fopen +FILE *fopen(const char *pathname, const char *mode) { + if (!orig_fopen) + orig_fopen = (orig_fopen_t)dlsym(RTLD_NEXT, "fopen"); + + FILE *rv = orig_fopen(pathname, mode); + printf("%u:%s:fopen %s\n", pid(), name(), pathname); + return rv; +} + +FILE *fopen64(const char *pathname, const char *mode) { + if (!orig_fopen64) + orig_fopen64 = (orig_fopen_t)dlsym(RTLD_NEXT, "fopen64"); + + FILE *rv = orig_fopen64(pathname, mode); + printf("%u:%s:fopen64 %s\n", pid(), name(), pathname); + return rv; +} + + +// freopen +typedef FILE *(*orig_freopen_t)(const char *pathname, const char *mode, FILE *stream); +static orig_freopen_t orig_freopen = NULL; +FILE *freopen(const char *pathname, const char *mode, FILE *stream) { + if (!orig_freopen) + orig_freopen = (orig_freopen_t)dlsym(RTLD_NEXT, "freopen"); + + FILE *rv = orig_freopen(pathname, mode, stream); + printf("%u:%s:freopen %s\n", pid(), name(), pathname); + return rv; +} + +typedef FILE *(*orig_freopen64_t)(const char *pathname, const char *mode, FILE *stream); +static orig_freopen64_t orig_freopen64 = NULL; +FILE *freopen64(const char *pathname, const char *mode, FILE *stream) { + if (!orig_freopen64) + orig_freopen64 = (orig_freopen64_t)dlsym(RTLD_NEXT, "freopen64"); + + FILE *rv = orig_freopen64(pathname, mode, stream); + printf("%u:%s:freopen64 %s\n", pid(), name(), pathname); + return rv; +} + +// unlink +typedef int (*orig_unlink_t)(const char *pathname); +static orig_unlink_t orig_unlink = NULL; +int unlink(const char *pathname) { + if (!orig_unlink) + orig_unlink = (orig_unlink_t)dlsym(RTLD_NEXT, "unlink"); + + int rv = orig_unlink(pathname); + printf("%u:%s:unlink %s\n", pid(), name(), pathname); + return rv; +} + +typedef int (*orig_unlinkat_t)(int dirfd, const char *pathname, int flags); +static orig_unlinkat_t orig_unlinkat = NULL; +int unlinkat(int dirfd, const char *pathname, int flags) { + if (!orig_unlinkat) + orig_unlinkat = (orig_unlinkat_t)dlsym(RTLD_NEXT, "unlinkat"); + + int rv = orig_unlinkat(dirfd, pathname, flags); + printf("%u:%s:unlinkat %s\n", pid(), name(), pathname); + return rv; +} + +// mkdir/mkdirat/rmdir +typedef int (*orig_mkdir_t)(const char *pathname, mode_t mode); +static orig_mkdir_t orig_mkdir = NULL; +int mkdir(const char *pathname, mode_t mode) { + if (!orig_mkdir) + orig_mkdir = (orig_mkdir_t)dlsym(RTLD_NEXT, "mkdir"); + + int rv = orig_mkdir(pathname, mode); + printf("%u:%s:mkdir %s\n", pid(), name(), pathname); + return rv; +} + +typedef int (*orig_mkdirat_t)(int dirfd, const char *pathname, mode_t mode); +static orig_mkdirat_t orig_mkdirat = NULL; +int mkdirat(int dirfd, const char *pathname, mode_t mode) { + if (!orig_mkdirat) + orig_mkdirat = (orig_mkdirat_t)dlsym(RTLD_NEXT, "mkdirat"); + + int rv = orig_mkdirat(dirfd, pathname, mode); + printf("%u:%s:mkdirat %s\n", pid(), name(), pathname); + return rv; +} + +typedef int (*orig_rmdir_t)(const char *pathname); +static orig_rmdir_t orig_rmdir = NULL; +int rmdir(const char *pathname) { + if (!orig_rmdir) + orig_rmdir = (orig_rmdir_t)dlsym(RTLD_NEXT, "rmdir"); + + int rv = orig_rmdir(pathname); + printf("%u:%s:rmdir %s\n", pid(), name(), pathname); + return rv; +} + +// stat +typedef int (*orig_stat_t)(const char *pathname, struct stat *buf); +static orig_stat_t orig_stat = NULL; +int stat(const char *pathname, struct stat *buf) { + if (!orig_stat) + orig_stat = (orig_stat_t)dlsym(RTLD_NEXT, "stat"); + + int rv = orig_stat(pathname, buf); + printf("%u:%s:stat %s\n", pid(), name(), pathname); + return rv; +} + +typedef int (*orig_stat64_t)(const char *pathname, struct stat64 *buf); +static orig_stat64_t orig_stat64 = NULL; +int stat64(const char *pathname, struct stat64 *buf) { + if (!orig_stat) + orig_stat64 = (orig_stat64_t)dlsym(RTLD_NEXT, "stat"); + + int rv = orig_stat64(pathname, buf); + printf("%u:%s:stat %s\n", pid(), name(), pathname); + return rv; +} + + +// access +typedef int (*orig_access_t)(const char *pathname, int mode); +static orig_access_t orig_access = NULL; +int access(const char *pathname, int mode) { + if (!orig_access) + orig_access = (orig_access_t)dlsym(RTLD_NEXT, "access"); + + int rv = orig_access(pathname, mode); + printf("%u:%s:access %s\n", pid(), name(), pathname); + return rv; +} + + +// connect +typedef int (*orig_connect_t)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); +static orig_connect_t orig_connect = NULL; +int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { + if (!orig_connect) + orig_connect = (orig_connect_t)dlsym(RTLD_NEXT, "connect"); + + int rv = orig_connect(sockfd, addr, addrlen); + print_sockaddr("connect", addr); + + return rv; +} + +// socket +typedef int (*orig_socket_t)(int domain, int type, int protocol); +static orig_socket_t orig_socket = NULL; +static char buf[1024]; +int socket(int domain, int type, int protocol) { + if (!orig_socket) + orig_socket = (orig_socket_t)dlsym(RTLD_NEXT, "socket"); + + int rv = orig_socket(domain, type, protocol); + char *ptr = buf; + ptr += sprintf(ptr, "%u:%s:socket ", pid(), name()); + char *str = translate(socket_domain, domain); + if (str == NULL) + ptr += sprintf(ptr, "%d ", domain); + else + ptr += sprintf(ptr, "%s ", str); + + int t = type; // glibc uses higher bits for various other purposes +#ifdef SOCK_CLOEXEC + t &= ~SOCK_CLOEXEC; +#endif +#ifdef SOCK_NONBLOCK + t &= ~SOCK_NONBLOCK; +#endif + str = translate(socket_type, t); + if (str == NULL) + ptr += sprintf(ptr, "%d ", type); + else + ptr += sprintf(ptr, "%s ", str); + + str = translate(socket_protocol, protocol); + if (str == NULL) + ptr += sprintf(ptr, "%d", protocol); + else + ptr += sprintf(ptr, "%s", str); + + printf("%s\n", buf); + return rv; +} + +// bind +typedef int (*orig_bind_t)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); +static orig_bind_t orig_bind = NULL; +int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { + if (!orig_bind) + orig_bind = (orig_bind_t)dlsym(RTLD_NEXT, "bind"); + + int rv = orig_bind(sockfd, addr, addrlen); + print_sockaddr("bind", addr); + + return rv; +} + +#if 0 //todo: fix compilation problems +typedef int (*orig_accept_t)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); +static orig_accept_t orig_accept = NULL; +int accept(int sockfd, struct sockaddr *addr, socklen_t addrlen) { + if (!orig_accept) + orig_accept = (orig_accept_t)dlsym(RTLD_NEXT, "accept"); + + int rv = orig_accept(sockfd, addr, addrlen); + print_sockaddr("accept", addr); + + return rv; +} +#endif + +typedef int (*orig_system_t)(const char *command); +static orig_system_t orig_system = NULL; +int system(const char *command) { + if (!orig_system) + orig_system = (orig_system_t)dlsym(RTLD_NEXT, "system"); + + int rv = orig_system(command); + printf("%u:%s:system %s\n", pid(), name(), command); + + return rv; +} + +typedef int (*orig_setuid_t)(uid_t uid); +static orig_setuid_t orig_setuid = NULL; +int setuid(uid_t uid) { + if (!orig_setuid) + orig_setuid = (orig_setuid_t)dlsym(RTLD_NEXT, "setuid"); + + int rv = orig_setuid(uid); + printf("%u:%s:setuid %d\n", pid(), name(), uid); + + return rv; +} + +typedef int (*orig_setgid_t)(gid_t gid); +static orig_setgid_t orig_setgid = NULL; +int setgid(gid_t gid) { + if (!orig_setgid) + orig_setgid = (orig_setgid_t)dlsym(RTLD_NEXT, "setgid"); + + int rv = orig_setgid(gid); + printf("%u:%s:setgid %d\n", pid(), name(), gid); + + return rv; +} + +typedef int (*orig_setfsuid_t)(uid_t uid); +static orig_setfsuid_t orig_setfsuid = NULL; +int setfsuid(uid_t uid) { + if (!orig_setfsuid) + orig_setfsuid = (orig_setfsuid_t)dlsym(RTLD_NEXT, "setfsuid"); + + int rv = orig_setfsuid(uid); + printf("%u:%s:setfsuid %d\n", pid(), name(), uid); + + return rv; +} + +typedef int (*orig_setfsgid_t)(gid_t gid); +static orig_setfsgid_t orig_setfsgid = NULL; +int setfsgid(gid_t gid) { + if (!orig_setfsgid) + orig_setfsgid = (orig_setfsgid_t)dlsym(RTLD_NEXT, "setfsgid"); + + int rv = orig_setfsgid(gid); + printf("%u:%s:setfsgid %d\n", pid(), name(), gid); + + return rv; +} + +typedef int (*orig_setreuid_t)(uid_t ruid, uid_t euid); +static orig_setreuid_t orig_setreuid = NULL; +int setreuid(uid_t ruid, uid_t euid) { + if (!orig_setreuid) + orig_setreuid = (orig_setreuid_t)dlsym(RTLD_NEXT, "setreuid"); + + int rv = orig_setreuid(ruid, euid); + printf("%u:%s:setreuid %d %d\n", pid(), name(), ruid, euid); + + return rv; +} + +typedef int (*orig_setregid_t)(gid_t rgid, gid_t egid); +static orig_setregid_t orig_setregid = NULL; +int setregid(gid_t rgid, gid_t egid) { + if (!orig_setregid) + orig_setregid = (orig_setregid_t)dlsym(RTLD_NEXT, "setregid"); + + int rv = orig_setregid(rgid, egid); + printf("%u:%s:setregid %d %d\n", pid(), name(), rgid, egid); + + return rv; +} + +typedef int (*orig_setresuid_t)(uid_t ruid, uid_t euid, uid_t suid); +static orig_setresuid_t orig_setresuid = NULL; +int setresuid(uid_t ruid, uid_t euid, uid_t suid) { + if (!orig_setresuid) + orig_setresuid = (orig_setresuid_t)dlsym(RTLD_NEXT, "setresuid"); + + int rv = orig_setresuid(ruid, euid, suid); + printf("%u:%s:setresuid %d %d %d\n", pid(), name(), ruid, euid, suid); + + return rv; +} + +typedef int (*orig_setresgid_t)(gid_t rgid, gid_t egid, gid_t sgid); +static orig_setresgid_t orig_setresgid = NULL; +int setresgid(gid_t rgid, gid_t egid, gid_t sgid) { + if (!orig_setresgid) + orig_setresgid = (orig_setresgid_t)dlsym(RTLD_NEXT, "setresgid"); + + int rv = orig_setresgid(rgid, egid, sgid); + printf("%u:%s:setresgid %d %d %d\n", pid(), name(), rgid, egid, sgid); + + return rv; +} \ No newline at end of file diff --git a/src/man/firejail-login.txt b/src/man/firejail-login.txt new file mode 100644 index 00000000000..6613dc044f1 --- /dev/null +++ b/src/man/firejail-login.txt @@ -0,0 +1,36 @@ +.TH man 5 "MONTH YEAR" "VERSION" "firejail login.users man page" +.SH NAME +login.users \- Login file syntax for Firejail + +.SH DESCRIPTION +/etc/firejail/login.users file describes additional arguments passed to firejail executable +upon user logging into a Firejail restircted shell. Each user entry in the file consists of +a user name followed by the arguments passed to firejail. The format is as follows: + + user_name: arguments + +Example: + + netblue:--debug --net=none + +.SH RESTRICTED SHELL +To configure a restricted shell, replace /bin/bash with /usr/bin/firejail in +/etc/password file for each user that needs to be restricted. Alternatively, +you can specify /usr/bin/firejail in adduser command: + +adduser \-\-shell /usr/bin/firejail username + +.SH FILES +/etc/firejail/login.users + +.SH LICENSE +Firejail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. +.PP +Homepage: http://firejail.sourceforge.net +.SH SEE ALSO +\&\flfirejail\fR\|(1), +\&\flfiremon\fR\|(1), +\&\flfirejail-profile\fR\|(5) + + + diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt new file mode 100644 index 00000000000..46da19ecde8 --- /dev/null +++ b/src/man/firejail-profile.txt @@ -0,0 +1,181 @@ +.TH man 5 "MONTH YEAR" "VERSION" "firejail profiles man page" +.SH NAME +profile \- Profile file syntax for Firejail + +.SH USAGE +.TP +firejail \-\-profile=filename.profile + +.SH DESCRIPTION +Several Firejail command line configuration options can be passed to the program using +profile files. Default Firejail profile files are stored in /etc/firejail +directory and ~/.config/firejail directory. + +.SH Scripting +Include and comment support: + +.TP +\f\include other.profile +Include other.profile file. +.TP +# this is a comment + +.SH Filesystem +These profile entries define a chroot filesystem built on top of the existing +host filesystem. Each line describes a file element that is removed from +the filesystem (\fBblacklist\fR), a read-only file or directory (\fBread-only\fR), +a tmpfs mounted on top of an existing directory (\fBtmpfs\fR), +or mount-bind a directory or file on top of another directory or file (\fBbind\fR). +Use \fBprivate\fR to set private mode. +File globbing is supported, and PATH and HOME directories are searched. +Examples: +.TP +\f\blacklist /usr/bin +Remove /usr/bin directory. +.TP +\f\blacklist /etc/password +Remove /etc/password file. +.TP +\f\read-only /etc/password +Read-only /etc/password file. +.TP +tmpfs /etc +Mount an empty tmpfs filesystem on top of /etc directory. +.TP +bind /root/config/ssh,/etc/ssh +Mount-bind /root/config/ssh on /etc/ssh. +.TP +\f\blacklist /usr/bin/gcc* +Remove all gcc files in /usr/bin (file globbing). +.TP +\f\blacklist ${PATH}/ifconfig +Remove ifconfig command from the regular path directories. +.TP +\f\blacklist ${HOME}/.ssh +Remove .ssh directory from user home directory. +.TP +\f\private +Mount new /root and /home/user directories in temporary +filesystems. All modifications are discarded when the sandbox is +closed. +.TP +\f\private directory +Use directory as user home. +.TP +\f\private.keep file,directory +Build a new user home in a temporary +filesystem, and copy the files and directories in the list in the +new home. All modifications are discarded when the sandbox is +closed. +.TP +\f\private-dev +Create a new /dev directory. Only null, full, zero, tty, pts, ptmx, random, urandom and shm devices are available. + +.SH Filters +\fBcaps\fR and \fBseccomp\fR enable Linux capabilities and seccomp filters. Examples: + +.TP +caps +Enable default Linux capabilities filter. +.TP +caps.drop all +Blacklist all Linux capabilities. +.TP +caps.drop capability,capability,capability +Blacklist Linux capabilities filter. +.TP +caps.drop capability,capability,capability +Whitelist Linux capabilities filter. +.TP +\f\seccomp +Enable default seccomp filter. +.TP +\f\seccomp syscall,syscall,syscall +Enable seccomp filter and blacklist the system calls in the list on top of default seccomp filter. +.TP +\f\seccomp.drop syscall,syscall,syscall +Enable seccomp filter and blacklist the system calls in the list. +.TP +\f\seccomp.keep syscall,syscall,syscall +Enable seccomp filter and whitelist the system calls in the list. + + +.SH User Namespace +Use \fBnoroot\fR to enable an user namespace. The namespace has only one user, the current user. +There is no root account defined in the namespace. + +.TP +noroot +Enable an user namespace without root user defined. + + +.SH Resource limits +These profile entries define the limits on system resources (rlimits) for the processes inside the sandbox. +The limits can be modified inside the sandbox using the regular \fBulimt\fR command. Examples: + +.TP +\f\rlimit-fsize 1024 +Set the maximum file size that can be created by a process to 1024 bytes. +.TP +\f\rlimit-nproc 1000 +Set the maximum number of processes that can be created for the real user ID of the calling process to 1000. +.TP +\f\rlimit-nofile 500 +Set the maximum number of files that can be opened by a process to 500. +.TP +\f\rlimit-sigpending 200 +Set the maximum number of processes that can be created for the real user ID of the calling process to 200. + +.SH CPU Affinity +Set the CPU cores available for this sandbox. Examples: + +.TP +cpu 1,2,3 +Use only CPU cores 0, 1 and 2. + +.SH Control Groups +Place the sandbox in an existing control group specified by the full path of the task file. Example: + +.TP +cgroup /sys/fs/cgroup/g1/tasks +The sandbox is placed in g1 control group. + +.SH User Environment + +.TP +nogroups +Disable supplementary user groups +.TP +shell none +Run the program directly, without a shell. + +.SH Networking +Networking features available in profile files. + +.TP +netfilter +If a new network namespace is created, enabled default network filter. + +.TP +netfilter filename +If a new network namespace is created, enabled the network filter in filename. + +.TP +dns address +Set a DNS server for the sandbox. Up to three DNS servers can be defined. + + +.SH FILES +/etc/firejail/filename.profile, $HOME/.config/firejail/filename.profile + +.SH LICENSE +Firejail is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. +.PP +Homepage: http://firejail.sourceforge.net +.SH SEE ALSO +\&\flfirejail\fR\|(1), +\&\flfiremon\fR\|(1), +\&\flfirejail-login\fR\|(5) + + + diff --git a/src/man/firejail.txt b/src/man/firejail.txt new file mode 100644 index 00000000000..51f21975ea9 --- /dev/null +++ b/src/man/firejail.txt @@ -0,0 +1,1196 @@ +.TH man 1 "MONTH YEAR" "VERSION" "firejail man page" +.SH NAME +Firejail \- Linux namespaces sandbox program +.SH SYNOPSIS +Start a sandbox: +.PP +.RS +firejail [OPTIONS] [program and arguments] +.RE +.PP +Network traffic shaping for an existing sandbox: +.PP +.RS +firejail \-\-bandwidth={|} bandwidth-command +.RE +.PP +Monitoring: +.PP +.RS +firejail {\-\-list | \-\-netstats | \-\-top | \-\-tree} +.RE +.PP +Miscellaneous: +.PP +.RS +firejail {\-? | \-\-debug-caps | \-\-debug-syscalls | \-\-help | +.br +\-\-version} +.RE +.SH DESCRIPTION +Firejail is a SUID sandbox program that reduces the risk of security breaches by +restricting the running environment of untrusted applications using Linux +namespaces, seccomp-bpf and Linux capabilities. +It allows a process and all its descendants to have their own private view of the +globally shared kernel resources, such as the network stack, process table, mount table. +Firejail can work in a SELinux or AppArmor environment, +and it is integrated with Linux Control Groups. +.PP +Written in C with virtually no dependencies, the software runs on any Linux computer with a 3.x kernel version +or newer. +It can sandbox any type of processes: servers, graphical applications, and even user login sessions. +The software includes sandbox profiles for a number of more common +Linux programs, such as Mozilla Firefox, Chromium, VLC, Transmission etc. +.SH USAGE +Without any options, the sandbox consists of a chroot filesystem build in a new mount namespace, +and new PID and UTS namespaces. IPC, network and user namespaces can be added using the command line options. +The default Firejail filesystem is based on the host filesystem with the main directories mounted read-only. +Only /home, /tmp and /var directories are writable. +.PP +If no program is specified as an argument, /bin/bash is started by default. +Examples: +.PP +$ firejail [OPTIONS] # starting a /bin/bash shell +.PP +$ firejail [OPTIONS] firefox # starting Mozilla Firefox +.PP +Multiple commands can be run in sandbox using regular bash logic operators: +.PP +$ sudo firejail [OPTIONS] "/etc/init.d/nginx start && sleep inf" +.PP +In the previous example, "sleep inf" command is required in order to keep the session open for the daemon program. + +.SH OPTIONS +.TP +\fB\-\- +Signal the end of options and disables further option processing. +.TP +\fB\-\-bandwidth=name +Set bandwidth limits for the sandbox identified by name, see TRAFFIC SHAPING section for more details. +.TP +\fB\-\-bandwidth=pid +Set bandwidth limits for the sandbox identified by PID, see TRAFFIC SHAPING section for more details. +.TP +\fB\-\-bind=dirname1,dirname2 +Mount-bind dirname1 on top of dirname2. This option is only available when running the sandbox as root. +.br + +.br +Example: +.br +# firejail \-\-bind=/config/www,/var/www +.TP +\fB\-\-bind=filename1,filename2 +Mount-bind filename1 on top of filename2. This option is only available when running as root. +.br + +.br +Example: +.br +# firejail \-\-bind=/config/etc/passwd,/etc/passwd +.TP +\fB\-\-blacklist=dirname_or_filename +Blacklist directory or file. +.br + +.br +Example: +.br +$ firejail \-\-blacklist=/sbin \-\-blacklist=/usr/sbin +.TP +\fB\-c +Execute command and exit. +.TP +\fB\-\-caps +Linux capabilities is a kernel feature designed to split up the root privilege into a set of distinct privileges. +These privileges can be enabled or disabled independently, thus restricting what a process running +as root can do in the system. + +By default root programs run with all capabilities enabled. \-\-caps option disables the following capabilities: +CAP_SYS_MODULE, CAP_SYS_RAWIO, +CAP_SYS_BOOT, CAP_SYS_NICE, CAP_SYS_TTY_CONFIG, CAP_SYSLOG, CAP_MKNOD, CAP_SYS_ADMIN. +The filter is applied to all processes started in the sandbox. +.br + +.br +Example: +.br +$ sudo firejail \-\-caps "/etc/init.d/nginx start && sleep inf" + +.TP +\fB\-\-caps.drop=all +Drop all capabilities for the processes running in the sandbox. This option is recommended for running GUI programs +or any other program that doesn't require root privileges. It is a must-have option for sandboxing untrusted programs +installed from unofficial sources - such as games, Java programs, etc. +.br + +.br +Example: +.br +$ firejail \-\-caps.drop=all warzone2100 + +.TP +\fB\-\-caps.drop=capability,capability,capability +Define a custom blacklist Linux capabilities filter. +.br + +.br +Example: +.br +$ firejail \-\-caps.keep=net_broadcast,net_admin,net_raw + +.TP +\fB\-\-caps.keep=capability,capability,capability +Define a custom whitelist Linux capabilities filter. +.br + +.br +Example: +.br +$ sudo firejail \-\-caps.keep=chown,net_bind_service,setgid,\\ +setuid "/etc/init.d/nginx start && sleep inf" + +.TP +\fB\-\-caps.print=name +Print the caps filter for the sandbox identified by name. +.br + +.br +Example: +.br +$ firejail \-\-name=mygame \-\-caps.drop=all warzone2100 & +.br +[...] +.br +$ firejail \-\-caps.print=mygame + +.TP +\fB\-\-caps.print=pid +Print the caps filter for a sandbox identified by PID. +.br + +.br +Example: +.br +$ firejail \-\-list +.br +3272:netblue:firejail \-\-private firefox +.br +$ firejail \-\-caps.print=3272 + +.TP +\fB\-\-cgroup=tasks-file +Place the sandbox in the specified control group. tasks-file is the full path of cgroup tasks file. +.br + +.br +Example: +.br +# firejail \-\-cgroup=/sys/fs/cgroup/g1/tasks + +.TP +\fB\-\-chroot=dirname +Chroot the sandbox into a root filesystem. If the sandbox is started as a +regular user, default seccomp and capabilities filters are eanbled. +.br + +.br +Example: +.br +$ firejail \-\-chroot=/media/ubuntu warzone2100 + +.TP +\fB\-\-cpu=cpu-number,cpu-number,cpu-number +Set CPU affinity. +.br + +.br +Example: +.br +$ firejail \-\-cpu=0,1 handbrake + +.TP +\fB\-\-csh +Use /bin/csh as default user shell. +.br + +.br +Example: +.br +$ firejail \-\-csh +.TP +\fB\-\-debug\fR +Print debug messages. +.br + +.br +Example: +.br +$ firejail \-\-debug firefox +.TP +\fB\-\-debug-syscalls +Print all recognized system calls in the current Firejail software build and exit. +.br + +.br +Example: +.br +$ firejail \-\-debug-syscalls +.TP +\fB\-\-debug-caps +Print all recognized capabilities in the current Firejail software build and exit. +.br + +.br +Example: +.br +$ firejail \-\-debug-caps +.TP +\fB\-\-defaultgw=address +Use this address as default gateway in the new network namespace. +.br + +.br +Example: +.br +$ firejail \-\-net=eth0 \-\-defaultgw=10.10.20.1 firefox + +.TP +\fB\-\-dns=address +Set a DNS server for the sandbox. Up to three DNS servers can be defined. +Use this option if you don't trust the DNS setup on your network. +.br + +.br +Example: +.br +$ firejail \-\-dns=8.8.8.8 \-\-dns=8.8.4.4 firefox + +.TP +\fB\-\-dns.print=name +Print DNS configuration for a sandbox identified by name. +.br + +.br +Example: +.br +$ firejail \-\-name=mygame \-\-caps.drop=all warzone2100 & +.br +[...] +.br +$ firejail \-\-dns.print=mygame + +.TP +\fB\-\-dns.print=pid +Print DNS configuration for a sandbox identified by PID. +.br + +.br +Example: +.br +$ firejail \-\-list +.br +3272:netblue:firejail \-\-private firefox +.br +$ firejail \-\-dns.print=3272 + +.TP +\fB\-?\fR, \fB\-\-help\fR +Print options end exit. +.TP +\fB\-\-ip=address +Assign IP addresses to the last network interface defined by a \-\-net option. A +default gateway is assigned by default. +.br + +.br +Example: +.br +$ firejail \-\-net=eth0 \-\-ip=10.10.20.56 firefox + +.TP +\fB\-\-ip=none +No IP address and no default gateway are configured for the last interface +defined by a \-\-net option. Use this option +in case you intend to start an external DHCP client in the sandbox. +.br + +.br +Example: +.br +$ firejail \-\-net=eth0 \-\-\ip=none + +.TP +\fB\-\-iprange=address,address +Assign an IP address in the provided range to the last network interface defined by a \-\-net option. A +default gateway is assigned by default. +.br + +.br +Example: +.br +$ firejail \-\-net=eth0 \-\-\iprange=192.168.1.100,192.168.1.150 + +.TP +\fB\-\-ipc-namespace +Enable a new IPC namespace if the sandbox was started as a regular user. IPC namespace is enabled by default +for sandboxes started as root. +.br + +.br +Example: +.br +$ firejail \-\-ipc-namespace firefox +.TP +\fB\-\-join=name +Join the sandbox identified by name. By default a /bin/bash shell is started after joining the sandbox. +If a program is specified, the program is run in the sandbox. +.br + +.br +Example: +.br +$ firejail \-\-name=mygame \-\-caps.drop=all warzone2100 & +.br +[...] +.br +$ firejail \-\-join=mygame + + +.TP +\fB\-\-join=pid +Join the sandbox identified by PID. By default a /bin/bash shell is started after joining the sandbox. +If a program is specified, the program is run in the sandbox. +.br + +.br +Example: +.br +$ firejail \-\-list +.br +3272:netblue:firejail \-\-private firefox +.br +$ firejail \-\-join=3272 + +.TP +\fB\-\-list +List all sandboxes, see MONITORING section for more details. +.br + +.br +Example: +.br +$ firejail \-\-list +.br +7015:netblue:firejail firefox +.br +7056:netblue:firejail \-\-net=eth0 transmission-gtk +.br +7064:netblue:firejail \-\-noroot xterm +.br +$ +.TP +\fB\-\-mac=address +Assign MAC addresses to the last network interface defined by a \-\-net option. +.br + +.br +Example: +.br +$ firejail \-\-net=eth0 \-\-mac=00:11:22:33:44:55 firefox + +.TP +\fB\-\-name=name +Set sandbox hostname. Several options, such as \-\-join and \-\-shutdown, can use +this name to identify a sandbox. +.br + +.br +Example: +.br +$ firejail \-\-name=mybrowser firefox + +.TP +\fB\-\-net=bridge_interface +Enable a new network namespace and connect it to this bridge interface. +Unless specified with option \-\-ip and \-\-defaultgw, an IP address and a default gateway will be assigned +automatically to the sandbox. The IP address is verified using ARP before assignment. The address +configured as default gateway is the bridge device IP address. Up to four \-\-net +bridge devices can be defined. Mixing bridge and macvlan devices is allowed. +.br + +.br +Example: +.br +$ sudo brctl addbr br0 +.br +$ sudo ifconfig br0 10.10.20.1/24 +.br +$ sudo brctl addbr br1 +.br +$ sudo ifconfig br1 10.10.30.1/24 +.br +$ firejail \-\-net=br0 \-\-net=br1 + +.TP +\fB\-\-net=ethernet_interface +Enable a new network namespace and connect it +to this ethernet interface using the standard Linux macvlan +driver. Unless specified with option \-\-ip and \-\-defaultgw, an +IP address and a default gateway will be assigned automatically +to the sandbox. The IP address is verified using ARP before +assignment. The address configured as default gateway is the +default gateway of the host. Up to four \-\-net devices can +be defined. Mixing bridge and macvlan devices is allowed. +.br + +.br +Example: +.br +$ firejail \-\-net=eth0 \-\-ip=192.168.1.80 \-\-dns=8.8.8.8 firefox + +.TP +\fB\-\-net=none +Enable a new, unconnected network namespace. The only interface +available in the new namespace is a new loopback interface (lo). +Use this option to deny +network access to programs that don't really need network access. +.br + +.br +Example: +.br +$ firejail \-\-net=none vlc + +.TP +\fB\-\-netfilter +Enable a default client network filter in the new network namespace. +New network namespaces are created using \-\-net option. If a new network namespaces is not created, +\-\-netfilter option does nothing. +The default filter is as follows: +.br + +.br +*filter +.br +:INPUT DROP [0:0] +.br +:FORWARD DROP [0:0] +.br +:OUTPUT ACCEPT [0:0] +.br +\-A INPUT \-i lo \-j ACCEPT +.br +\-A INPUT \-m state \-\-state RELATED,ESTABLISHED \-j ACCEPT +.br +\-A INPUT \-p icmp \-\-icmp-type destination-unreachable \-j ACCEPT +.br +\-A INPUT \-p icmp \-\-icmp-type time-exceeded \-j ACCEPT +.br +\-A INPUT \-p icmp \-\-icmp-type echo-request \-j ACCEPT +.br +COMMIT +.br + +.br +Example: +.br +$ firejail \-\-net=eth0 \-\-netfilter firefox +.TP +\fB\-\-netfilter=filename +Enable the network filter specified by filename in the new network namespace. The filter file format +is the format of iptables-save and iptable-restore commands. +New network namespaces are created using \-\-net option. If a new network namespaces is not created, +\-\-netfilter option does nothing. +.br + +.br +Example: +.br +$ firejail \-\-net=eth0 \-\-netfilter=myfile firefox +.TP +\fB\-\-netstats +Monitor network namespace statistics, see MONITORING section for more details. +.br + +.br +Example: +.br +$ firejail \-\-netstats +.br +PID User RX(KB/s) TX(KB/s) Command +.br +1294 netblue 53.355 1.473 firejail \-\-net=eth0 firefox +.br +7383 netblue 9.045 0.112 firejail \-\-net=eth0 transmission + + +.TP +\fB\-\-nogroups +Disable supplementary groups. Without this option, supplementary groups are enabled for the user starting the +sandbox. For root user supplementary groups are always disabled. +.br + +.br +Example: +.br +$ id +.br +uid=1000(netblue) gid=1000(netblue) groups=1000(netblue),24(cdrom),25(floppy),27(sudo),29(audio) +.br +$ firejail \-\-nogroups +.br +Parent pid 8704, child pid 8705 +.br +Child process initialized +.br +$ id +.br +uid=1000(netblue) gid=1000(netblue) groups=1000(netblue) +.br +$ + +.TP +\fB\-\-noroot +Install a user namespace with a single user - the current user. +root user does not exist in the new namespace. This option +requires a Linux kernel version 3.8 or newer. The option +is not supported for \-\-chroot and \-\-overlay configurations, +or for sandboxes started as root. +.br + +.br +Example: +.br +$ firejail \-\-noroot +.br +Parent pid 8553, child pid 8554 +.br +Child process initialized +.br +$ ping google.com +.br +ping: icmp open socket: Operation not permitted +.br +$ +.TP +\fB\-\-output=logfile +stdout logging and log rotation. Copy stdout to logfile, and keep the size of the file under 500KB using log +rotation. Five files with prefixes .1 to .5 are used in rotation. +.br + +.br +Example: +.br +$ firejail \-\-output=sandboxlog /bin/bash +.br +[...] +.br +$ ls -l sandboxlog* +.br +-rw-r--r-- 1 netblue netblue 333890 Jun 2 07:48 sadnboxlog +.br +-rw-r--r-- 1 netblue netblue 511488 Jun 2 07:48 sandboxlog.1 +.br +-rw-r--r-- 1 netblue netblue 511488 Jun 2 07:48 sandboxlog.2 +.br +-rw-r--r-- 1 netblue netblue 511488 Jun 2 07:48 sandboxlog.3 +.br +-rw-r--r-- 1 netblue netblue 511488 Jun 2 07:48 sandboxlog.4 +.br +-rw-r--r-- 1 netblue netblue 511488 Jun 2 07:48 sandboxlog.5 + +.TP +\fB\-\-overlay +Mount a filesystem overlay on top of the current filesystem. All filesystem modifications go into the overlay, +and are discarded when the sandbox is closed. +.br + +.br +OverlayFS support is required in Linux kernel for this option to work. +OverlayFS was officially introduced in Linux kernel version 3.18. It was also +available in earlier kernel versions in some distributions such as Ubuntu and OpenSUSE. +.br + +.br +Example: +.br +$ firejail \-\-overlay firefox + +.TP +\fB\-\-private +Mount new /root and /home/user directories in temporary +filesystems. All modifications are discarded when the sandbox is +closed. +.br + +.br +Example: +.br +$ firejail \-\-private firefox +.TP +\fB\-\-private=directory +Use directory as user home. +.br + +.br +Example: +.br +$ firejail \-\-private=/home/netblue/firefox-home firefox + +.TP +\fB\-\-private.keep=file,directory +Build a new user home in a temporary +filesystem, and copy the files and directories in the list in the +new home. All modifications are discarded when the sandbox is +closed. +.br + +.br +Example: +.br +$ firejail \-\-private.keep=.mozilla firefox +.TP +\fB\-\-private-dev +Create a new /dev directory. Only null, full, zero, tty, pts, ptmx, random, urandom and shm devices are available. +.br + +.br +Example: +.br +$ firejail \-\-private-dev +.br +Parent pid 9887, child pid 9888 +.br +Child process initialized +.br +$ ls /dev +.br +full null ptmx pts random shm tty urandom zero +.br +$ +.TP +\fB\-\-profile=filename +Load a custom profile from filename. For filename use an absolute path or a path relative to the current path. +For more information, see PROFILES section below. +.br + +.br +Example: +.br +$ firejail \-\-profile=myprofile +.TP +\fB\-\-read-only=dirname_or_filename +Set directory or file read-only. +.br + +.br +Example: +.br +$ firejail \-\-read-only=~/.mozilla firefox +.TP +\fB\-\-rlimit-fsize=number +Set the maximum file size that can be created by a process. +.TP +\fB\-\-rlimit-nofile=number +Set the maximum number of files that can be opened by a process. +.TP +\fB\-\-rlimit-nproc=number +Set the maximum number of processes that can be created for the real user ID of the calling process. +.TP +\fB\-\-rlimit-sigpending=number +Set the maximum number of pending signals for a process. +.TP +\fB\-\-scan +ARP-scan all the networks from inside a network namespace. +This makes it possible to detect macvlan kernel device drivers running on the current host. +.br + +.br +Example: +.br +$ firejail \-\-net=eth0 \-\-scan +.TP +\fB\-\-seccomp +Enable seccomp filter and blacklist the syscalls in the default list. The default list is as follows: +mount, umount2, ptrace, kexec_load, open_by_handle_at, init_module, finit_module, delete_module, +iopl, ioperm, swapon, swapoff, mknode, syslog, process_vm_readv and process_vm_writev, +sysfs,_sysctl, adjtimex, clock_adjtime, lookup_dcookie, perf_event_open, fanotify_init and kcmp. +.br + +.br +Example: +.br +$ firejail \-\-sccomp +.TP +\fB\-\-seccomp=syscall,syscall,syscall +Enable seccomp filter, blacklist the default list and the syscalls specified by the command. +.br + +.br +Example: +.br +$ firejail \-\-seccomp=utime,utimensat,utimes firefox +.TP +\fB\-\-seccomp.drop=syscall,syscall,syscall +Enable seccomp filter, and blacklist the syscalls specified by the command. +.br + +.br +Example: +.br +$ firejail \-\-seccomp.drop=utime,utimensat,utimes +.TP +\fB\-\-seccomp.keep=syscall,syscall,syscall +Enable seccomp filter, and whitelist the syscalls specified by the command. +.br + +.br +Example: +.br +$ firejail \-\-shell=none \-\-seccomp.keep=poll,select,[...] transmission-gtk +.TP +\fB\-\-seccomp.print=name +Print the seccomp filter for the sandbox started using \-\-name option. +.br + +.br +Example: +.br +$ firejail \-\-name=browser firefox & +.br +$ firejail \-\-seccomp.print=browser +.br +SECCOMP Filter: +.br + VALIDATE_ARCHITECTURE +.br + EXAMINE_SYSCAL +.br + BLACKLIST 165 mount +.br + BLACKLIST 166 umount2 +.br + BLACKLIST 101 ptrace +.br + BLACKLIST 246 kexec_load +.br + BLACKLIST 304 open_by_handle_at +.br + BLACKLIST 175 init_module +.br + BLACKLIST 176 delete_module +.br + BLACKLIST 172 iopl +.br + BLACKLIST 173 ioperm +.br + BLACKLIST 167 swapon +.br + BLACKLIST 168 swapoff +.br + BLACKLIST 103 syslog +.br + BLACKLIST 310 process_vm_readv +.br + BLACKLIST 311 process_vm_writev +.br + BLACKLIST 133 mknod +.br + BLACKLIST 139 sysfs +.br + BLACKLIST 156 _sysctl +.br + BLACKLIST 159 adjtimex +.br + BLACKLIST 305 clock_adjtime +.br + BLACKLIST 212 lookup_dcookie +.br + BLACKLIST 298 perf_event_open +.br + BLACKLIST 300 fanotify_init +.br + RETURN_ALLOW +.br +$ +.TP +\fB\-\-seccomp.print=pid +Print the seccomp filter for the sandbox specified by process ID. Use \-\-list option to get a list of all active sandboxes. +.br + +.br +Example: +.br +$ firejail \-\-list +.br +10786:netblue:firejail \-\-name=browser firefox +$ firejail \-\-seccomp.print=10786 +.br +SECCOMP Filter: +.br + VALIDATE_ARCHITECTURE +.br + EXAMINE_SYSCAL +.br + BLACKLIST 165 mount +.br + BLACKLIST 166 umount2 +.br + BLACKLIST 101 ptrace +.br + BLACKLIST 246 kexec_load +.br + BLACKLIST 304 open_by_handle_at +.br + BLACKLIST 175 init_module +.br + BLACKLIST 176 delete_module +.br + BLACKLIST 172 iopl +.br + BLACKLIST 173 ioperm +.br + BLACKLIST 167 swapon +.br + BLACKLIST 168 swapoff +.br + BLACKLIST 103 syslog +.br + BLACKLIST 310 process_vm_readv +.br + BLACKLIST 311 process_vm_writev +.br + BLACKLIST 133 mknod +.br + BLACKLIST 139 sysfs +.br + BLACKLIST 156 _sysctl +.br + BLACKLIST 159 adjtimex +.br + BLACKLIST 305 clock_adjtime +.br + BLACKLIST 212 lookup_dcookie +.br + BLACKLIST 298 perf_event_open +.br + BLACKLIST 300 fanotify_init +.br + RETURN_ALLOW +.br +$ +.TP +\fB\-\-shell=none +Run the program directly, without a user shell. +.br + +.br +Example: +.br +$ firejail \-\-shell=none script.sh +.TP +\fB\-\-shell=program +Set default user shell. Use this shell to run the application using \-c shell option. +For example "firejail \-\-shell=/bin/dash firefox" will start Mozilla Firefox as "/bin/dash \-c firefox". +By default Bash shell (/bin/bash) is used. Options such as \-\-zsh and \-\-csh can also set the default +shell. +.br + +.br +Example: +$firejail \-\-shell=/bin/dash script.sh +.TP +\fB\-\-shutdown=name +Shutdown the sandbox started using \-\-name option. +.br + +.br +Example: +.br +$ firejail \-\-name=mygame \-\-caps.drop=all warzone2100 & +.br +[...] +.br +$ firejail \-\-shutdown=mygame +.TP +\fB\-\-shutdown=pid +Shutdown the sandbox specified by process ID. Use \-\-list option to get a list of all active sandboxes. +.br + +.br +Example: +.br +$ firejail \-\-list +.br +3272:netblue:firejail \-\-private firefox +.br +$ firejail \-\-shutdown=3272 +.TP +\fB\-\-tmpfs=dirname +Mount a tmpfs filesystem on directory dirname. +.br + +.br +Example: +.br +$ firejail \-\-tmpfs=/var +.TP +\fB\-\-top +Monitor the most CPU-intensive sandboxes, see MONITORING section for more details. +.br + +.br +Example: +.br +$ firejail \-\-top +.TP +\fB\-\-trace +Trace open, access and connect system calls. +.br + +.br +Example: +.br +$ firejail \-\-trace wget -q www.debian.org +.br +Parent pid 11793, child pid 11794 +.br +Child process initialized +.br +1:bash:open /dev/tty +.br +1:wget:fopen64 /etc/wgetrc +.br +1:wget:fopen /etc/hosts +.br +1:wget:socket AF_INET SOCK_DGRAM IPPROTO_IP +.br +1:wget:connect 8.8.8.8:53 +.br +1:wget:socket AF_INET SOCK_STREAM IPPROTO_IP +.br +1:wget:connect 140.211.15.34:80 +.br +1:wget:fopen64 index.html.1 +.br + +.br +parent is shutting down, bye... +.TP +\fB\-\-tree +Print a tree of all sandboxed processes, see MONITORING section for more details. +.br + +.br +Example: +.br +$ firejail \-\-tree +.br +11903:netblue:firejail iceweasel +.br + 11904:netblue:iceweasel +.br + 11957:netblue:/usr/lib/iceweasel/plugin-container +.br +11969:netblue:firejail \-\-net=eth0 transmission-gtk +.br + 11970:netblue:transmission-gtk +.TP +\fB\-\-version +Print program version and exit. +.br + +.br +Example: +.br +$ firejail \-\-version +.br +firejail version 0.9.27 +.TP +\fB\-\-zsh +Use /usr/bin/zsh as default user shell. +.br + +.br +Example: +.br +$ firejakil \-\-zsh +.SH TRAFFIC SHAPING +Network bandwidth is an expensive resource shared among all sandboxes running on a system. +Traffic shaping allows the user to increase network performance by controlling +the amount of data that flows into and out of the sandboxes. + +Firejail implements a simple rate-limiting shaper based on Linux command tc. +The shaper works at sandbox level, and can be used only for sandboxes configured with new network namespaces. + +Set rate-limits: + + firejail --bandwidth={name|pid} set network download upload + +Clear rate-limits: + + firejail --bandwidth={name|pid} clear network + +Status: + + firejail --bandwidth={name|pid} status + +where: +.br + name - sandbox name +.br + pid - sandbox pid +.br + network - network interface as used by \-\-net option +.br + download - download speed in KB/s (kilobyte per second) +.br + upload - upload speed in KB/s (kilobyte per second) + +Example: +.br + $ firejail \-\-name=mybrowser \-\-net=eth0 firefox & +.br + $ firejail \-\-bandwidth=mybrowser set eth0 80 20 +.br + $ firejail \-\-bandwidth=mybrowser status +.br + $ firejail \-\-bandwidth=mybrowser clear eth0 + +.SH MONITORING +Option \-\-list prints a list of all sandboxes. The format +for each process entry is as follows: + + PID:USER:Command + +Option \-\-tree prints the tree of processes running in the sandbox. The format +for each process entry is as follows: + + PID:USER:Command + +Option \-\-top is similar to the UNIX top command, however it applies only to +sandboxes. + +Option \-\-netstats prints network statistics for active sandboxes installing new network namespaces. + + +Listed below are the available fields (columns) in alphabetical +order for \-\-top and \-\-netstat options: + +.TP +Command +Command used to start the sandbox. +.TP +CPU% +CPU usage, the sandbox share of the elapsed CPU time since the +last screen update +.TP +PID +Unique process ID for the task controlling the sandbox. +.TP +Prcs +Number of processes running in sandbox, including the controlling process. +.TP +RES +Resident Memory Size (KiB), sandbox non-swapped physical memory. +It is a sum of the RES values for all processes running in the sandbox. +.TP +RX(KB/s) +Network receive speed. +.TP +SHR +Shared Memory Size (KiB), it reflects memory shared with other +processes. It is a sum of the SHR values for all processes running +in the sandbox, including the controlling process. +.TP +TX(KB/s) +Network transmit speed. +.TP +Uptime +Sandbox running time in hours:minutes:seconds format. +.TP +User +The owner of the sandbox. + +.SH PROFILES +Several command line configuration options can be passed to the program using +profile files. Firejail supports user specified profile files and automatic profile files, +as follows: + +1. Load a specific profile file from a full path, or a path relative to the current directory. +Example: +.PP +.RS +$ firejail --profile=/home/netblue/icecat.profile icecat +.RE + +2. Load a default profile file automatically from ~/.config/firejail or from /etc/firejail, based +on the name of the executable started in the sandbox. Example: +.PP +.RS +$ firejail icecat +.br +Command name #icecat# +.br +.br +Found icecat profile in /home/netblue/.config/firejail directory +.br +Reading profile /home/netblue/.config/firejail/icecat.profile +.br +[...] +.RE + +See man 5 firejail-profile for profile file syntax information. + +.SH RESTRICTED SHELL +To configure a restricted shell, replace /bin/bash with /usr/bin/firejail in +/etc/password file for each user that needs to be restricted. Alternatively, +you can specify /usr/bin/firejail in adduser command: + +adduser \-\-shell /usr/bin/firejail username + +Additional arguments passed to firejail executable upon login are declared in /etc/firejail/login.users file. + +.SH EXAMPLES +.TP +\f\firejail +Start a regular /bin/bash session in sandbox. +.TP +\f\firejail firefox +Start Mozilla Firefox. +.TP +\f\firejail \-\-seccomp firefox +Start Mozilla Firefox in a seccomp sandbox. +.TP +\f\firejail \-\-caps firefox +Start Mozilla Firefox in a Linux capabilities sandbox. +.TP +\f\firejail \-\-debug firefox +Debug Firefox sandbox. +.TP +\f\firejail \-\-private +Start a /bin/bash session with a new tmpfs home directory. +.TP +\f\firejail \-\-net=br0 ip=10.10.20.10 +Start a /bin/bash session in a new network namespace. The session is +connected to the main network using br0 bridge device. An IP address +of 10.10.20.10 is assigned to the sandbox. +.TP +\f\firejail \-\-net=br0 \-\-net=br1 \-\-net=br2 +Start a /bin/bash session in a new network namespace and connect it +to br0, br1, and br2 host bridge devices. +.TP +\f\firejail \-\-list +List all sandboxed processes. +.SH LICENSE +This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. +.PP +Homepage: http://firejail.sourceforge.net +.SH SEE ALSO +\&\flfiremon\fR\|(1), +\&\flfirejail-profile\fR\|(5), +\&\flfirejail-login\fR\|(5) + + + diff --git a/src/man/firemon.txt b/src/man/firemon.txt new file mode 100644 index 00000000000..b6010f46e2c --- /dev/null +++ b/src/man/firemon.txt @@ -0,0 +1,107 @@ +.TH man 1 "MONTH YEAR" "VERSION" "firemon man page" +.SH NAME +Firemon \- Monitoring program for processes started in a Firejail sandbox. +.SH SYNOPSIS +firemon [OPTIONS] [PID] +.SH DESCRIPTION +Firemon monitors programs started in a Firejail sandbox. +Without a PID specified, all processes started by Firejail are monitored. Descendants of +these processes are also being monitored. +.SH OPTIONS +.TP +\fB\-\-arp +Print ARP table for each sandbox. +.TP +\fB\-\-caps +Print capabilities configuration for each sandbox. +.TP +\fB\-\-cgroup +Print control group information for each sandbox. +.TP +\fB\-\-cpu +Print CPU affinity for each sandbox. +.TP +\fB\-?\fR, \fB\-\-help\fR +Print options end exit. +.TP +\fB\-\-interface +Print network interface information for each sandbox. +.TP +\fB\-\-list +List all sandboxes. +.TP +\fB\-\-name=name +Print information only about named sandbox. +.TP +\fB\-\-netstats +Monitor network statistics for sandboxes creating a new network namespace. +.TP +\fB\-\-route +Print route table for each sandbox. +.TP +\fB\-\-seccomp +Print seccomp configuration for each sandbox. +.TP +\fB\-\-top +Monitor the most CPU-intensive sandboxes. +.TP +\fB\-\-tree +Print a tree of all sandboxed processes. +.TP +\fB\-\-version +Print program version and exit. + +.PP +Option \-\-list prints a list of all sandboxes. The format +for each entry is as follows: + + PID:USER:Command + +Option \-\-tree prints the tree of processes running in the sandbox. The format +for each process entry is as follows: + + PID:USER:Command + +Option \-\-top is similar to the UNIX top command, however it applies only to +sandboxes. Listed below are the available fields (columns) in alphabetical +order: + +.TP +Command +Command used to start the sandbox. +.TP +CPU% +CPU usage, the sandbox share of the elapsed CPU time since the +last screen update +.TP +PID +Unique process ID for the task controlling the sandbox. +.TP +Prcs +Number of processes running in sandbox, including the controlling process. +.TP +RES +Resident Memory Size (KiB), sandbox non-swapped physical memory. +It is a sum of the RES values for all processes running in the sandbox. +.TP +SHR +Shared Memory Size (KiB), it reflects memory shared with other +processes. It is a sum of the SHR values for all processes running +in the sandbox, including the controlling process. +.TP +Uptime +Sandbox running time in hours:minutes:seconds format. +.TP +User +The owner of the sandbox. + +.SH LICENSE +This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. +.PP +Homepage: http://firejail.sourceforge.net +.SH SEE ALSO +\&\flfirejail\fR\|(1), +\&\flfirejail-profile\fR\|(5), +\&\flfirejail-login\fR\|(5) + + diff --git a/src/tools/check-caps.sh b/src/tools/check-caps.sh new file mode 100755 index 00000000000..13525677be0 --- /dev/null +++ b/src/tools/check-caps.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +if [ $# -eq 0 ] +then + echo "Usage: check-caps.sh program-and-arguments" + echo +fi + +set -x + +firejail --caps.drop=chown "$1" +firejail --caps.drop=dac_override "$1" +firejail --caps.drop=dac_read_search "$1" +firejail --caps.drop=fowner "$1" +firejail --caps.drop=fsetid "$1" +firejail --caps.drop=kill "$1" +firejail --caps.drop=setgid "$1" +firejail --caps.drop=setuid "$1" +firejail --caps.drop=setpcap "$1" +firejail --caps.drop=linux_immutable "$1" +firejail --caps.drop=net_bind_service "$1" +firejail --caps.drop=net_broadcast "$1" +firejail --caps.drop=net_admin "$1" +firejail --caps.drop=net_raw "$1" +firejail --caps.drop=ipc_lock "$1" +firejail --caps.drop=ipc_owner "$1" +firejail --caps.drop=sys_module "$1" +firejail --caps.drop=sys_rawio "$1" +firejail --caps.drop=sys_chroot "$1" +firejail --caps.drop=sys_ptrace "$1" +firejail --caps.drop=sys_pacct "$1" +firejail --caps.drop=sys_admin "$1" +firejail --caps.drop=sys_boot "$1" +firejail --caps.drop=sys_nice "$1" +firejail --caps.drop=sys_resource "$1" +firejail --caps.drop=sys_time "$1" +firejail --caps.drop=sys_tty_config "$1" +firejail --caps.drop=mknod "$1" +firejail --caps.drop=lease "$1" +firejail --caps.drop=audit_write "$1" +firejail --caps.drop=audit_control "$1" +firejail --caps.drop=setfcap "$1" +firejail --caps.drop=mac_override "$1" +firejail --caps.drop=mac_admin "$1" +firejail --caps.drop=syslog "$1" +firejail --caps.drop=wake_alarm "$1" diff --git a/src/tools/extract_caps.c b/src/tools/extract_caps.c new file mode 100644 index 00000000000..94a062ccb86 --- /dev/null +++ b/src/tools/extract_caps.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include +#include + +#define BUFMAX 4096 + +int main(int argc, char **argv) { + if (argc != 2) { + printf("usage: %s /usr/include/linux/capability.h\n", argv[0]); + return 1; + } + + //open file + FILE *fp = fopen(argv[1], "r"); + if (!fp) { + fprintf(stderr, "Error: cannot open file\n"); + return 1; + } + + // read file + char buf[BUFMAX]; + while (fgets(buf, BUFMAX, fp)) { + // cleanup + char *start = buf; + while (*start == ' ' || *start == '\t') + start++; + char *end = strchr(start, '\n'); + if (end) + *end = '\0'; + + // parsing + if (strncmp(start, "#define CAP_", 12) == 0) { + if (strstr(start, "CAP_LAST_CAP")) + break; + + char *ptr1 = start + 8; + char *ptr2 = ptr1; + while (*ptr2 == ' ' || *ptr2 == '\t') + ptr2++; + while (*ptr2 != ' ' && *ptr2 != '\t') + ptr2++; + *ptr2 = '\0'; + + ptr2 = strdup(ptr1); + assert(ptr2); + ptr2 += 4; + char *ptr3 = ptr2; + while (*ptr3 != '\0') { + *ptr3 = tolower(*ptr3); + ptr3++; + } + + + printf("#ifdef %s\n", ptr1); + printf("\t{\"%s\", %s },\n", ptr2, ptr1); + printf("#endif\n"); + + } + + } + fclose(fp); + return 0; +} diff --git a/src/tools/extract_syscalls.c b/src/tools/extract_syscalls.c new file mode 100644 index 00000000000..0e064a49e6e --- /dev/null +++ b/src/tools/extract_syscalls.c @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include 6 +#include + +#define BUFMAX 4096 + +int main(int argc, char **argv) { + if (argc != 2) { + printf("usage: %s /media/ubuntu/usr/include/x86_64-linux-gnu/bits/syscall.h\n", argv[0]); + return 1; + } + + //open file + FILE *fp = fopen(argv[1], "r"); + if (!fp) { + fprintf(stderr, "Error: cannot open file\n"); + return 1; + } + + // read file + char buf[BUFMAX]; + while (fgets(buf, BUFMAX, fp)) { + // cleanup + char *start = buf; + while (*start == ' ' || *start == '\t') + start++; + char *end = strchr(start, '\n'); + if (end) + *end = '\0'; + + // parsing + if (strncmp(start, "#endif", 6) == 0) + printf("%s\n", start); + if (strncmp(start, "#endif", 6) == 0) + printf("%s\n", start); + else if (strncmp(start, "#if", 3) == 0) + printf("%s\n", start); + else if (strncmp(start, "#define", 7) == 0) { + // extract data + char *ptr1 = strstr(start, "SYS_"); + char *ptr2 = strstr(start, "__NR_"); + if (!ptr1 || !ptr2) { + fprintf(stderr, "Error: cannot parse \"%s\"\n", start); + fclose(fp); + return 1; + } + *(ptr2 - 1) = '\0'; + + char *ptr3 = ptr1; + while (*ptr3 != ' ' && *ptr3 != '\t' && *ptr3 != '\0') + ptr3++; + *ptr3 = '\0'; + ptr3 = ptr2; + while (*ptr3 != ' ' && *ptr3 != '\t' && *ptr3 != '\0') + ptr3++; + *ptr3 = '\0'; + + ptr3 = ptr1; + while (*ptr3 != '_') + ptr3++; + ptr3++; + + printf("#ifdef %s\n", ptr1); + printf("#ifdef %s\n", ptr2); + printf("\t{\"%s\", %s},\n", ptr3, ptr2); + printf("#endif\n"); + printf("#endif\n"); + } + } + fclose(fp); + return 0; +} diff --git a/src/tools/mkcoverit.sh b/src/tools/mkcoverit.sh new file mode 100755 index 00000000000..4af84a7a1e0 --- /dev/null +++ b/src/tools/mkcoverit.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +# unpack firejail archive +ARCFIREJAIL=`ls *.tar.bz2| grep firejail` +if [ "$?" -eq 0 ]; +then + echo "preparing $ARCFIREJAIL" + DIRFIREJAIL=`basename $ARCFIREJAIL .tar.bz2` + rm -fr $DIRFIREJAIL + tar -xjvf $ARCFIREJAIL + cd $DIRFIREJAIL + ./configure --prefix=/usr + cd .. +else + echo "Error: firejail source archive missing" + exit 1 +fi + + +# unpack firetools archive +ARCFIRETOOLS=`ls *.tar.bz2 | grep firetools` +if [ "$?" -eq 0 ]; +then + echo "preparing $ARCFIRETOOLS" + DIRFIRETOOLS=`basename $ARCFIRETOOLS .tar.bz2` + rm -fr $DIRFIRETOOLS + tar -xjvf $ARCFIRETOOLS + cd $DIRFIRETOOLS + pwd + ./configure --prefix=/usr + cd .. + +else + echo "Error: firetools source archive missing" + exit 1 +fi + +# move firetools in firejail source tree +mkdir -p $DIRFIREJAIL/extras +mv $DIRFIRETOOLS $DIRFIREJAIL/extras/firetools + +# build +cd $DIRFIREJAIL +cov-build --dir cov-int make -j 4 extras +tar czvf myproject.tgz cov-int diff --git a/src/tools/rvtest.c b/src/tools/rvtest.c new file mode 100644 index 00000000000..95050e67101 --- /dev/null +++ b/src/tools/rvtest.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com) + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +// run it as "rvtest 2>/dev/null | grep TESTING" + +#include +#include +#include +#include +#include +#include + +#define MAXBUF 1024 // line buffer +#define TIMEOUT 30 // timeout time in seconds + +static pid_t pid; +static void catch_alarm(int sig) { + kill(pid, SIGTERM); + sleep(1); + kill(pid, SIGKILL); + printf("TESTING ERROR: SIGALARM triggered\n"); + exit(1); +} + +static void usage(void) { + printf("Usage: rvtest testfile\n"); + printf("\n"); + printf("Testfile format:\n"); + printf("\tretval command\n"); + printf("\n"); + printf("Testfile example:\n"); + printf("\n"); + printf("0 firejail --net=none exit\n"); + printf("1 firejail --private=/etc sleep 1\n"); + printf("1 firejail --blablabla\n"); +} + +int main(int argc, char **argv) { + if (argc != 2) { + fprintf(stderr, "Error: test file missing\n"); + usage(); + return 1; + } + + signal (SIGALRM, catch_alarm); + + // open test file + char *fname = argv[1]; + FILE *fp = fopen(fname, "r"); + + // read test file + char buf[MAXBUF]; + int line = 0; + while (fgets(buf, MAXBUF, fp)) { + line++; + // skip blanks + char *start = buf; + while (*start == ' ' || *start == '\t') + start++; + // remove '\n' + char *ptr = strchr(start, '\n'); + if (ptr) + *ptr ='\0'; + if (*start == '\0') + continue; + + // skip comments + if (*start == '#') + continue; + ptr = strchr(start, '#'); + if (ptr) + *ptr = '\0'; + + // extract exit status + int status; + int rv = sscanf(start, "%d\n", &status); + if (rv != 1) { + fprintf(stderr, "Error: invalid line %d in %s\n", line, fname); + exit(1); + } + + // extract command + char *cmd = strchr(start, ' '); + if (!cmd) { + fprintf(stderr, "Error: invalid line %d in %s\n", line, fname); + exit(1); + } + + // execute command + printf("TESTING %s\n", cmd); + fflush(0); + pid = fork(); + if (pid == -1) { + perror("fork"); + exit(1); + } + + // child + if (pid == 0) { + char *earg[50]; + earg[0] = "/bin/bash"; + earg[1] = "-c"; + earg[2] = cmd; + earg[3] = NULL; + execvp(earg[0], earg); + } + // parent + else { + int exit_status; + + alarm(TIMEOUT); + pid = waitpid(pid, &exit_status, 0); + if (pid == -1) { + perror("waitpid"); + exit(1); + } + + if (WEXITSTATUS(exit_status) != status) + printf("ERROR TESTING: %s\n", cmd); + } + + fflush(0); + } + fclose(fp); + + return 0; +} \ No newline at end of file diff --git a/src/tools/ttytest.c b/src/tools/ttytest.c new file mode 100644 index 00000000000..a449bf9ba3e --- /dev/null +++ b/src/tools/ttytest.c @@ -0,0 +1,36 @@ +#define _XOPEN_SOURCE 600 +#include +#include +#include +#include + +int main(void) { + int fdm; + int rc; + + // initial + system("ls -l /dev/pts"); + + fdm = posix_openpt(O_RDWR); + if (fdm < 0) { + perror("posix_openpt"); + return 1; + } + + rc = grantpt(fdm); + if (rc != 0) { + perror("grantpt"); + return 1; + } + + rc = unlockpt(fdm); + if (rc != 0) { + perror("unlockpt"); + return 1; + } + + // final + system("ls -l /dev/pts"); + + return 0; +} diff --git a/test/4bridges_arp.exp b/test/4bridges_arp.exp new file mode 100755 index 00000000000..3004082e6d6 --- /dev/null +++ b/test/4bridges_arp.exp @@ -0,0 +1,175 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# check eth0 +send -- "firejail --net=br0 --net=br1 --net=br2 --net=br3\r" +expect { + timeout {puts "TESTING ERROR 0.0\n";exit} + "eth0" +} +expect { + timeout {puts "TESTING ERROR 0.1\n";exit} + "10.10.20" +} +expect { + timeout {puts "TESTING ERROR 0.2\n";exit} + "255.255.255.248" +} +expect { + timeout {puts "TESTING ERROR 0.3\n";exit} + "UP" +} +expect { + timeout {puts "TESTING ERROR 0.4\n";exit} + "Child process initialized" +} +sleep 2 +send -- "exit\r" +sleep 2 + +# check eth1 +send -- "firejail --net=br0 --net=br1 --net=br2 --net=br3\r" +expect { + timeout {puts "TESTING ERROR 1.0\n";exit} + "eth1" +} +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + "10.10.30" +} +expect { + timeout {puts "TESTING ERROR 1.2\n";exit} + "255.255.255.0" +} +expect { + timeout {puts "TESTING ERROR 1.3\n";exit} + "UP" +} +expect { + timeout {puts "TESTING ERROR 1.4\n";exit} + "Child process initialized" +} +sleep 2 +send -- "exit\r" +sleep 2 + + +# check eth2 +send -- "firejail --net=br0 --net=br1 --net=br2 --net=br3\r" +expect { + timeout {puts "TESTING ERROR 2.0\n";exit} + "eth2" +} +expect { + timeout {puts "TESTING ERROR 2.1\n";exit} + "10.10.40" +} +expect { + timeout {puts "TESTING ERROR 2.2\n";exit} + "255.255.255.0" +} +expect { + timeout {puts "TESTING ERROR 2.3\n";exit} + "UP" +} +expect { + timeout {puts "TESTING ERROR 2.4\n";exit} + "Child process initialized" +} +sleep 2 +send -- "exit\r" +sleep 2 + + + +# check eth3 +send -- "firejail --net=br0 --net=br1 --net=br2 --net=br3\r" +expect { + timeout {puts "TESTING ERROR 3.0\n";exit} + "eth3" +} +expect { + timeout {puts "TESTING ERROR 3.1\n";exit} + "10.10.50" +} +expect { + timeout {puts "TESTING ERROR 3.2\n";exit} + "255.255.255.0" +} +expect { + timeout {puts "TESTING ERROR 3.3\n";exit} + "UP" +} +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} +sleep 2 +send -- "exit\r" +sleep 2 + + + + +# check loopback +send -- "firejail --net=br0 --net=br1 --net=br2 --net=br3\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + "lo" +} +expect { + timeout {puts "TESTING ERROR 6\n";exit} + "127.0.0.1" +} +expect { + timeout {puts "TESTING ERROR 7\n";exit} + "255.0.0.0" +} +expect { + timeout {puts "TESTING ERROR 8\n";exit} + "UP" +} +expect { + timeout {puts "TESTING ERROR 9\n";exit} + "Child process initialized" +} + +# check default gateway +send -- "bash\r" +sleep 1 +send -- "netstat -rn;pwd\r" +expect { + timeout {puts "TESTING ERROR 10.1\n";exit} + "0.0.0.0" +} +expect { + timeout {puts "TESTING ERROR 10.2\n";exit} + "10.10.20.1" +} +expect { + timeout {puts "TESTING ERROR 10.3\n";exit} + "eth0" +} +expect { + timeout {puts "TESTING ERROR 10.4\n";exit} + "10.10.20.0" +} +expect { + timeout {puts "TESTING ERROR 10.5\n";exit} + "0.0.0.0" +} +expect { + timeout {puts "TESTING ERROR 10.6\n";exit} + "eth0" +} +expect { + timeout {puts "TESTING ERROR 10\n";exit} + "home" +} +sleep 1 + +puts "\n" + diff --git a/test/4bridges_ip.exp b/test/4bridges_ip.exp new file mode 100755 index 00000000000..9e37b4ff47a --- /dev/null +++ b/test/4bridges_ip.exp @@ -0,0 +1,175 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# check eth0 +send -- "firejail --net=br0 --net=br1 --ip=10.10.30.50 --net=br2 --ip=10.10.40.100 --net=br3\r" +expect { + timeout {puts "TESTING ERROR 0.0\n";exit} + "eth0" +} +expect { + timeout {puts "TESTING ERROR 0.1\n";exit} + "10.10.20" +} +expect { + timeout {puts "TESTING ERROR 0.2\n";exit} + "255.255.255.248" +} +expect { + timeout {puts "TESTING ERROR 0.3\n";exit} + "UP" +} +expect { + timeout {puts "TESTING ERROR 0.4\n";exit} + "Child process initialized" +} +sleep 2 +send -- "exit\r" +sleep 2 + +# check eth1 +send -- "firejail --net=br0 --net=br1 --ip=10.10.30.50 --net=br2 --ip=10.10.40.100 --net=br3\r" +expect { + timeout {puts "TESTING ERROR 1.0\n";exit} + "eth1" +} +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + "10.10.30.50" +} +expect { + timeout {puts "TESTING ERROR 1.2\n";exit} + "255.255.255.0" +} +expect { + timeout {puts "TESTING ERROR 1.3\n";exit} + "UP" +} +expect { + timeout {puts "TESTING ERROR 1.4\n";exit} + "Child process initialized" +} +sleep 2 +send -- "exit\r" +sleep 2 + + +# check eth2 +send -- "firejail --net=br0 --net=br1 --ip=10.10.30.50 --net=br2 --ip=10.10.40.100 --net=br3\r" +expect { + timeout {puts "TESTING ERROR 2.0\n";exit} + "eth2" +} +expect { + timeout {puts "TESTING ERROR 2.1\n";exit} + "10.10.40.100" +} +expect { + timeout {puts "TESTING ERROR 2.2\n";exit} + "255.255.255.0" +} +expect { + timeout {puts "TESTING ERROR 2.3\n";exit} + "UP" +} +expect { + timeout {puts "TESTING ERROR 2.4\n";exit} + "Child process initialized" +} +sleep 2 +send -- "exit\r" +sleep 2 + + + +# check eth3 +send -- "firejail --net=br0 --net=br1 --ip=10.10.30.50 --net=br2 --ip=10.10.40.100 --net=br3\r" +expect { + timeout {puts "TESTING ERROR 3.0\n";exit} + "eth3" +} +expect { + timeout {puts "TESTING ERROR 3.1\n";exit} + "10.10.50" +} +expect { + timeout {puts "TESTING ERROR 3.2\n";exit} + "255.255.255.0" +} +expect { + timeout {puts "TESTING ERROR 3.3\n";exit} + "UP" +} +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} +sleep 2 +send -- "exit\r" +sleep 2 + + + + +# check loopback +send -- "firejail --net=br0 --net=br1 --ip=10.10.30.50 --net=br2 --ip=10.10.40.100 --net=br3\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + "lo" +} +expect { + timeout {puts "TESTING ERROR 6\n";exit} + "127.0.0.1" +} +expect { + timeout {puts "TESTING ERROR 7\n";exit} + "255.0.0.0" +} +expect { + timeout {puts "TESTING ERROR 8\n";exit} + "UP" +} +expect { + timeout {puts "TESTING ERROR 9\n";exit} + "Child process initialized" +} + +# check default gateway +send -- "bash\r" +sleep 1 +send -- "netstat -rn;pwd\r" +expect { + timeout {puts "TESTING ERROR 10.1\n";exit} + "0.0.0.0" +} +expect { + timeout {puts "TESTING ERROR 10.2\n";exit} + "10.10.20.1" +} +expect { + timeout {puts "TESTING ERROR 10.3\n";exit} + "eth0" +} +expect { + timeout {puts "TESTING ERROR 10.4\n";exit} + "10.10.20.0" +} +expect { + timeout {puts "TESTING ERROR 10.5\n";exit} + "0.0.0.0" +} +expect { + timeout {puts "TESTING ERROR 10.6\n";exit} + "eth0" +} +expect { + timeout {puts "TESTING ERROR 10\n";exit} + "home" +} +sleep 1 + +puts "\n" + diff --git a/test/auto/autotest.sh b/test/auto/autotest.sh new file mode 100755 index 00000000000..0fb7565af6e --- /dev/null +++ b/test/auto/autotest.sh @@ -0,0 +1,202 @@ +#!/bin/bash + +arr[1]="TEST 1: svn and standard compilation" +arr[2]="TEST 2: cppcheck" +arr[3]="TEST 3: compile seccomp disabled, chroot disabled, bind disabled" +arr[4]="TEST 4: rvtest" +arr[5]="TEST 5: expect test as root, no malloc perturb" +arr[6]="TEST 6: expect test as user, no malloc perturb" +arr[7]="TEST 7: expect test as root, malloc perturb" +arr[8]="TEST 8: expect test as user, malloc perturb" + + +# remove previous reports and output file +cleanup() { + rm -f out-test + rm -f output* + rm -f report* + rm -fr firejail-trunk +} + +print_title() { + echo + echo + echo + echo "**************************************************" + echo $1 + echo "**************************************************" +} + +while [ $# -gt 0 ]; do # Until you run out of parameters . . . + case "$1" in + --clean) + cleanup + exit + ;; + --help) + echo "./autotest.sh [--clean|--help]" + exit + ;; + esac + shift # Check next set of parameters. +done + +cleanup +# enable sudo +sudo ls -al + +#***************************************************************** +# TEST 1 +#***************************************************************** +# - checkout source code +# - check compilation +# - install +#***************************************************************** +print_title "${arr[1]}" +svn checkout svn://svn.code.sf.net/p/firejail/code-0/trunk firejail-trunk +cd firejail-trunk +./configure --prefix=/usr 2>&1 | tee ../output-configure +make -j4 2>&1 | tee ../output-make +sudo make install 2>&1 | tee ../output-install +cd src/tools +gcc -o rvtest rvtest.c +cd ../.. +cd test +sudo ./configure > /dev/null +cd ../.. +grep warning output-configure output-make output-install > ./report-test1 +grep error output-configure output-make output-install >> ./report-test1 +cat report-test1 > out-test1 + +#***************************************************************** +# TEST 2 +#***************************************************************** +# - run cppcheck +#***************************************************************** +print_title "${arr[2]}" +cd firejail-trunk +cp /home/netblue/bin/cfg/std.cfg . +cppcheck --force . 2>&1 | tee ../output-cppcheck +cd .. +grep error output-cppcheck > report-test2 +cat report-test2 > out-test2 + +#***************************************************************** +# TEST 3 +#***************************************************************** +# - disable seccomp configuration +# - check compilation +#***************************************************************** +print_title "${arr[3]}" +# seccomp +cd firejail-trunk +make distclean +./configure --prefix=/usr --disable-seccomp 2>&1 | tee ../output-configure-noseccomp +make -j4 2>&1 | tee ../output-make-noseccomp +cd .. +grep warning output-configure-noseccomp output-make-noseccomp > ./report-test3 +grep error output-configure-noseccomp output-make-noseccomp >> ./report-test3 +# chroot +cd firejail-trunk +make distclean +./configure --prefix=/usr --disable-chroot 2>&1 | tee ../output-configure-nochroot +make -j4 2>&1 | tee ../output-make-nochroot +cd .. +grep warning output-configure-nochroot output-make-nochroot >> ./report-test3 +grep error output-configure-nochroot output-make-nochroot >> ./report-test3 +# bind +cd firejail-trunk +make distclean +./configure --prefix=/usr --disable-bind 2>&1 | tee ../output-configure-nobind +make -j4 2>&1 | tee ../output-make-nobind +cd .. +grep warning output-configure-nobind output-make-nobind >> ./report-test3 +grep error output-configure-nobind output-make-nobind >> ./report-test3 +# save result +cat report-test3 > out-test3 + +#***************************************************************** +# TEST 4 +#***************************************************************** +# - rvtest +#***************************************************************** +print_title "${arr[4]}" +cd firejail-trunk +cd test +../src/tools/rvtest test.rv 2>/dev/null | tee ../../output-test4 | grep TESTING +cd ../.. +grep TESTING output-test4 > ./report-test4 +grep ERROR report-test4 > out-test4 + + +#***************************************************************** +# TEST 5 +#***************************************************************** +# - expect test as root, no malloc perturb +#***************************************************************** +print_title "${arr[5]}" +cd firejail-trunk/test +sudo ./test-root.sh 2>&1 | tee ../../output-test5 | grep TESTING +cd ../.. +grep TESTING output-test5 > ./report-test5 +grep ERROR report-test5 > out-test5 + +#***************************************************************** +# TEST 6 +#***************************************************************** +# - expect test as user, no malloc perturb +#***************************************************************** +print_title "${arr[6]}" +cd firejail-trunk/test +./test.sh 2>&1 | tee ../../output-test6 | grep TESTING +cd ../.. +grep TESTING output-test6 > ./report-test6 +grep ERROR report-test6 > out-test6 + + + +#***************************************************************** +# TEST 7 +#***************************************************************** +# - expect test as root, malloc perturb +#***************************************************************** +print_title "${arr[7]}" +export MALLOC_CHECK_=3 +export MALLOC_PERTURB_=$(($RANDOM % 255 + 1)) +cd firejail-trunk/test +sudo ./test-root.sh 2>&1 | tee ../../output-test7 | grep TESTING +cd ../.. +grep TESTING output-test7 > ./report-test7 +grep ERROR report-test7 > out-test7 + +#***************************************************************** +# TEST 8 +#***************************************************************** +# - expect test as user, malloc perturb +#***************************************************************** +print_title "${arr[8]}" +cd firejail-trunk/test +./test.sh 2>&1 | tee ../../output-test8| grep TESTING +cd ../.. +grep TESTING output-test8 > ./report-test8 +grep ERROR report-test8 > out-test8 + +#***************************************************************** +# PRINT REPORTS +#***************************************************************** +echo +echo +echo +echo +echo "**********************************************************" +echo "TEST RESULTS" +echo "**********************************************************" + +wc -l out-test* +rm out-test* +echo + + + + +exit diff --git a/test/caps1.profile b/test/caps1.profile new file mode 100644 index 00000000000..e14655b2e93 --- /dev/null +++ b/test/caps1.profile @@ -0,0 +1 @@ +caps.drop chown,kill \ No newline at end of file diff --git a/test/caps2.profile b/test/caps2.profile new file mode 100644 index 00000000000..cb2258c52ae --- /dev/null +++ b/test/caps2.profile @@ -0,0 +1 @@ +caps.keep chown,kill \ No newline at end of file diff --git a/test/chk_config.exp b/test/chk_config.exp new file mode 100755 index 00000000000..ada59d6551e --- /dev/null +++ b/test/chk_config.exp @@ -0,0 +1,86 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# check br0 +send -- "/sbin/ifconfig;pwd\r" +expect { + timeout {puts "TESTING ERROR 0 - please run ./configure\n";exit} + "br0" +} +expect { + timeout {puts "TESTING ERROR 0 - please run ./configure\n";exit} + "10.10.20.1" +} +expect { + timeout {puts "TESTING ERROR 0 - please run ./configure\n";exit} + "home" +} + +# check br1 +send -- "/sbin/ifconfig;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "br1" +} +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "10.10.30.1" +} +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "home" +} + +# check br2 +send -- "/sbin/ifconfig;pwd\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "br2" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "10.10.40.1" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "home" +} + +# check br3 +send -- "/sbin/ifconfig;pwd\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "br3" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "10.10.50.1" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "home" +} + +# start a sandbox and check MALLOC_PERTURB +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} +sleep 1 + +set timeout 2 +send -- "env | grep MALLOC;pwd\r" +expect { + timeout {puts "\nTESTING: MALLOC_PERTURB_ disabled\n"} + "MALLOC_PERTURB_" {puts "\nTESTING: MALLOC_PERTURB_ enabled\n"} +} +expect { + timeout {puts "TESTING ERROR 5\n";exit} + "home" +} + + diff --git a/test/chromium.exp b/test/chromium.exp new file mode 100755 index 00000000000..020826f3dd8 --- /dev/null +++ b/test/chromium.exp @@ -0,0 +1,72 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail chromium-browser www.gentoo.org\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Reading profile /etc/firejail/chromium-browser.profile" +} +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +sleep 10 + +spawn $env(SHELL) +send -- "firejail --list\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + ":firejail" +} +expect { + timeout {puts "TESTING ERROR 3.1\n";exit} + "chromium-browser" +} +sleep 1 + +send -- "firejail --name=blablabla\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} +sleep 2 + +spawn $env(SHELL) +send -- "firemon --seccomp\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + ":firejail chromium-browser" +} +expect { + timeout {puts "TESTING ERROR 5.1\n";exit} + "Seccomp: 0" +} +expect { + timeout {puts "TESTING ERROR 5.1\n";exit} + "name=blablabla" +} +sleep 1 +send -- "firemon --caps\r" +expect { + timeout {puts "TESTING ERROR 6\n";exit} + ":firejail chromium-browser" +} +expect { + timeout {puts "TESTING ERROR 6.1\n";exit} + "CapBnd:" +} +expect { + timeout {puts "TESTING ERROR 6.2\n";exit} + "fffffffff" +} +expect { + timeout {puts "TESTING ERROR 6.3\n";exit} + "name=blablabla" +} +sleep 1 + +puts "\n" + diff --git a/test/configure b/test/configure new file mode 100755 index 00000000000..17bb22e1be2 --- /dev/null +++ b/test/configure @@ -0,0 +1,42 @@ +#!/bin/bash + +brctl addbr br0 +ifconfig br0 10.10.20.1/29 up +# NAT masquerade +iptables -t nat -A POSTROUTING -o eth0 -s 10.10.20.0/29 -j MASQUERADE +# port forwarding +# iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to 10.10.20.2:80 + +brctl addbr br1 +ifconfig br1 10.10.30.1/24 up +brctl addbr br2 +ifconfig br2 10.10.40.1/24 up +brctl addbr br3 +ifconfig br3 10.10.50.1/24 up +brctl addbr br4 +ifconfig br4 10.10.60.1/24 up + + +# build a very small chroot +ROOTDIR="/tmp/chroot" # default chroot directory +DEFAULT_FILES="/bin/bash /bin/sh " # basic chroot files +DEFAULT_FILES+="/etc/passwd /etc/nsswitch.conf /etc/group " +DEFAULT_FILES+=`find /lib -name libnss*` # files required by glibc +DEFAULT_FILES+=" /bin/ls /bin/cat /bin/ps /usr/bin/id /usr/bin/whoami /usr/bin/wc /usr/bin/wget" + +rm -fr $ROOTDIR +mkdir -p $ROOTDIR/{root,bin,lib,lib64,usr,home,etc,dev/shm,tmp,var/run,var/tmp,var/lock,proc} +SORTED=`for FILE in $* $DEFAULT_FILES; do echo " $FILE "; ldd $FILE | grep -v dynamic | cut -d " " -f 3; done | sort -u` +for FILE in $SORTED +do + cp --parents $FILE $ROOTDIR +done +cp --parents /lib64/ld-linux-x86-64.so.2 $ROOTDIR +cp --parents /lib/ld-linux.so.2 $ROOTDIR + +cd $ROOTDIR; find . +mkdir -p usr/lib/firejail/ +cp /usr/lib/firejail/libtrace.so usr/lib/firejail/. + + +echo "To enter the chroot directory run: firejail --chroot=$ROOTDIR" diff --git a/test/dns.exp b/test/dns.exp new file mode 100755 index 00000000000..96513f27889 --- /dev/null +++ b/test/dns.exp @@ -0,0 +1,69 @@ +#!/usr/bin/expect -f + +set timeout 30 +spawn $env(SHELL) +match_max 100000 + +# no chroot +send -- "firejail --trace --dns=208.67.222.222 wget -q debian.org\r" +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + "Child process initialized" +} +expect { + timeout {puts "TESTING ERROR 1.2\n";exit} + "1:wget:connect 208.67.222.222:53" +} +sleep 1 + +send -- "rm index.html\r" +sleep 1 + +# with chroot +send -- "firejail --chroot=/tmp/chroot --trace --dns=208.67.222.222 wget -q debian.org\r" +expect { + timeout {puts "TESTING ERROR 2.1\n";exit} + "Child process initialized" +} +expect { + timeout {puts "TESTING ERROR 2.2\n";exit} + "1:wget:connect 208.67.222.222:53" +} +sleep 1 + +send -- "rm index.html\r" +sleep 1 + +# net eth0 +send -- "firejail --net=eth0 --trace --dns=208.67.222.222 wget -q debian.org\r" +expect { + timeout {puts "TESTING ERROR 3.1\n";exit} + "Child process initialized" +} +expect { + timeout {puts "TESTING ERROR 3.2\n";exit} + "1:wget:connect 208.67.222.222:53" +} +sleep 1 + +send -- "rm index.html\r" +sleep 1 + +# net eth0 and chroot +send -- "firejail --net=eth0 --chroot=/tmp/chroot --trace --dns=208.67.222.222 wget -q debian.org\r" +expect { + timeout {puts "TESTING ERROR 4.1\n";exit} + "Child process initialized" +} +expect { + timeout {puts "TESTING ERROR 4.2\n";exit} + "1:wget:connect 208.67.222.222:53" +} +sleep 1 + +send -- "rm index.html\r" +sleep 1 + + +puts "\n" + diff --git a/test/doubledash.exp b/test/doubledash.exp new file mode 100755 index 00000000000..3c8a424713f --- /dev/null +++ b/test/doubledash.exp @@ -0,0 +1,60 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail -- ls -- -testdir\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "ttt" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "parent is shutting down" +} +sleep 1 + + +send -- "firejail --name=testing -- -testdir/bash\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} +sleep 3 + +spawn $env(SHELL) +send -- "firejail --join=testing -- -testdir/bash\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + "the first child process inside the sandbox" +} +sleep 3 + +spawn $env(SHELL) +send -- "firejail --list;pwd\r" +expect { + timeout {puts "TESTING ERROR 6\n";exit} + "name=testing" +} +expect { + timeout {puts "TESTING ERROR 7\n";exit} + "home" +} +send -- "firejail --list;pwd\r" +expect { + timeout {puts "TESTING ERROR 8 (join)\n";exit} + "join=testing" +} +expect { + timeout {puts "TESTING ERROR 9\n";exit} + "home" +} + +sleep 1 + +puts "\n" diff --git a/test/evince.exp b/test/evince.exp new file mode 100755 index 00000000000..7b115144c06 --- /dev/null +++ b/test/evince.exp @@ -0,0 +1,72 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail evince\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Reading profile /etc/firejail/evince.profile" +} +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +sleep 10 + +spawn $env(SHELL) +send -- "firejail --list\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + ":firejail" +} +expect { + timeout {puts "TESTING ERROR 3.1\n";exit} + "evince" +} +sleep 1 + +send -- "firejail --name=blablabla\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} +sleep 2 + +spawn $env(SHELL) +send -- "firemon --seccomp\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + ":firejail evince" +} +expect { + timeout {puts "TESTING ERROR 5.1 (seccomp)\n";exit} + "Seccomp: 2" +} +expect { + timeout {puts "TESTING ERROR 5.1\n";exit} + "name=blablabla" +} +sleep 1 +send -- "firemon --caps\r" +expect { + timeout {puts "TESTING ERROR 6\n";exit} + ":firejail evince" +} +expect { + timeout {puts "TESTING ERROR 6.1\n";exit} + "CapBnd:" +} +expect { + timeout {puts "TESTING ERROR 6.2\n";exit} + "0000000000000000" +} +expect { + timeout {puts "TESTING ERROR 6.3\n";exit} + "name=blablabla" +} +sleep 1 + +puts "\n" + diff --git a/test/extract_command.exp b/test/extract_command.exp new file mode 100755 index 00000000000..c49614b84b2 --- /dev/null +++ b/test/extract_command.exp @@ -0,0 +1,23 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --debug /usr/bin/firefox www.gentoo.org\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Reading profile /etc/firejail/firefox.profile" +} +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Starting /usr/bin/firefox" +} +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +sleep 5 + +puts "\n" + diff --git a/test/firefox.exp b/test/firefox.exp new file mode 100755 index 00000000000..c2e64e04f84 --- /dev/null +++ b/test/firefox.exp @@ -0,0 +1,74 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail firefox www.gentoo.org\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Reading profile /etc/firejail/firefox.profile" +} +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +sleep 10 + +spawn $env(SHELL) +send -- "firejail --list\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + ":firejail" +} +expect { + timeout {puts "TESTING ERROR 3.1\n";exit} + "firefox" {puts "firefox detected\n";} + "iceweasel" {puts "iceweasel detected\n";} +} +sleep 1 +send -- "firejail --name=blablabla\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} +sleep 2 + +spawn $env(SHELL) +send -- "firemon --seccomp\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + " firefox" {puts "firefox detected\n";} + " iceweasel" {puts "iceweasel detected\n";} +} +expect { + timeout {puts "TESTING ERROR 5.1 (seccomp)\n";exit} + "Seccomp: 2" +} +expect { + timeout {puts "TESTING ERROR 5.1\n";exit} + "name=blablabla" +} +sleep 1 +send -- "firemon --caps\r" +expect { + timeout {puts "TESTING ERROR 6\n";exit} + " firefox" {puts "firefox detected\n";} + " iceweasel" {puts "iceweasel detected\n";} +} +expect { + timeout {puts "TESTING ERROR 6.1\n";exit} + "CapBnd:" +} +expect { + timeout {puts "TESTING ERROR 6.2\n";exit} + "0000000000000000" +} +expect { + timeout {puts "TESTING ERROR 6.3\n";exit} + "name=blablabla" +} +sleep 1 + +puts "\n" + diff --git a/test/firejail-in-firejail.exp b/test/firejail-in-firejail.exp new file mode 100755 index 00000000000..404eb03bb46 --- /dev/null +++ b/test/firejail-in-firejail.exp @@ -0,0 +1,37 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +sleep 1 +puts "\n" + +send -- "exit\r" +sleep 1 +send -- "exit\r" +sleep 1 +send -- "exit\r" +sleep 1 + + +puts "\n" diff --git a/test/firemon-arp.exp b/test/firemon-arp.exp new file mode 100755 index 00000000000..3fc8c2aeeb7 --- /dev/null +++ b/test/firemon-arp.exp @@ -0,0 +1,34 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "ping -c 3 192.168.1.1\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "3 packets transmitted" +} +sleep 1 + +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +sleep 1 + +spawn $env(SHELL) +send -- "firemon --arp\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "192.168.1.1 dev eth0 lladdr" {puts "Debian testing\n";} + "192.168.1.1 dev enp0s3 lladdr" {puts "Centos 7 testing\n";} +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "REACHABLE" +} +sleep 1 + +puts "\n" diff --git a/test/firemon-caps.exp b/test/firemon-caps.exp new file mode 100755 index 00000000000..547d04c0222 --- /dev/null +++ b/test/firemon-caps.exp @@ -0,0 +1,135 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --name=bingo1 --caps\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +spawn $env(SHELL) +send -- "firejail --name=bingo2\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +spawn $env(SHELL) +send -- "firejail --name=bingo3 --caps.drop=all\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +spawn $env(SHELL) +send -- "firejail --name=bingo4 --caps.drop=chown,kill\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +spawn $env(SHELL) +send -- "firejail --name=bingo5 --caps.keep=chown,kill\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +spawn $env(SHELL) +send -- "firejail --name=bingo6 --profile=caps1.profile\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +spawn $env(SHELL) +send -- "firejail --name=bingo7 --profile=caps2.profile\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + + + + +spawn $env(SHELL) +send -- "firemon --caps\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "bingo1" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "31cffff" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "bingo2" +} +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "fffffff" +} +expect { + timeout {puts "TESTING ERROR 5\n";exit} + "bingo3" +} +expect { + timeout {puts "TESTING ERROR 6\n";exit} + "000000000000" +} + +expect { + timeout {puts "TESTING ERROR 7\n";exit} + "bingo4" +} +expect { + timeout {puts "TESTING ERROR 8\n";exit} + "ffffffde" +} +expect { + timeout {puts "TESTING ERROR 7\n";exit} + "bingo5" +} +expect { + timeout {puts "TESTING ERROR 9\n";exit} + "0000000000000021" +} + +expect { + timeout {puts "TESTING ERROR 10\n";exit} + "bingo6" +} +expect { + timeout {puts "TESTING ERROR 11\n";exit} + "ffffffde" +} +expect { + timeout {puts "TESTING ERROR 12\n";exit} + "bingo7" +} +expect { + timeout {puts "TESTING ERROR 13\n";exit} + "0000000000000021" +} + + + + + + + +sleep 1 + +puts "\n" + diff --git a/test/firemon-cgroup.exp b/test/firemon-cgroup.exp new file mode 100755 index 00000000000..41a38b3b6cc --- /dev/null +++ b/test/firemon-cgroup.exp @@ -0,0 +1,40 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --name=bingo1 --cgroup=/sys/fs/cgroup/g1/tasks\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +spawn $env(SHELL) +send -- "firejail --name=bingo2\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + + +spawn $env(SHELL) +send -- "firemon --cgroup\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "bingo1" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + ":/g1" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "bingo2" +} +sleep 1 + +puts "\n" + diff --git a/test/firemon-interface.exp b/test/firemon-interface.exp new file mode 100755 index 00000000000..6a82ae41ec8 --- /dev/null +++ b/test/firemon-interface.exp @@ -0,0 +1,34 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +spawn $env(SHELL) +send -- "firemon --interface\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "lo UP" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "10.10.20.1/29" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "10.10.50.1/24" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "br3" +} +sleep 1 + +puts "\n" diff --git a/test/firemon-route.exp b/test/firemon-route.exp new file mode 100755 index 00000000000..76ebd70f618 --- /dev/null +++ b/test/firemon-route.exp @@ -0,0 +1,32 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +spawn $env(SHELL) +send -- "firemon --route\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "0.0.0.0/0 via 192.168.1.1, dev eth0, metric 0" {puts "Debian testing\n";} + "0.0.0.0/0 via 192.168.1.1, dev enp0s3, metric 1024" {puts "Centos 7 testing\n";} + "0.0.0.0/0 via 192.168.1.1, dev enp0s3, metric 0" {puts "OpenSUSE testing\n";} +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "10.10.30.0/24, dev br1, scope link src 10.10.30.1" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "10.10.50.0/24, dev br3, scope link src 10.10.50.1" +} +sleep 1 + +puts "\n" diff --git a/test/firemon-seccomp.exp b/test/firemon-seccomp.exp new file mode 100755 index 00000000000..0cf53b690b4 --- /dev/null +++ b/test/firemon-seccomp.exp @@ -0,0 +1,45 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --name=bingo1 --seccomp\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +spawn $env(SHELL) +send -- "firejail --name=bingo2\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + + + + +spawn $env(SHELL) +send -- "firemon --seccomp\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "bingo1" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Seccomp: 2" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "bingo2" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "Seccomp: 0" +} +sleep 1 + +puts "\n" diff --git a/test/fs_chroot.exp b/test/fs_chroot.exp new file mode 100755 index 00000000000..ba832337bb8 --- /dev/null +++ b/test/fs_chroot.exp @@ -0,0 +1,54 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --chroot=/tmp/chroot\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "cd /home;pwd\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "home" +} +sleep 1 +send -- "bash\r" +sleep 1 +send -- "ps aux; pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "/bin/bash" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "bash" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "ps aux" +} +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "home" +} +sleep 1 + + +send -- "ps aux |wc -l; pwd\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + "5" +} +expect { + timeout {puts "TESTING ERROR 6\n";exit} + "home" +} +sleep 1 + +puts "\n" + diff --git a/test/fs_dev_shm.exp b/test/fs_dev_shm.exp new file mode 100755 index 00000000000..b54f24eb52f --- /dev/null +++ b/test/fs_dev_shm.exp @@ -0,0 +1,87 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# testing read-write /dev/shm +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "echo mytest > /dev/shm/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "home" +} + +send -- "cat /dev/shm/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 2.1\n";exit} + "mytest" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "home" +} + +send -- "rm /dev/shm/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "home" +} + +send -- "cat /dev/shm/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "mytest" {puts "TESTING ERROR 4.1\n";exit} + "home" +} + +sleep 1 +send -- "exit\r" +sleep 1 + +# redo the test with --private +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 10\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "echo mytest > /dev/shm/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 11\n";exit} + "home" +} + +send -- "cat /dev/shm/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 12.1\n";exit} + "mytest" +} +expect { + timeout {puts "TESTING ERROR 12\n";exit} + "home" +} + +send -- "rm /dev/shm/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 13\n";exit} + "home" +} + +send -- "cat /dev/shm/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 14\n";exit} + "mytest" {puts "TESTING ERROR 14.1\n";exit} + "home" +} + +sleep 1 + +puts "\n" diff --git a/test/fs_home_sanitize.exp b/test/fs_home_sanitize.exp new file mode 100755 index 00000000000..300babd1c3a --- /dev/null +++ b/test/fs_home_sanitize.exp @@ -0,0 +1,33 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "ls /home;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "bingo" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "home" +} +sleep 1 + +send -- "ls /home/bingo;pwd\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "cannot open directory" +} +sleep 1 + +puts "\n" + diff --git a/test/fs_overlay.exp b/test/fs_overlay.exp new file mode 100755 index 00000000000..166970a5c0e --- /dev/null +++ b/test/fs_overlay.exp @@ -0,0 +1,64 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "rm -f /tmp/firejail-overlay-test;pwd\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "home" +} + +send -- "ls > /tmp/firejail-overlay-test;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "home" +} + +send -- "firejail --overlay\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "echo xyzxyzxyz > /tmp/firejail-overlay-test;pwd\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "home" +} +sleep 1 + +send -- "cat /tmp/firejail-overlay-test;pwd\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "xyzxyzxyz" +} +expect { + timeout {puts "TESTING ERROR 4.1\n";exit} + "home" +} +sleep 1 + +send -- "exit\r" +sleep 2 + +send -- "cat /tmp/firejail-overlay-test;pwd\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + "xyzxyzxyz" {puts "TESTING ERROR 5.1\n";exit} + "home" +} + +sleep 1 +send -- "rm -f /tmp/firejail-overlay-test;pwd\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "home" +} + + +sleep 1 +puts "\n" + diff --git a/test/fs_sys.exp b/test/fs_sys.exp new file mode 100755 index 00000000000..69f0804604e --- /dev/null +++ b/test/fs_sys.exp @@ -0,0 +1,34 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --net=br0\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "find /sys | grep --color=never eth0;pwd\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "/sys/class/net/eth0" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "home" +} +sleep 1 + +send -- "find /sys | grep --color=never br0;pwd\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "/sys/class/net/br0" {puts "TESTING ERROR 5\n";exit} + "home" +} +sleep 1 + +puts "\n" + diff --git a/test/fs_var_lock.exp b/test/fs_var_lock.exp new file mode 100755 index 00000000000..dfcf571f42a --- /dev/null +++ b/test/fs_var_lock.exp @@ -0,0 +1,87 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# testing read-write /var/lock +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "echo mytest > /var/lock/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "home" +} + +send -- "cat /var/lock/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 2.1\n";exit} + "mytest" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "home" +} + +send -- "rm /var/lock/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "home" +} + +send -- "cat /var/lock/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "mytest" {puts "TESTING ERROR 4.1\n";exit} + "home" +} + +sleep 1 +send -- "exit\r" +sleep 1 + +# redo the test with --private +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 10\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "echo mytest > /var/lock/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 11\n";exit} + "home" +} + +send -- "cat /var/lock/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 12.1\n";exit} + "mytest" +} +expect { + timeout {puts "TESTING ERROR 12\n";exit} + "home" +} + +send -- "rm /var/lock/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 13\n";exit} + "home" +} + +send -- "cat /var/lock/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 14\n";exit} + "mytest" {puts "TESTING ERROR 14.1\n";exit} + "home" +} + +sleep 1 + +puts "\n" diff --git a/test/fs_var_tmp.exp b/test/fs_var_tmp.exp new file mode 100755 index 00000000000..95ceeb2a4b0 --- /dev/null +++ b/test/fs_var_tmp.exp @@ -0,0 +1,87 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# testing read-write /var/tmp +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "echo mytest > /var/tmp/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "home" +} + +send -- "cat /var/tmp/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 2.1\n";exit} + "mytest" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "home" +} + +send -- "rm /var/tmp/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "home" +} + +send -- "cat /var/tmp/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "mytest" {puts "TESTING ERROR 4.1\n";exit} + "home" +} + +sleep 1 +send -- "exit\r" +sleep 1 + +# redo the test with --private +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 10\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "echo mytest > /var/tmp/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 11\n";exit} + "home" +} + +send -- "cat /var/tmp/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 12.1\n";exit} + "mytest" +} +expect { + timeout {puts "TESTING ERROR 12\n";exit} + "home" +} + +send -- "rm /var/tmp/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 13\n";exit} + "home" +} + +send -- "cat /var/tmp/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 14\n";exit} + "mytest" {puts "TESTING ERROR 14.1\n";exit} + "home" +} + +sleep 1 + +puts "\n" diff --git a/test/fscheck-bindnoroot.exp b/test/fscheck-bindnoroot.exp new file mode 100755 index 00000000000..796a7d9756e --- /dev/null +++ b/test/fscheck-bindnoroot.exp @@ -0,0 +1,14 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# dir +send -- "firejail --net=br0 --bind=fscheck-dir,/etc\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Error" +} +after 100 + diff --git a/test/fscheck-blacklist.exp b/test/fscheck-blacklist.exp new file mode 100755 index 00000000000..5b6a9623c86 --- /dev/null +++ b/test/fscheck-blacklist.exp @@ -0,0 +1,14 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# dir +send -- "firejail --net=br0 --blacklist=../test/fscheck-dir\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Error" +} +after 100 + diff --git a/test/fscheck-chroot.exp b/test/fscheck-chroot.exp new file mode 100755 index 00000000000..208ca6a4393 --- /dev/null +++ b/test/fscheck-chroot.exp @@ -0,0 +1,77 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# dir +#send -- "firejail --net=br0 --chroot=fscheck-dir\r" +#expect { +# timeout {puts "TESTING ERROR 0\n";exit} +# "Error" +#} +#after 100 + +# .. +send -- "firejail --net=br0 --chroot=../test/fscheck-dir\r" +expect { + timeout {puts "TESTING ERROR 0.1\n";exit} + "Error" +} +after 100 + +# dir link +send -- "firejail --net=br0 --chroot=fscheck-dir-link\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Error" +} +after 100 + +# .. +send -- "firejail --net=br0 --chroot=../test/fscheck-dir-link\r" +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + "Error" +} +after 100 + +# file link +send -- "firejail --net=br0 --chroot=fscheck-file-link\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Error" +} +after 100 + +# file +send -- "firejail --net=br0 --chroot=fscheck-file\r" +expect { + timeout {puts "TESTING ERROR 2.1\n";exit} + "Error" +} +after 100 + +# .. +send -- "firejail --net=br0 --chroot=../test/fscheck-file\r" +expect { + timeout {puts "TESTING ERROR 2.2\n";exit} + "Error" +} +after 100 + +# no file +send -- "firejail --net=br0 --chroot=../test/nodir\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "Error" +} +after 100 + +# same owner +#send -- "firejail --net=br0 --chroot=/etc\r" +#expect { +# timeout {puts "TESTING ERROR 4\n";exit} +# "Error" +#} +#after 100 diff --git a/test/fscheck-netfilter.exp b/test/fscheck-netfilter.exp new file mode 100755 index 00000000000..d2339c8b952 --- /dev/null +++ b/test/fscheck-netfilter.exp @@ -0,0 +1,69 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# dir +send -- "firejail --net=br0 --netfilter=fscheck-dir\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Error" +} +after 100 + +# .. +send -- "firejail --net=br0 --netfilter=../test/fscheck-dir\r" +expect { + timeout {puts "TESTING ERROR 0.1\n";exit} + "Error" +} +after 100 + +# dir link +send -- "firejail --net=br0 --netfilter=fscheck-dir-link\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Error" +} +after 100 + +# .. +send -- "firejail --net=br0 --netfilter=../test/fscheck-dir-link\r" +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + "Error" +} +after 100 + +# file link +send -- "firejail --net=br0 --netfilter=fscheck-file-link\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Error" +} +after 100 + +# .. +send -- "firejail --net=br0 --netfilter=../test/fscheck-file-link\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Error" +} +after 100 + +# no file +send -- "firejail --net=br0 --netfilter=../test/nofile\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "Error" +} +after 100 + +# real GID/UID +send -- "firejail --net=br0 --netfilter=/etc/shadow\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Error" +} +after 100 diff --git a/test/fscheck-output.exp b/test/fscheck-output.exp new file mode 100755 index 00000000000..0b444d6ba6d --- /dev/null +++ b/test/fscheck-output.exp @@ -0,0 +1,104 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# dir +send -- "firejail --net=br0 --output=fscheck-dir\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Error" +} +after 100 + +# .. +send -- "firejail --net=br0 --output=../test/fscheck-dir\r" +expect { + timeout {puts "TESTING ERROR 0.1\n";exit} + "Error" +} +after 100 + +# dir link +send -- "firejail --net=br0 --output=fscheck-dir-link\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Error" +} +after 100 + +# .. +send -- "firejail --net=br0 --output=../test/fscheck-dir-link\r" +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + "Error" +} +after 100 + +# file link +send -- "firejail --net=br0 --output=fscheck-file-link\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Error" +} +after 100 + +# .. +send -- "firejail --net=br0 --output=../test/fscheck-file-link\r" +expect { + timeout {puts "TESTING ERROR 2.1\n";exit} + "Error" +} +after 100 + +# hard link1 +send -- "firejail --net=br0 --output=fscheck-file-hard1\r" +expect { + timeout {puts "TESTING ERROR 2.2\n";exit} + "Error" +} +after 100 + +# hard link2 +send -- "firejail --net=br0 --output=fscheck-file-hard2\r" +expect { + timeout {puts "TESTING ERROR 2.3\n";exit} + "Error" +} +after 100 + +# .. +send -- "firejail --net=br0 --output=../test/fscheck-file-hard1\r" +expect { + timeout {puts "TESTING ERROR 2.4\n";exit} + "Error" +} +after 100 + +# .. +send -- "firejail --net=br0 --output=../test/fscheck-file-hard2\r" +expect { + timeout {puts "TESTING ERROR 2.5\n";exit} + "Error" +} +after 100 + + + + +# no file +send -- "firejail --net=br0 --output=../test/nofile\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "Error" +} +after 100 + +# real GID/UID +send -- "firejail --net=br0 --output=/etc/shadow\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Error" +} +after 100 diff --git a/test/fscheck-private.exp b/test/fscheck-private.exp new file mode 100755 index 00000000000..4c791423da4 --- /dev/null +++ b/test/fscheck-private.exp @@ -0,0 +1,77 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# dir +#send -- "firejail --net=br0 --private=fscheck-dir\r" +#expect { +# timeout {puts "TESTING ERROR 0\n";exit} +# "Error" +#} +#after 100 + +# .. +send -- "firejail --net=br0 --private=../test/fscheck-dir\r" +expect { + timeout {puts "TESTING ERROR 0.1\n";exit} + "Error" +} +after 100 + +# dir link +send -- "firejail --net=br0 --private=fscheck-dir-link\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Error" +} +after 100 + +# .. +send -- "firejail --net=br0 --private=../test/fscheck-dir-link\r" +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + "Error" +} +after 100 + +# file link +send -- "firejail --net=br0 --private=fscheck-file-link\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Error" +} +after 100 + +# file +send -- "firejail --net=br0 --private=fscheck-file\r" +expect { + timeout {puts "TESTING ERROR 2.1\n";exit} + "Error" +} +after 100 + +# .. +send -- "firejail --net=br0 --private=../test/fscheck-file\r" +expect { + timeout {puts "TESTING ERROR 2.2\n";exit} + "Error" +} +after 100 + +# no file +send -- "firejail --net=br0 --private=../test/nodir\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "Error" +} +after 100 + +# same owner +send -- "firejail --net=br0 --private=/etc\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Error" +} +after 100 diff --git a/test/fscheck-privatekeep.exp b/test/fscheck-privatekeep.exp new file mode 100755 index 00000000000..513dcc37acd --- /dev/null +++ b/test/fscheck-privatekeep.exp @@ -0,0 +1,93 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# dir +#send -- "firejail --net=br0 --private.keep=fscheck-dir\r" +#expect { +# timeout {puts "TESTING ERROR 0\n";exit} +# "Error" +#} +#after 100 + +# .. +send -- "firejail --net=br0 --private.keep=../test/fscheck-dir\r" +expect { + timeout {puts "TESTING ERROR 0.1\n";exit} + "Error" +} +after 100 + +# dir link +send -- "firejail --net=br0 --private.keep=fscheck-dir-link\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Error" +} +after 100 + +# .. +send -- "firejail --net=br0 --private.keep=../test/fscheck-dir-link\r" +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + "Error" +} +after 100 + +# file link +send -- "firejail --net=br0 --private.keep=fscheck-file-link\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Error" +} +after 100 + +# file +#send -- "firejail --net=br0 --private.keep=fscheck-file\r" +#expect { +# timeout {puts "TESTING ERROR 2.1\n";exit} +# "Error" +#} +#after 100 + +# .. +send -- "firejail --net=br0 --private.keep=../test/fscheck-file\r" +expect { + timeout {puts "TESTING ERROR 2.2\n";exit} + "Error" +} +after 100 + +# no dir +send -- "firejail --net=br0 --private.keep=../test/nodir\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "Error" +} +after 100 + +# no file +send -- "firejail --net=br0 --private.keep=../test/nofile\r" +expect { + timeout {puts "TESTING ERROR 3.1\n";exit} + "Error" +} +after 100 + +# same owner +send -- "firejail --net=br0 --private=/etc\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Error" +} +after 100 + +# same owner +send -- "firejail --net=br0 --private=/etc/shadow\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Error" +} +after 100 diff --git a/test/fscheck-profile.exp b/test/fscheck-profile.exp new file mode 100755 index 00000000000..d7d7c7cd1f7 --- /dev/null +++ b/test/fscheck-profile.exp @@ -0,0 +1,69 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# dir +send -- "firejail --net=br0 --profile=fscheck-dir\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Error" +} +after 100 + +# .. +send -- "firejail --net=br0 --profile=../test/fscheck-dir\r" +expect { + timeout {puts "TESTING ERROR 0.1\n";exit} + "Error" +} +after 100 + +# dir link +send -- "firejail --net=br0 --profile=fscheck-dir-link\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Error" +} +after 100 + +# .. +send -- "firejail --net=br0 --profile=../test/fscheck-dir-link\r" +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + "Error" +} +after 100 + +# file link +send -- "firejail --net=br0 --profile=fscheck-file-link\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Error" +} +after 100 + +# .. +send -- "firejail --net=br0 --profile=../test/fscheck-file-link\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Error" +} +after 100 + +# no file +send -- "firejail --net=br0 --profile=../test/nofile\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "Error" +} +after 100 + +# real GID/UID +send -- "firejail --net=br0 --profile=/etc/shadow\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Error" +} +after 100 diff --git a/test/fscheck-readonly.exp b/test/fscheck-readonly.exp new file mode 100755 index 00000000000..e0f0a8a1d00 --- /dev/null +++ b/test/fscheck-readonly.exp @@ -0,0 +1,14 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# dir +send -- "firejail --net=br0 --read-only=../test/fscheck-dir\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Error" +} +after 100 + diff --git a/test/fscheck-shell.exp b/test/fscheck-shell.exp new file mode 100755 index 00000000000..d2320a4c330 --- /dev/null +++ b/test/fscheck-shell.exp @@ -0,0 +1,69 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# dir +send -- "firejail --net=br0 --shell=fscheck-dir\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Error" +} +after 100 + +# .. +send -- "firejail --net=br0 --shell=../test/fscheck-dir\r" +expect { + timeout {puts "TESTING ERROR 0.1\n";exit} + "Error" +} +after 100 + +# dir link +send -- "firejail --net=br0 --shell=fscheck-dir-link\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Error" +} +after 100 + +# .. +send -- "firejail --net=br0 --shell=../test/fscheck-dir-link\r" +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + "Error" +} +after 100 + +# file link +send -- "firejail --net=br0 --shell=fscheck-file-link\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Error" +} +after 100 + +# .. +send -- "firejail --net=br0 --shell=../test/fscheck-file-link\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Error" +} +after 100 + +# no file +send -- "firejail --net=br0 --shell=../test/nofile\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "Error" +} +after 100 + +# real GID/UID +send -- "firejail --net=br0 --shell=/etc/shadow\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Error" +} +after 100 diff --git a/test/fscheck-tmpfs.exp b/test/fscheck-tmpfs.exp new file mode 100755 index 00000000000..d5bbccd96ad --- /dev/null +++ b/test/fscheck-tmpfs.exp @@ -0,0 +1,14 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# .. +send -- "firejail --net=br0 --tmpfs=../test/fscheck-dir\r" +expect { + timeout {puts "TESTING ERROR 0.1\n";exit} + "Error" +} +after 100 + diff --git a/test/fscheck.sh b/test/fscheck.sh new file mode 100755 index 00000000000..25756d5be3c --- /dev/null +++ b/test/fscheck.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +mkdir fscheck-dir +ln -s fscheck-dir fscheck-dir-link +touch fscheck-file +ln -s fscheck-file fscheck-file-link +touch fscheck-file-hard1 +ln fscheck-file-hard1 fscheck-file-hard2 + +echo "TESTING: fscheck netfilter" +./fscheck-netfilter.exp +echo "TESTING: fscheck shell" +./fscheck-shell.exp +echo "TESTING: fscheck private" +./fscheck-private.exp +echo "TESTING: fscheck private keep" +./fscheck-privatekeep.exp +echo "TESTING: fscheck profile" +./fscheck-profile.exp +echo "TESTING: fscheck chroot" +./fscheck-chroot.exp +echo "TESTING: fscheck output" +./fscheck-output.exp +echo "TESTING: fscheck bind nonroot" +./fscheck-bindnoroot.exp +echo "TESTING: fscheck tmpfs" +./fscheck-tmpfs.exp +echo "TESTING: fscheck readonly" +./fscheck-readonly.exp +echo "TESTING: fscheck blacklist" +./fscheck-blacklist.exp + + +rm -fr fscheck-dir +rm -fr fscheck-dir-link +rm -fr fscheck-file-link +rm -fr fscheck-file +rm -fr fscheck-file-hard1 +rm -fr fscheck-file-hard2 diff --git a/test/login_ssh.exp b/test/login_ssh.exp new file mode 100755 index 00000000000..dff6dc655f0 --- /dev/null +++ b/test/login_ssh.exp @@ -0,0 +1,59 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "ssh bingo@0\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "password:" { + puts "\nTESTING: please enter SSH password" + set oldmode [stty -echo -raw] + expect_user -re "(.*)\n" + send_user "\n" + eval stty $oldmode +# stty echo + set pass $expect_out(1,string) + send -- "$pass\r" + puts "TESTING: password sent to the server" + } + "Child process initialized" +} +sleep 1 + +# test default gw +send -- "bash\r" +sleep 1 +send -- "ps aux; pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "/bin/bash" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "bash" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "ps aux" +} +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "home" +} +sleep 1 + + +send -- "ps aux |wc -l; pwd\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + "5" +} +expect { + timeout {puts "TESTING ERROR 6\n";exit} + "home" +} +sleep 1 + +puts "\n" diff --git a/test/midori.exp b/test/midori.exp new file mode 100755 index 00000000000..ec33816ddbb --- /dev/null +++ b/test/midori.exp @@ -0,0 +1,73 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail midori www.gentoo.org\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Reading profile /etc/firejail/midori.profile" +} +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +sleep 10 + +spawn $env(SHELL) +send -- "firejail --list\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + ":firejail" +} +expect { + timeout {puts "TESTING ERROR 3.1\n";exit} + "midori" +} +sleep 1 + +send -- "firejail --name=blablabla\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} +sleep 2 + +spawn $env(SHELL) +send -- "firemon --seccomp\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + ":firejail midori" +} +expect { + timeout {puts "TESTING ERROR 5.1 (seccomp)\n";exit} + "Seccomp: 2" +} +expect { + timeout {puts "TESTING ERROR 5.1\n";exit} + "name=blablabla" +} +sleep 1 +send -- "firemon --caps\r" +expect { + timeout {puts "TESTING ERROR 6\n";exit} + ":firejail midori" +} +expect { + timeout {puts "TESTING ERROR 6.1\n";exit} + "CapBnd" +} +expect { + timeout {puts "TESTING ERROR 6.2\n";exit} + "0000000000000000" +} +expect { + timeout {puts "TESTING ERROR 6.3n";exit} + "name=blablabla" +} +sleep 1 + + +puts "\n" + diff --git a/test/name.exp b/test/name.exp new file mode 100755 index 00000000000..704b8315e22 --- /dev/null +++ b/test/name.exp @@ -0,0 +1,25 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --name=baluba\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "ping -c 3 baluba;pwd\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "3 packets transmitted, 3 received" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "home" +} +sleep 1 + +puts "\n" diff --git a/test/net_arp.exp b/test/net_arp.exp new file mode 100755 index 00000000000..9e07744f3d0 --- /dev/null +++ b/test/net_arp.exp @@ -0,0 +1,71 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --net=br0 sleep 20 &\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +send -- "firejail --net=br0 sleep 20 &\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +send -- "firejail --net=br0 sleep 20 &\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Child process initialized" +} +send -- "firejail --net=br0 sleep 20 &\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "Child process initialized" +} +send -- "firejail --net=br0 sleep 20 &\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} + +# will fail +send -- "firejail --net=br0 sleep 20 &\r" +expect { + timeout {puts "TESTING ERROR 5n";exit} + "cannot assign an IP address" +} + +send -- "firejail --net=br0 sleep 20 &\r" +expect { + timeout {puts "TESTING ERROR 6\n";exit} + "cannot assign an IP address" +} + +# check firejail --list +send -- "firejail --list\r" +expect { + timeout {puts "TESTING ERROR 7.1\n";exit} + "sleep 20" +} +expect { + timeout {puts "TESTING ERROR 7.2\n";exit} + "sleep 20" +} +expect { + timeout {puts "TESTING ERROR 7.3\n";exit} + "sleep 20" +} +expect { + timeout {puts "TESTING ERROR 7.4\n";exit} + "sleep 20" +} +expect { + timeout {puts "TESTING ERROR 7.5\n";exit} + "sleep 20" +} + +# wait for snadboxes to be shutdown +sleep 30 +puts "\n" diff --git a/test/net_badip.exp b/test/net_badip.exp new file mode 100755 index 00000000000..71b69e10414 --- /dev/null +++ b/test/net_badip.exp @@ -0,0 +1,16 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# check eth0 +send -- "firejail --net=br0 --net=br1 --ip=10.100.10.47\r" +expect { + timeout {puts "TESTING ERROR 0.0\n";exit} + "the IP address is not" +} +sleep 1 + +puts "\n" + diff --git a/test/net_defaultgw.exp b/test/net_defaultgw.exp new file mode 100755 index 00000000000..9820660b7cf --- /dev/null +++ b/test/net_defaultgw.exp @@ -0,0 +1,65 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# check ip address +send -- "firejail --net=br0 --ip=10.10.20.5 --defaultgw=10.10.20.2\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "eth0" +} +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "10.10.20.5" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "255.255.255.248" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "UP" +} +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} + +# check default gateway +send -- "bash\r" +sleep 1 +send -- "netstat -rn;pwd\r" +expect { + timeout {puts "TESTING ERROR 10.1\n";exit} + "0.0.0.0" +} +expect { + timeout {puts "TESTING ERROR 10.2\n";exit} + "10.10.20.2" +} +expect { + timeout {puts "TESTING ERROR 10.3\n";exit} + "eth0" +} +expect { + timeout {puts "TESTING ERROR 10.4\n";exit} + "10.10.20.0" +} +expect { + timeout {puts "TESTING ERROR 10.5\n";exit} + "0.0.0.0" +} +expect { + timeout {puts "TESTING ERROR 10.6\n";exit} + "eth0" +} +expect { + timeout {puts "TESTING ERROR 10\n";exit} + "home" +} +sleep 1 + +puts "\n" + diff --git a/test/net_defaultgw2.exp b/test/net_defaultgw2.exp new file mode 100755 index 00000000000..be9b4882adc --- /dev/null +++ b/test/net_defaultgw2.exp @@ -0,0 +1,65 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# check ip address +send -- "firejail --net=br0 --net=br1 --defaultgw=10.10.30.89\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "eth1" +} +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} + +# check default gateway +send -- "bash\r" +sleep 1 +send -- "netstat -rn;pwd\r" +expect { + timeout {puts "TESTING ERROR 10.1\n";exit} + "0.0.0.0" +} +expect { + timeout {puts "TESTING ERROR 10.2\n";exit} + "10.10.30.89" +} +expect { + timeout {puts "TESTING ERROR 10.3\n";exit} + "eth1" +} +expect { + timeout {puts "TESTING ERROR 10.4\n";exit} + "10.10.20.0" +} +expect { + timeout {puts "TESTING ERROR 10.5\n";exit} + "0.0.0.0" +} +expect { + timeout {puts "TESTING ERROR 10.6\n";exit} + "eth0" +} +expect { + timeout {puts "TESTING ERROR 10.4\n";exit} + "10.10.30.0" +} +expect { + timeout {puts "TESTING ERROR 10.5\n";exit} + "0.0.0.0" +} +expect { + timeout {puts "TESTING ERROR 10.6\n";exit} + "eth1" +} +expect { + timeout {puts "TESTING ERROR 10\n";exit} + "home" +} +sleep 1 + +puts "\n" + diff --git a/test/net_defaultgw3.exp b/test/net_defaultgw3.exp new file mode 100755 index 00000000000..64da9dfca15 --- /dev/null +++ b/test/net_defaultgw3.exp @@ -0,0 +1,17 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# check ip address +send -- "firejail --net=br0 --net=br1 --defaultgw=10.10.95.89\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "default gateway 10.10.95.89 is not in the range of any network" +} + +sleep 1 + +puts "\n" + diff --git a/test/net_ip.exp b/test/net_ip.exp new file mode 100755 index 00000000000..5995296c7f8 --- /dev/null +++ b/test/net_ip.exp @@ -0,0 +1,91 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# check ip address +send -- "firejail --net=br0 --ip=10.10.20.5\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "eth0" +} +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "10.10.20.5" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "255.255.255.248" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "UP" +} +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} +sleep 2 +send -- "exit\r" +sleep 2 + +# check loopback +send -- "firejail --net=br0 --ip=10.10.20.5\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + "lo" +} +expect { + timeout {puts "TESTING ERROR 6\n";exit} + "127.0.0.1" +} +expect { + timeout {puts "TESTING ERROR 7\n";exit} + "255.0.0.0" +} +expect { + timeout {puts "TESTING ERROR 8\n";exit} + "UP" +} +expect { + timeout {puts "TESTING ERROR 9\n";exit} + "Child process initialized" +} + +# check default gateway +send -- "bash\r" +sleep 1 +send -- "netstat -rn;pwd\r" +expect { + timeout {puts "TESTING ERROR 10.1\n";exit} + "0.0.0.0" +} +expect { + timeout {puts "TESTING ERROR 10.2\n";exit} + "10.10.20.1" +} +expect { + timeout {puts "TESTING ERROR 10.3\n";exit} + "eth0" +} +expect { + timeout {puts "TESTING ERROR 10.4\n";exit} + "10.10.20.0" +} +expect { + timeout {puts "TESTING ERROR 10.5\n";exit} + "0.0.0.0" +} +expect { + timeout {puts "TESTING ERROR 10.6\n";exit} + "eth0" +} +expect { + timeout {puts "TESTING ERROR 10\n";exit} + "home" +} +sleep 1 + +puts "\n" + diff --git a/test/net_local.exp b/test/net_local.exp new file mode 100755 index 00000000000..9302ec4ef22 --- /dev/null +++ b/test/net_local.exp @@ -0,0 +1,49 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# check ip address +send -- "firejail --debug\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Using the local network stack" +} +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} +sleep 2 +send -- "exit\r" +sleep 2 + +# check loopback +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 9\n";exit} + "Child process initialized" +} +sleep 1 + + +send -- "/sbin/ifconfig\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + "lo" +} +expect { + timeout {puts "TESTING ERROR 6\n";exit} + "127.0.0.1" +} +expect { + timeout {puts "TESTING ERROR 7\n";exit} + "255.0.0.0" +} +expect { + timeout {puts "TESTING ERROR 8\n";exit} + "UP" +} + +puts "\n" + diff --git a/test/net_mac.exp b/test/net_mac.exp new file mode 100755 index 00000000000..555d86b74fd --- /dev/null +++ b/test/net_mac.exp @@ -0,0 +1,36 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# check ip address +send -- "firejail --net=br0 --ip=10.10.20.5 --mac=00:11:22:33:44:55\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "eth0" +} +expect { + timeout {puts "TESTING ERROR 0.1\n";exit} + "00:11:22:33:44:55" +} +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "10.10.20.5" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "255.255.255.248" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "UP" +} +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} +sleep 1 + +puts "\n" + diff --git a/test/net_macvlan.exp b/test/net_macvlan.exp new file mode 100755 index 00000000000..20d022de942 --- /dev/null +++ b/test/net_macvlan.exp @@ -0,0 +1,88 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# check the existing address +spawn $env(SHELL) +send -- "firejail --net=eth0 --ip=192.168.1.60\r" +expect { + timeout {puts "TESTING ERROR 1.1\n";puts "Please open a sandbox on 192.168.1.60\n";exit} + "the address 192.168.1.60 is already in use" +} + + + +# grab 30 ip addresses +set MAXi 229 +set i 200 +while { $i <= $MAXi } { + spawn $env(SHELL) + send -- "firejail --net=eth0 --ip=192.168.1.$i\r" + expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" + } + incr i + after 100 +} + + +# check an existing address +spawn $env(SHELL) +send -- "firejail --net=eth0 --ip=192.168.1.200\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "the address 192.168.1.200 is already in use" +} + + +set MAXi 254 +set i 2 +while { $i <= $MAXi } { + spawn $env(SHELL) + send -- "firejail --net=eth0\r" + expect { + timeout {puts "TESTING ERROR 2.1\n";exit} + "192.168.1.60" {puts "TESTING ERROR 2.2\n";exit} + "192.168.1.200" {puts "TESTING ERROR 3\n";exit} + "192.168.1.201" {puts "TESTING ERROR 3\n";exit} + "192.168.1.202" {puts "TESTING ERROR 3\n";exit} + "192.168.1.203" {puts "TESTING ERROR 3\n";exit} + "192.168.1.204" {puts "TESTING ERROR 3\n";exit} + "192.168.1.205" {puts "TESTING ERROR 3\n";exit} + "192.168.1.206" {puts "TESTING ERROR 3\n";exit} + "192.168.1.207" {puts "TESTING ERROR 3\n";exit} + "192.168.1.208" {puts "TESTING ERROR 3\n";exit} + "192.168.1.209" {puts "TESTING ERROR 3\n";exit} + "192.168.1.210" {puts "TESTING ERROR 3\n";exit} + "192.168.1.211" {puts "TESTING ERROR 3\n";exit} + "192.168.1.212" {puts "TESTING ERROR 3\n";exit} + "192.168.1.213" {puts "TESTING ERROR 3\n";exit} + "192.168.1.214" {puts "TESTING ERROR 3\n";exit} + "192.168.1.215" {puts "TESTING ERROR 3\n";exit} + "192.168.1.216" {puts "TESTING ERROR 3\n";exit} + "192.168.1.217" {puts "TESTING ERROR 3\n";exit} + "192.168.1.218" {puts "TESTING ERROR 3\n";exit} + "192.168.1.219" {puts "TESTING ERROR 3\n";exit} + "192.168.1.220" {puts "TESTING ERROR 3\n";exit} + "192.168.1.221" {puts "TESTING ERROR 3\n";exit} + "192.168.1.222" {puts "TESTING ERROR 3\n";exit} + "192.168.1.223" {puts "TESTING ERROR 3\n";exit} + "192.168.1.224" {puts "TESTING ERROR 3\n";exit} + "192.168.1.225" {puts "TESTING ERROR 3\n";exit} + "192.168.1.226" {puts "TESTING ERROR 3\n";exit} + "192.168.1.227" {puts "TESTING ERROR 3\n";exit} + "192.168.1.228" {puts "TESTING ERROR 3\n";exit} + "192.168.1.229" {puts "TESTING ERROR 3\n";exit} + "Child process initialized" + } + puts "************ $i ******************\n" + incr i + after 100 +# sleep 1 +} + +puts "\n" + diff --git a/test/net_netfilter.exp b/test/net_netfilter.exp new file mode 100755 index 00000000000..8583d462530 --- /dev/null +++ b/test/net_netfilter.exp @@ -0,0 +1,88 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# check default netfilter on br0 +send -- "firejail --debug --net=br0 --ip=10.10.20.5 --netfilter\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Installing network filter" +} +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Chain INPUT (policy DROP" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "ACCEPT all -- any any anywhere" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "ACCEPT icmp -- any any anywhere" +} +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} +sleep 2 +send -- "exit\r" +sleep 1 + +# check default netfilter no new network +send -- "firejail --debug --netfilter\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + "Installing network filter" {puts "TESTING ERROR 5.1\n";exit} + "Chain INPUT (policy DROP" {puts "TESTING ERROR 5.1\n";exit} + "ACCEPT all -- any any anywhere" {puts "TESTING ERROR 5.1\n";exit} + "ACCEPT icmp -- any any anywhere" {puts "TESTING ERROR 5.1\n";exit} + "Child process initialized" +} +sleep 2 +send -- "exit\r" +sleep 1 + +# check file filter netfilter on br0 +send -- "firejail --debug --net=br0 --ip=10.10.20.5 --netfilter=netfilter.filter\r" +expect { + timeout {puts "TESTING ERROR 6\n";exit} + "Installing network filter" +} +expect { + timeout {puts "TESTING ERROR 6.1\n";exit} + "Child process initialized" +} +sleep 2 +send -- "ping -c 1 -w 3 10.10.20.1\r" +expect { + timeout {puts "TESTING ERROR 6.2\n";exit} + "0 received, 100% packet loss" +} + +send -- "exit\r" +sleep 1 + +# check profile netfilter on br0 +send -- "firejail --debug --net=br0 --ip=10.10.20.5 --profile=netfilter.profile\r" +expect { + timeout {puts "TESTING ERROR 7\n";exit} + "Installing network filter" +} +expect { + timeout {puts "TESTING ERROR 7.1\n";exit} + "Child process initialized" +} +sleep 2 +send -- "ping -c 1 -w 3 10.10.20.1\r" +expect { + timeout {puts "TESTING ERROR 7.2\n";exit} + "0 received, 100% packet loss" +} + +send -- "exit\r" +sleep 1 + +puts "\n" + diff --git a/test/net_noip.exp b/test/net_noip.exp new file mode 100755 index 00000000000..3db67885d6d --- /dev/null +++ b/test/net_noip.exp @@ -0,0 +1,41 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# check ip address +send -- "firejail --net=br0 --ip=none\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "eth0" {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +sleep 1 +send -- "bash\r" +sleep 1 + +# no default gateway configured +send -- "netstat -rn;pwd\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "0.0.0.0" {puts "TESTING ERROR 3\n";exit} + "eth0" {puts "TESTING ERROR 4\n";exit} + "home" +} +sleep 1 + +# eth0 configured +send -- "/sbin/ifconfig;pwd\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + "eth0" +} +expect { + timeout {puts "TESTING ERROR 6\n";exit} + "home" +} +sleep 1 + +puts "\n" + diff --git a/test/net_noip2.exp b/test/net_noip2.exp new file mode 100755 index 00000000000..234aec8a8f9 --- /dev/null +++ b/test/net_noip2.exp @@ -0,0 +1,41 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# check ip address +send -- "firejail --net=br1 --ip=none --defaultgw=10.10.30.78\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "eth0" {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +sleep 1 +send -- "bash\r" +sleep 1 + +# no default gateway configured +send -- "netstat -rn;pwd\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "0.0.0.0" {puts "TESTING ERROR 3\n";exit} + "eth0" {puts "TESTING ERROR 4\n";exit} + "home" +} +sleep 1 + +# eth0 configured +send -- "/sbin/ifconfig;pwd\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + "eth0" +} +expect { + timeout {puts "TESTING ERROR 6\n";exit} + "home" +} +sleep 1 + +puts "\n" + diff --git a/test/net_none.exp b/test/net_none.exp new file mode 100755 index 00000000000..dfa14a21171 --- /dev/null +++ b/test/net_none.exp @@ -0,0 +1,36 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --net=none\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "eth0" {puts "TESTING ERROR 0.1\n";exit} + "Child process initialized" +} +sleep 1 + +# test default gw +send -- "bash\r" +sleep 1 +send -- "netstat -rn; pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "0.0.0.0" {puts "TESTING ERROR 1.1\n";exit} + "home" +} +sleep 1 + +# check again devices +send -- "cat /proc/1/net/dev;pwd\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "eth0" {puts "TESTING ERROR 2.1\n";exit} + "home" +} +sleep 1 + + +puts "\n" diff --git a/test/netfilter.filter b/test/netfilter.filter new file mode 100644 index 00000000000..3e232065c0f --- /dev/null +++ b/test/netfilter.filter @@ -0,0 +1,6 @@ +*filter +:INPUT DROP [0:0] +:FORWARD DROP [0:0] +:OUTPUT ACCEPT [0:0] +-A INPUT -i lo -j ACCEPT +COMMIT diff --git a/test/netfilter.profile b/test/netfilter.profile new file mode 100644 index 00000000000..824c6cd0fe8 --- /dev/null +++ b/test/netfilter.profile @@ -0,0 +1 @@ +netfilter netfilter.filter diff --git a/test/noroot.exp b/test/noroot.exp new file mode 100755 index 00000000000..78991d4a918 --- /dev/null +++ b/test/noroot.exp @@ -0,0 +1,124 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --debug --noroot --caps.drop=all --seccomp --cpu=0,1 --name=noroot-sandbox\r" +expect { + timeout {puts "TESTING ERROR 0.1\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "cat /proc/self/status\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "CapBnd:" +} +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + "0000000000000000" +} + +send -- "cat /proc/self/status\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Cpus_allowed:" +} +expect { + timeout {puts "TESTING ERROR 2.1\n";exit} + "3" +} +expect { + timeout {puts "TESTING ERROR 2.2\n";exit} + "Cpus_allowed_list:" +} +puts "\n" + +send -- "cat /proc/self/status\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Seccomp:" +} +expect { + timeout {puts "TESTING ERROR 2.1\n";exit} + "2" +} +expect { + timeout {puts "TESTING ERROR 2.2\n";exit} + "Cpus_allowed:" +} +puts "\n" + +send -- "cat /etc/hostname\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "noroot-sandbox" +} +puts "\n" + +send -- "ping 0\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Operation not permitted" +} +puts "\n" + +send -- "whoami\r" +expect { + timeout {puts "TESTING ERROR 55\\n";exit} + "netblue" +} +puts "\n" +send -- "exit\r" +sleep 2 + + +send -- "firejail --noroot\r" +expect { + timeout {puts "TESTING ERROR 6\n";exit} + "Child process initialized" +} +sleep 1 +send -- "whoami\r" +expect { + timeout {puts "TESTING ERROR 7\n";exit} + "netblue" +} +send -- "sudo -s\r" +expect { + timeout {puts "TESTING ERROR 8\n";exit} + "effective uid is not 0, is sudo installed setuid root?" { puts "OK\n";} + "sudo must be owned by uid 0 and have the setuid bit set" { puts "OK\n";} +} +puts "\n" +send -- "exit\r" +sleep 2 + +send -- "firejail --name=test --noroot\r" +expect { + timeout {puts "TESTING ERROR 9\n";exit} + "Child process initialized" +} +sleep 1 + +spawn $env(SHELL) +send -- "firejail --debug --join=test\r" +expect { + timeout {puts "TESTING ERROR 9\n";exit} + "User namespace detected" +} +expect { + timeout {puts "TESTING ERROR 9\n";exit} + "Joining user namespace" +} +sleep 1 + +send -- "sudo -s\r" +expect { + timeout {puts "TESTING ERROR 8\n";exit} + "effective uid is not 0, is sudo installed setuid root?" { puts "OK\n";} + "sudo must be owned by uid 0 and have the setuid bit set" { puts "OK\n";} +} +puts "\n" diff --git a/test/opera.exp b/test/opera.exp new file mode 100755 index 00000000000..f536ae86626 --- /dev/null +++ b/test/opera.exp @@ -0,0 +1,72 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail opera www.gentoo.org\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Reading profile /etc/firejail/opera.profile" +} +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +sleep 10 + +spawn $env(SHELL) +send -- "firejail --list\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + ":firejail" +} +expect { + timeout {puts "TESTING ERROR 3.1\n";exit} + "opera" +} +sleep 1 + +send -- "firejail --name=blablabla\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} +sleep 2 + +spawn $env(SHELL) +send -- "firemon --seccomp\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + ":firejail opera" +} +expect { + timeout {puts "TESTING ERROR 5.1\n";exit} + "Seccomp: 0" +} +expect { + timeout {puts "TESTING ERROR 5.1\n";exit} + "name=blablabla" +} +sleep 1 +send -- "firemon --caps\r" +expect { + timeout {puts "TESTING ERROR 6\n";exit} + ":firejail opera" +} +expect { + timeout {puts "TESTING ERROR 6.1\n";exit} + "CapBnd:" +} +expect { + timeout {puts "TESTING ERROR 6.2\n";exit} + "fffffffff" +} +expect { + timeout {puts "TESTING ERROR 6.3\n";exit} + "name=blablabla" +} +sleep 1 + +puts "\n" + diff --git a/test/option-join.exp b/test/option-join.exp new file mode 100755 index 00000000000..ad8ba73e0ce --- /dev/null +++ b/test/option-join.exp @@ -0,0 +1,43 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --name=svntesting\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 3 + +spawn $env(SHELL) +send -- "firejail --join=svntesting;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Switching to pid" +} +expect { + timeout {puts "TESTING ERROR 2 (join) \n";exit} + "@svntesting" +} +sleep 1 + + +spawn $env(SHELL) +send -- "firejail --shutdown=svntesting;pwd\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "home" +} +sleep 1 + +send -- "firejail --list;pwd\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "svntesting" {puts "TESTING ERROR 5\n";exit} + "home" +} +sleep 1 + +puts "\n" diff --git a/test/option-shutdown.exp b/test/option-shutdown.exp new file mode 100755 index 00000000000..260a5b84f94 --- /dev/null +++ b/test/option-shutdown.exp @@ -0,0 +1,30 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --name=svntesting\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 3 + +spawn $env(SHELL) +send -- "firejail --shutdown=svntesting;pwd\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "home" +} +sleep 1 + +send -- "firejail --list;pwd\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + "svntesting" {puts "TESTING ERROR 6\n";exit} + "home" +} +sleep 1 + +puts "\n" diff --git a/test/option-trace.exp b/test/option-trace.exp new file mode 100755 index 00000000000..b8f723fb89f --- /dev/null +++ b/test/option-trace.exp @@ -0,0 +1,31 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --trace firefox --name=testing\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "command not found" {puts "\nTESTING: not tested, firefox not found\n"; exit} + "1:firefox:open" {puts "\n"} + "1:iceweasel:open" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "1:firefox:access" {puts "\n"} + "1:iceweasel:access" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "1:firefox:connect" {puts "\n"} + "1:iceweasel:connect" +} + +sleep 1 + +puts "\n" diff --git a/test/option_bind_directory.exp b/test/option_bind_directory.exp new file mode 100755 index 00000000000..1c1acc81422 --- /dev/null +++ b/test/option_bind_directory.exp @@ -0,0 +1,26 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --bind=/tmp/chroot,mntpoint\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "ls mntpoint;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "root" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "home" +} +sleep 1 + +puts "\n" + diff --git a/test/option_bind_file.exp b/test/option_bind_file.exp new file mode 100755 index 00000000000..0380b68b591 --- /dev/null +++ b/test/option_bind_file.exp @@ -0,0 +1,26 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --bind=tmpfile,/etc/passwd\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "cat /etc/passwd;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "hello" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "home" +} +sleep 1 + +puts "\n" + diff --git a/test/option_bind_user.exp b/test/option_bind_user.exp new file mode 100755 index 00000000000..9d2d17d7f4d --- /dev/null +++ b/test/option_bind_user.exp @@ -0,0 +1,15 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --bind=/tmp/chroot,mntpoint\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "bind option is available only if running as root" +} +sleep 1 + +puts "\n" + diff --git a/test/option_blacklist.exp b/test/option_blacklist.exp new file mode 100755 index 00000000000..b80d0cc6066 --- /dev/null +++ b/test/option_blacklist.exp @@ -0,0 +1,35 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --blacklist=/var\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "ls -l /var;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Permission denied" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "home" +} +send -- "cd /var;pwd\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "Permission denied" +} +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "home" +} +sleep 1 + +puts "\n" + diff --git a/test/option_blacklist_file.exp b/test/option_blacklist_file.exp new file mode 100755 index 00000000000..ecdfe3b8210 --- /dev/null +++ b/test/option_blacklist_file.exp @@ -0,0 +1,26 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --blacklist=/etc/passwd\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "cat /etc/passwd;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Permission denied" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "home" +} +sleep 1 + +puts "\n" + diff --git a/test/option_chroot_overlay.exp b/test/option_chroot_overlay.exp new file mode 100755 index 00000000000..b39bc0c8eb1 --- /dev/null +++ b/test/option_chroot_overlay.exp @@ -0,0 +1,21 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --chroot=/tmp/chroot --overlay\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "mutually exclusive" +} +sleep 1 + +send -- "firejail --overlay --chroot=/tmp/chroot\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "mutually exclusive" +} +sleep 1 + +puts "\n" diff --git a/test/option_help.exp b/test/option_help.exp new file mode 100755 index 00000000000..f4518219c7d --- /dev/null +++ b/test/option_help.exp @@ -0,0 +1,22 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --help\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "License GPL version 2 or later" +} +after 100 + +send -- "firejail -?\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "License GPL version 2 or later" +} +after 100 + +puts "\n" + diff --git a/test/option_list.exp b/test/option_list.exp new file mode 100755 index 00000000000..b9c73e52b03 --- /dev/null +++ b/test/option_list.exp @@ -0,0 +1,48 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +after 100 + +spawn $env(SHELL) +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +after 100 + +spawn $env(SHELL) +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Child process initialized" +} +sleep 1 + +spawn $env(SHELL) +send -- "firejail --list\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + ":firejail" +} +expect { + timeout {puts "TESTING ERROR 4\n";exit} + ":firejail" +} +expect { + timeout {puts "TESTING ERROR 5\n";exit} + ":firejail" +} +after 100 + + +puts "\n" + diff --git a/test/option_man.exp b/test/option_man.exp new file mode 100755 index 00000000000..d941a2432fb --- /dev/null +++ b/test/option_man.exp @@ -0,0 +1,17 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "man firejail\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Linux namespaces sandbox program" +} +after 100 + +send -- "q\r" +after 100 +puts "\n" + diff --git a/test/option_readonly.exp b/test/option_readonly.exp new file mode 100755 index 00000000000..4abbef6172d --- /dev/null +++ b/test/option_readonly.exp @@ -0,0 +1,26 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --read-only=tmpreadonly\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "touch tmpreadonly;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Read-only file system" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "home" +} +sleep 1 + +puts "\n" + diff --git a/test/option_rlimit.exp b/test/option_rlimit.exp new file mode 100755 index 00000000000..17d2bd9d19f --- /dev/null +++ b/test/option_rlimit.exp @@ -0,0 +1,36 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --rlimit-fsize=1024 --rlimit-nproc=1000 --rlimit-nofile=500 --rlimit-sigpending=200\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "cat /proc/self/limits; pwd\r" +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + "Max file size 1024 1024" +} +expect { + timeout {puts "TESTING ERROR 1.2\n";exit} + "Max processes 1000 1000" +} +expect { + timeout {puts "TESTING ERROR 1.3\n";exit} + "Max open files 500 500" +} +expect { + timeout {puts "TESTING ERROR 1.4\n";exit} + "Max pending signals 200 200" +} +expect { + timeout {puts "TESTING ERROR 1.5\n";exit} + "home" +} +sleep 1 +puts "\n" diff --git a/test/option_tmpfs.exp b/test/option_tmpfs.exp new file mode 100755 index 00000000000..1ff47ab13a3 --- /dev/null +++ b/test/option_tmpfs.exp @@ -0,0 +1,26 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --tmpfs=/var\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "ls -l /var;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "total 0" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "home" +} +sleep 1 + +puts "\n" + diff --git a/test/option_tree.exp b/test/option_tree.exp new file mode 100755 index 00000000000..1841907d16b --- /dev/null +++ b/test/option_tree.exp @@ -0,0 +1,60 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +after 100 + +spawn $env(SHELL) +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +after 100 + +spawn $env(SHELL) +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Child process initialized" +} +sleep 1 + +spawn $env(SHELL) +send -- "firejail --tree\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + ":firejail" +} +expect { + timeout {puts "TESTING ERROR 3.1\n";exit} + ":/bin/bash" +} +expect { + timeout {puts "TESTING ERROR 4\n";exit} + ":firejail" +} +expect { + timeout {puts "TESTING ERROR 4.1\n";exit} + ":/bin/bash" +} +expect { + timeout {puts "TESTING ERROR 5\n";exit} + ":firejail" +} +expect { + timeout {puts "TESTING ERROR 5.1\n";exit} + ":/bin/bash" +} +after 100 + + +puts "\n" + diff --git a/test/option_version.exp b/test/option_version.exp new file mode 100755 index 00000000000..44c0c217f00 --- /dev/null +++ b/test/option_version.exp @@ -0,0 +1,15 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --version\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "firejail version " +} +after 100 + +puts "\n" + diff --git a/test/output.exp b/test/output.exp new file mode 100755 index 00000000000..90a9d64b62d --- /dev/null +++ b/test/output.exp @@ -0,0 +1,66 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "rm -f logfile*\r" +sleep 1 +puts "\n" + +send -- "firejail --output=logfile -- ./output.sh\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "20000" +} +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + "60000" +} +expect { + timeout {puts "TESTING ERROR 1.2\n";exit} + "100000" +} +expect { + timeout {puts "TESTING ERROR 1.3\n";exit} + "120000" +} +expect { + timeout {puts "TESTING ERROR 1.4\n";exit} + "14999" +} +sleep 2 +puts "\n" + + +set timeout 2 +send -- "ls -al logfile*\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "logfile" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "logfile.1" +} +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "logfile.2" +} +expect { + timeout {puts "TESTING ERROR 5\n";exit} + "logfile.3" +} +expect { + timeout {puts "TESTING ERROR 6\n";exit} + "logfile.4" +} +expect { + timeout {puts "TESTING ERROR 7\n";exit} + "logfile.5" +} +sleep 1 +send -- "rm -f logfile*\r" +sleep 1 + +puts "\n" diff --git a/test/output.sh b/test/output.sh new file mode 100755 index 00000000000..2be188e3a33 --- /dev/null +++ b/test/output.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +i="0" + +while [ $i -lt 150000 ] +do + echo message number $i + i=$[$i+1] +done diff --git a/test/pid.exp b/test/pid.exp new file mode 100755 index 00000000000..0baf3af0ee3 --- /dev/null +++ b/test/pid.exp @@ -0,0 +1,48 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +# test processes +send -- "bash\r" +sleep 1 +send -- "ps aux; pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "/bin/bash" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "bash" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "ps aux" +} +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "home" +} +sleep 1 + + +send -- "ps aux |wc -l; pwd\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + "5" +} +expect { + timeout {puts "TESTING ERROR 6\n";exit} + "home" +} +sleep 1 + +puts "\n" diff --git a/test/private-keep.exp b/test/private-keep.exp new file mode 100755 index 00000000000..cdae12ac3e3 --- /dev/null +++ b/test/private-keep.exp @@ -0,0 +1,66 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --private.keep=.mozilla,.config/firejail\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "ls -al\r" +expect { + timeout {puts "TESTING ERROR 0.1\n";exit} + ".config" +} +expect { + timeout {puts "TESTING ERROR 0.2\n";exit} + ".mozilla" +} +sleep 1 + +send -- "find .config\r" +expect { + timeout {puts "TESTING ERROR 0.3\n";exit} + ".config" +} +expect { + timeout {puts "TESTING ERROR 0.4\n";exit} + ".config/firejail" +} +sleep 1 +puts "\n" +send -- "exit\r" +sleep 2 + + +send -- "firejail --profile=private-keep.profile\r" +expect { + timeout {puts "TESTING ERROR 1.0\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "ls -al\r" +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + ".config" +} +expect { + timeout {puts "TESTING ERROR 1.2\n";exit} + ".mozilla" +} +sleep 1 + +send -- "find .config\r" +expect { + timeout {puts "TESTING ERROR 1.3\n";exit} + ".config" +} +expect { + timeout {puts "TESTING ERROR 1.4\n";exit} + ".config/firejail" +} diff --git a/test/private-keep.profile b/test/private-keep.profile new file mode 100644 index 00000000000..7f842cc0401 --- /dev/null +++ b/test/private-keep.profile @@ -0,0 +1 @@ +private.keep .mozilla,.config/firejail diff --git a/test/private.exp b/test/private.exp new file mode 100755 index 00000000000..e2ae80b33bf --- /dev/null +++ b/test/private.exp @@ -0,0 +1,95 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +if { $argc != 1 } { + puts "TESTING ERROR: argument missing" + puts "Usage: private.exp username" + puts "where username is the name of the current user" + exit +} + +# testing profile and private +send -- "firejail --private --profile=/etc/firejail/firefox.profile\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 +send -- "exit\r" +sleep 1 + +send -- "firejail --private\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} + +sleep 1 +send -- "ls -al; pwd\r" +expect { + timeout {puts "TESTING ERROR 0.1\n";exit} + ".bashrc" +} +expect { + timeout {puts "TESTING ERROR 0.2\n";exit} + [lindex $argv 0] +} +send -- "ls -al; pwd\r" +expect { + timeout { + # OpenSUSE doesn't use .Xauthority from user home directory + send -- "env | grep XAUTHORITY\r" + + expect { + timeout {puts "TESTING ERROR 0.3\n";exit} + "/run/lightdm/netblue/xauthority" + } + } + ".Xauthority" +} +expect { + timeout {puts "TESTING ERROR 0.4\n";exit} + [lindex $argv 0] +} + + +# testing private only +send -- "bash\r" +sleep 1 +# owner /home/netblue +send -- "ls -l /home;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + [lindex $argv 0] +} +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + [lindex $argv 0] +} +expect { + timeout {puts "TESTING ERROR 1.2\n";exit} + [lindex $argv 0] +} +expect { + timeout {puts "TESTING ERROR 1.3\n";exit} + "home" +} +sleep 1 + +# owner /tmp +send -- "stat -c %U%a /tmp;pwd\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "root777" {puts "version 1\n";} + "root1777" {puts "version 2\n";} +} +expect { + timeout {puts "TESTING ERROR 2.1\n";exit} + "home" +} +sleep 1 + +puts "\n" diff --git a/test/private.profile b/test/private.profile new file mode 100644 index 00000000000..1b947b6f7c1 --- /dev/null +++ b/test/private.profile @@ -0,0 +1 @@ +private ./dirprivate diff --git a/test/private_dir.exp b/test/private_dir.exp new file mode 100755 index 00000000000..95f89362abb --- /dev/null +++ b/test/private_dir.exp @@ -0,0 +1,53 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# testing private +send -- "firejail --private=./dirprivate\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "ls -al;pwd\r" +expect { + timeout {puts "TESTING ERROR 0.1\n";exit} + "bashrc" +} +expect { + timeout {puts "TESTING ERROR 0.2\n";exit} + "home" +} +send -- "ls -al;pwd\r" +expect { + timeout { + # OpenSUSE doesn't use .Xauthority from user home directory + send -- "env | grep XAUTHORITY\r" + + expect { + timeout {puts "TESTING ERROR 0.3\n";exit} + "/run/lightdm/netblue/xauthority" + } + } + ".Xauthority" +} +expect { + timeout {puts "TESTING ERROR 0.4\n";exit} + [lindex $argv 0] +} + +send -- "ls -al | wc -l;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "5" {puts "normal system\n";} + "4" {puts "OpenSUSE\n";} +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "home" +} + +puts "\n" diff --git a/test/private_dir_profile.exp b/test/private_dir_profile.exp new file mode 100755 index 00000000000..e6c01798ee0 --- /dev/null +++ b/test/private_dir_profile.exp @@ -0,0 +1,54 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# testing private +send -- "firejail --profile=private.profile\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "ls -al;pwd\r" +expect { + timeout {puts "TESTING ERROR 0.1\n";exit} + "bashrc" +} +expect { + timeout {puts "TESTING ERROR 0.2\n";exit} + "home" +} +send -- "ls -al;pwd\r" +expect { + timeout { + # OpenSUSE doesn't use .Xauthority from user home directory + send -- "env | grep XAUTHORITY\r" + + expect { + timeout {puts "TESTING ERROR 0.3\n";exit} + "/run/lightdm/netblue/xauthority" + } + } + ".Xauthority" +} +expect { + timeout {puts "TESTING ERROR 0.4\n";exit} + [lindex $argv 0] +} + +send -- "ls -al | wc -l;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "5" {puts "normal system\n";} + "4" {puts "OpenSUSE\n";} +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "home" +} + +puts "\n" + diff --git a/test/profile_apps.exp b/test/profile_apps.exp new file mode 100755 index 00000000000..c57b314893d --- /dev/null +++ b/test/profile_apps.exp @@ -0,0 +1,48 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +# firefox +send -- "firejail --profile=/etc/firejail/firefox.profile\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 +send -- "exit\r" +sleep 1 + +# iceweasel +send -- "firejail --profile=/etc/firejail/iceweasel.profile\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +sleep 1 +send -- "exit\r" +sleep 1 + +# evince +send -- "firejail --profile=/etc/firejail/evince.profile\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Child process initialized" +} +sleep 1 +send -- "exit\r" +sleep 1 + +# midori +send -- "firejail --profile=/etc/firejail/midori.profile\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "Child process initialized" +} +sleep 1 +send -- "exit\r" +sleep 1 + + +puts "\n" diff --git a/test/profile_followlnk.exp b/test/profile_followlnk.exp new file mode 100755 index 00000000000..e2ede2865ae --- /dev/null +++ b/test/profile_followlnk.exp @@ -0,0 +1,68 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "mkdir /tmp/firejailtestdir\r" +sleep 1 +send -- "ln -s /tmp/firejailtestdir /tmp/firejailtestdirlnk\r" +sleep 1 +send -- "touch /tmp/firejailtestfile\r" +sleep 1 +send -- "ln -s /tmp/firejailtestfile /tmp/firejailtestfilelnk\r" +sleep 1 + +send -- "firejail --profile=readonly-lnk.profile --debug\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} + +# testing private only +send -- "bash\r" +sleep 1 + + +send -- "ls > /tmp/firejailtestdirlnk/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Read-only file system" +} +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + "home" +} +sleep 1 + +send -- "ls > /tmp/firejailtestfilelnk;pwd\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Read-only file system" +} +expect { + timeout {puts "TESTING ERROR 2.1\n";exit} + "home" +} +sleep 1 + +send -- "exit\r" +sleep 1 +send -- "pwd\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "home" +} +sleep 1 +send -- "exit\r" +sleep 1 +send -- "pwd\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "home" +} +sleep 2 +send -- "rm -fr /tmp/firejailtest*\r" +sleep 1 + +puts "\n" diff --git a/test/profile_noperm.exp b/test/profile_noperm.exp new file mode 100755 index 00000000000..b3ed558bc3b --- /dev/null +++ b/test/profile_noperm.exp @@ -0,0 +1,13 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --profile=/etc/shadow\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "cannot access profile" +} +sleep 1 +puts "\n" diff --git a/test/profile_readonly.exp b/test/profile_readonly.exp new file mode 100755 index 00000000000..046b0d7386d --- /dev/null +++ b/test/profile_readonly.exp @@ -0,0 +1,64 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "mkdir /tmp/firejailtestdir\r" +sleep 1 +send -- "touch /tmp/firejailtestfile\r" +sleep 1 + +send -- "firejail --profile=readonly.profile\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} + +# testing private only +send -- "bash\r" +sleep 1 + + +send -- "ls > /tmp/firejailtestdir/ttt;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Read-only file system" +} +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + "home" +} +sleep 1 + +send -- "ls > /tmp/firejailtestfile;pwd\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Read-only file system" +} +expect { + timeout {puts "TESTING ERROR 2.1\n";exit} + "home" +} +sleep 1 + +send -- "exit\r" +sleep 1 +send -- "pwd\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "home" +} +sleep 1 +send -- "exit\r" +sleep 1 +send -- "pwd\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "home" +} +sleep 2 +send -- "rm -fr /tmp/firejailtest*\r" +sleep 1 + +puts "\n" diff --git a/test/profile_rlimit.exp b/test/profile_rlimit.exp new file mode 100755 index 00000000000..7d2637444de --- /dev/null +++ b/test/profile_rlimit.exp @@ -0,0 +1,36 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --profile=rlimit.profile\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "cat /proc/self/limits; pwd\r" +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + "Max file size 1024 1024" +} +expect { + timeout {puts "TESTING ERROR 1.2\n";exit} + "Max processes 1000 1000" +} +expect { + timeout {puts "TESTING ERROR 1.3\n";exit} + "Max open files 500 500" +} +expect { + timeout {puts "TESTING ERROR 1.4\n";exit} + "Max pending signals 200 200" +} +expect { + timeout {puts "TESTING ERROR 1.5\n";exit} + "home" +} +sleep 1 +puts "\n" diff --git a/test/profile_syntax.exp b/test/profile_syntax.exp new file mode 100755 index 00000000000..3218177c33a --- /dev/null +++ b/test/profile_syntax.exp @@ -0,0 +1,69 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --profile=test.profile\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} + +sleep 2 +send -- "ls /sbin\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "cannot open" +} + +sleep 1 +send -- "ls /usr/sbin\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "cannot open" +} + +sleep 1 +send -- "ls -l /etc/shadow\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "root root 0" +} + +sleep 1 +send -- "rmdir;pwd\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Permission denied" +} +expect { + timeout {puts "TESTING ERROR 5\n";exit} + "home" +} + +sleep 1 +send -- "mount;pwd\r" +expect { + timeout {puts "TESTING ERROR 6\n";exit} + "Permission denied" +} +expect { + timeout {puts "TESTING ERROR 7\n";exit} + "home" +} + +sleep 1 +send -- "umount;pwd\r" +expect { + timeout {puts "TESTING ERROR 8\n";exit} + "Permission denied" +} +expect { + timeout {puts "TESTING ERROR 9\n";exit} + "home" +} +send -- "exit\r" + +sleep 1 +puts "\n" diff --git a/test/profile_syntax2.exp b/test/profile_syntax2.exp new file mode 100755 index 00000000000..cd514aa0e09 --- /dev/null +++ b/test/profile_syntax2.exp @@ -0,0 +1,47 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --debug --profile=test2.profile\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Reading profile test2.profile" +} +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Reading profile test.profile" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Disable /bin/rmdir" {puts "Most Linux platforms\n"} + "Disable /usr/bin/rmdir" { puts "OpenSUSE platform\n"} +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "Mounting a new /home directory" +} +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Drop CAP_SYS_MODULE" +} +expect { + timeout {puts "TESTING ERROR 5\n";exit} + "Initialize seccomp filter" +} +expect { + timeout {puts "TESTING ERROR 6\n";exit} + "Blacklisting syscall" +} +expect { + timeout {puts "TESTING ERROR 7\n";exit} + "mount" +} +expect { + timeout {puts "TESTING ERROR 8\n";exit} + "Child process initialized" +} + +sleep 1 +puts "\n" diff --git a/test/profile_tmpfs.exp b/test/profile_tmpfs.exp new file mode 100755 index 00000000000..a2faa32f780 --- /dev/null +++ b/test/profile_tmpfs.exp @@ -0,0 +1,37 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "mkdir /tmp/firejailtestdir\r" +sleep 1 +send -- "ls > /tmp/firejailtestdir/tmpfile\r" +sleep 1 + +send -- "firejail --profile=tmpfs.profile\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} + +# testing private only +send -- "bash\r" +sleep 1 + +send -- "ls -l /tmp/firejailtestdir;pwd\r" +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + "tmpfile" {puts "TESTING ERROR 1\n";exit} + "home" +} +sleep 1 +send -- "exit\r" +sleep 1 +send -- "exit\r" +sleep 1 +send -- "rm -fr /tmp/firejailtestdir\r" + +sleep 1 + +puts "\n" diff --git a/test/readonly-lnk.profile b/test/readonly-lnk.profile new file mode 100644 index 00000000000..71ffb1a26ad --- /dev/null +++ b/test/readonly-lnk.profile @@ -0,0 +1,2 @@ +read-only /tmp/firejailtestdirlnk +read-only /tmp/firejailtestfilelnk diff --git a/test/readonly.profile b/test/readonly.profile new file mode 100644 index 00000000000..55d89e3d736 --- /dev/null +++ b/test/readonly.profile @@ -0,0 +1,2 @@ +read-only /tmp/firejailtestdir +read-only /tmp/firejailtestfile \ No newline at end of file diff --git a/test/rlimit.profile b/test/rlimit.profile new file mode 100644 index 00000000000..271891c035e --- /dev/null +++ b/test/rlimit.profile @@ -0,0 +1,4 @@ + rlimit-fsize 1024 +rlimit-nproc 1000 + rlimit-nofile 500 +rlimit-sigpending 200 \ No newline at end of file diff --git a/test/seccomp-bad-empty.exp b/test/seccomp-bad-empty.exp new file mode 100755 index 00000000000..53b5c2e21a2 --- /dev/null +++ b/test/seccomp-bad-empty.exp @@ -0,0 +1,38 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --seccomp=\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Error: empty syscall lists are not allowed" +} + +send -- "firejail --seccomp.drop=\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Error: empty syscall lists are not allowed" +} + +send -- "firejail --seccomp.keep=\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Error: empty syscall lists are not allowed" +} + +send -- "firejail --profile=seccomp-bad-empty.profile\r" +expect { + timeout {puts "TESTING ERROR 6\n";exit} + "Error: line 1 in the custom profile is invalid" +} + +send -- "firejail --profile=seccomp-bad-empty2.profile\r" +expect { + timeout {puts "TESTING ERROR 7\n";exit} + "Error: line 1 in the custom profile is invalid" +} +sleep 1 +puts "\n" + diff --git a/test/seccomp-bad-empty.profile b/test/seccomp-bad-empty.profile new file mode 100644 index 00000000000..2d4fcde7c25 --- /dev/null +++ b/test/seccomp-bad-empty.profile @@ -0,0 +1 @@ +seccomp.drop diff --git a/test/seccomp-bad-empty2.profile b/test/seccomp-bad-empty2.profile new file mode 100644 index 00000000000..c4e6c9f74a5 --- /dev/null +++ b/test/seccomp-bad-empty2.profile @@ -0,0 +1 @@ +seccomp.keep diff --git a/test/seccomp-chmod-profile.exp b/test/seccomp-chmod-profile.exp new file mode 100755 index 00000000000..098328cea21 --- /dev/null +++ b/test/seccomp-chmod-profile.exp @@ -0,0 +1,46 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --profile=seccomp.profile --private\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 2 + +send -- "touch testfile;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "/root" {puts "running as root"} + "/home" +} + +send -- "ls -l testfile;pwd\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "testfile" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "/root" {puts "running as root"} + "/home" +} + +send -- "chmod +x testfile;pwd\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Bad system call" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "/root" {puts "running as root"} + "/home" +} + + +send -- "exit\r" +sleep 1 +puts "\n" diff --git a/test/seccomp-chmod.exp b/test/seccomp-chmod.exp new file mode 100755 index 00000000000..b4a213206c4 --- /dev/null +++ b/test/seccomp-chmod.exp @@ -0,0 +1,46 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --seccomp=chmod,fchmod,fchmodat --private\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 2 + +send -- "touch testfile;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "/root" {puts "running as root"} + "/home" +} + +send -- "ls -l testfile;pwd\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "testfile" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "/root" {puts "running as root"} + "/home" +} + +send -- "chmod +x testfile;pwd\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Bad system call" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "/root" {puts "running as root"} + "/home" +} + + +send -- "exit\r" +sleep 1 +puts "\n" diff --git a/test/seccomp-chown.exp b/test/seccomp-chown.exp new file mode 100755 index 00000000000..69b896700eb --- /dev/null +++ b/test/seccomp-chown.exp @@ -0,0 +1,46 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --seccomp=chown,fchown,fchownat,lchown --private\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 2 + +send -- "touch testfile;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "/root" {puts "running as root"} + "/home" +} + +send -- "ls -l testfile;pwd\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "testfile" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "/root" {puts "running as root"} + "/home" +} + +send -- "chown netblue:netblue testfile;pwd\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Bad system call" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "/root" {puts "running as root"} + "/home" +} + + +send -- "exit\r" +sleep 1 +puts "\n" diff --git a/test/seccomp-debug.exp b/test/seccomp-debug.exp new file mode 100755 index 00000000000..a7b89912aec --- /dev/null +++ b/test/seccomp-debug.exp @@ -0,0 +1,32 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --seccomp --debug\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Blacklisting syscall" +} +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "open_by_handle_at" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "BLACKLIST" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "open_by_handle_at" +} +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} +sleep 2 + +send -- "exit\r" +sleep 1 +puts "\n" diff --git a/test/seccomp-empty.exp b/test/seccomp-empty.exp new file mode 100755 index 00000000000..11abf2e0080 --- /dev/null +++ b/test/seccomp-empty.exp @@ -0,0 +1,145 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --debug --seccomp=chmod,fchmod,fchmodat --private\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "VALIDATE_ARCHITECTURE" +} +expect { + timeout {puts "TESTING ERROR 0.1\n";exit} + "mount" +} +expect { + timeout {puts "TESTING ERROR 0.2\n";exit} + "ptrace" +} +expect { + timeout {puts "TESTING ERROR 0.3\n";exit} + "chmod" +} +expect { + timeout {puts "TESTING ERROR 0.4\n";exit} + "fchmod" +} +expect { + timeout {puts "TESTING ERROR 0.5\n";exit} + "fchmodat" +} +expect { + timeout {puts "TESTING ERROR 0.6\n";exit} + "RETURN_ALLOW" +} +expect { + timeout {puts "TESTING ERROR 0.7\n";exit} + "Child process initialized" +} +sleep 2 +send -- "exit\r" +sleep 3 +puts "\n" + +send -- "firejail --debug --seccomp.drop=chmod,fchmod,fchmodat --private\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "VALIDATE_ARCHITECTURE" +} +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + "mount" {puts "TESTING ERROR 1.2\n";exit} + "ptrace" {puts "TESTING ERROR 1.3\n";exit} + "chmod" +} +expect { + timeout {puts "TESTING ERROR 1.4\n";exit} + "fchmod" +} +expect { + timeout {puts "TESTING ERROR 1.5\n";exit} + "fchmodat" +} +expect { + timeout {puts "TESTING ERROR 1.6\n";exit} + "RETURN_ALLOW" +} +expect { + timeout {puts "TESTING ERROR 1.7\n";exit} + "Child process initialized" +} +sleep 2 +send -- "exit\r" +puts "\n" + +sleep 2 +send -- "firejail --debug --profile=seccomp.profile --private\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "VALIDATE_ARCHITECTURE" +} +expect { + timeout {puts "TESTING ERROR 2.1\n";exit} + "mount" +} +expect { + timeout {puts "TESTING ERROR 2.2\n";exit} + "ptrace" +} +expect { + timeout {puts "TESTING ERROR 2.3\n";exit} + "chmod" +} +expect { + timeout {puts "TESTING ERROR 2.4\n";exit} + "fchmod" +} +expect { + timeout {puts "TESTING ERROR 2.5\n";exit} + "fchmodat" +} +expect { + timeout {puts "TESTING ERROR 2.6\n";exit} + "RETURN_ALLOW" +} +expect { + timeout {puts "TESTING ERROR 2.7\n";exit} + "Child process initialized" +} +sleep 2 +send -- "exit\r" +sleep 3 +puts "\n" + +send -- "firejail --debug --profile=seccomp-empty.profile --private\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "VALIDATE_ARCHITECTURE" +} +expect { + timeout {puts "TESTING ERROR 3.1\n";exit} + "mount" {puts "TESTING ERROR 3.2\n";exit} + "ptrace" {puts "TESTING ERROR 3.3\n";exit} + "chmod" +} +expect { + timeout {puts "TESTING ERROR 3.4\n";exit} + "fchmod" +} +expect { + timeout {puts "TESTING ERROR 3.5\n";exit} + "fchmodat" +} +expect { + timeout {puts "TESTING ERROR 3.6\n";exit} + "RETURN_ALLOW" +} +expect { + timeout {puts "TESTING ERROR 3.7\n";exit} + "Child process initialized" +} +sleep 2 +send -- "exit\r" +puts "\n" + diff --git a/test/seccomp-empty.profile b/test/seccomp-empty.profile new file mode 100644 index 00000000000..8f71f55a5dc --- /dev/null +++ b/test/seccomp-empty.profile @@ -0,0 +1 @@ +seccomp.drop chmod,fchmod,fchmodat diff --git a/test/seccomp-ptrace.exp b/test/seccomp-ptrace.exp new file mode 100755 index 00000000000..c5411c249cc --- /dev/null +++ b/test/seccomp-ptrace.exp @@ -0,0 +1,23 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --seccomp\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 2 + +send -- "strace ls\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Bad system call" {puts "version 1\n";} + " unexpected signal 31" {puts "version 2\n"} +} + +send -- "exit\r" +sleep 1 +puts "\n" diff --git a/test/seccomp-su.exp b/test/seccomp-su.exp new file mode 100755 index 00000000000..dca6f15ee28 --- /dev/null +++ b/test/seccomp-su.exp @@ -0,0 +1,34 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --seccomp\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 2 + +send -- "sudo su -\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "effective uid is not 0" +} + +send -- "sudo ls\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "effective uid is not 0" +} + +send -- "ping google.com\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Operation not permitted" +} + +send -- "exit\r" +sleep 1 +puts "\n" diff --git a/test/seccomp-umount.exp b/test/seccomp-umount.exp new file mode 100755 index 00000000000..e037d32648f --- /dev/null +++ b/test/seccomp-umount.exp @@ -0,0 +1,28 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "sudo ls; sudo whoami; sudo pwd\r" +expect { + timeout {puts "TESTING ERROR: you need to root run this test as root\n";exit} + "root" +} + +send -- "firejail --net=br0 --ip=10.10.20.5 --seccomp\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 2 + +send -- "umount /proc\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Bad system call" +} + +send -- "exit\r" +sleep 1 +puts "\n" diff --git a/test/seccomp.profile b/test/seccomp.profile new file mode 100644 index 00000000000..cb0b15aee87 --- /dev/null +++ b/test/seccomp.profile @@ -0,0 +1 @@ +seccomp chmod,fchmod,fchmodat diff --git a/test/servers.exp b/test/servers.exp new file mode 100755 index 00000000000..a36814a69a8 --- /dev/null +++ b/test/servers.exp @@ -0,0 +1,40 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "sudo ls; sudo whoami; sudo pwd\r" +expect { + timeout {puts "TESTING ERROR: you need to root run this test as root\n";exit} + "root" +} + +send -- "firejail --net=br0 --ip=10.10.20.5 --seccomp\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 2 + + +send -- "/etc/init.d/rsyslog start;sleep 1;/etc/init.d/ssh start;sleep 1;/etc/init.d/nginx start\r" +sleep 3 + +send -- "ps aux; pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "rsyslogd" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "sshd" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "nginx" +} + +send -- "exit\r" +sleep 1 +puts "\n" diff --git a/test/servers2.exp b/test/servers2.exp new file mode 100755 index 00000000000..28bcae2070d --- /dev/null +++ b/test/servers2.exp @@ -0,0 +1,31 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "sudo ls; sudo whoami; sudo pwd\r" +expect { + timeout {puts "TESTING ERROR: you need to root run this test as root\n";exit} + "root" +} + +send -- "firejail --net=br0 --ip=10.10.20.5--seccomp\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 2 + +send -- "/etc/init.d/snmpd start" +sleep 2 + +send -- "ps aux; pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "snmpd" +} + +send -- "exit\r" +sleep 1 +puts "\n" diff --git a/test/servers3.exp b/test/servers3.exp new file mode 100755 index 00000000000..f23ffba46cd --- /dev/null +++ b/test/servers3.exp @@ -0,0 +1,31 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "sudo ls; sudo whoami; sudo pwd\r" +expect { + timeout {puts "TESTING ERROR: you need to root run this test as root\n";exit} + "root" +} + +send -- "firejail --net=br0 --ip=10.10.20.5 --seccomp\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 2 + +send -- "/etc/init.d/apache2 start\r" +sleep 2 + +send -- "ps aux; pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "apache" +} + +send -- "exit\r" +sleep 1 +puts "\n" diff --git a/test/servers4.exp b/test/servers4.exp new file mode 100755 index 00000000000..9feeecf6192 --- /dev/null +++ b/test/servers4.exp @@ -0,0 +1,32 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "sudo ls; sudo whoami; sudo pwd\r" +expect { + timeout {puts "TESTING ERROR: you need to root run this test as root\n";exit} + "root" +} + +send -- "firejail --net=br0 --ip=10.10.20.5 --seccomp\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 2 + +send -- "/etc/init.d/isc-dhcp-server start\r" +sleep 5 + + +send -- "ps aux; pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "dhcpd" +} + +send -- "exit\r" +sleep 1 +puts "\n" diff --git a/test/shell_csh.exp b/test/shell_csh.exp new file mode 100755 index 00000000000..8fa1ef16675 --- /dev/null +++ b/test/shell_csh.exp @@ -0,0 +1,40 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --private --csh\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "ls -al;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + ".cshrc" +} +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + "home" +} +send -- "env | grep SHELL;pwd\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "SHELL" +} +expect { + timeout {puts "TESTING ERROR 2.1\n";exit} + "/bin/csh" +} +expect { + timeout {puts "TESTING ERROR 2.2\n";exit} + "home" +} +send -- "exit\r" +sleep 1 + +puts "\n" + diff --git a/test/shell_dash.exp b/test/shell_dash.exp new file mode 100755 index 00000000000..298b65a0d6b --- /dev/null +++ b/test/shell_dash.exp @@ -0,0 +1,41 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --private --shell=/bin/dash\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +#send -- "ls -al;pwd\r" +#expect { +# timeout {puts "TESTING ERROR 1\n";exit} +# ".zshrc" +#} +#expect { +# timeout {puts "TESTING ERROR 1.1\n";exit} +# "home" +#} + +send -- "env | grep SHELL;pwd\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "SHELL" +} +expect { + timeout {puts "TESTING ERROR 2.1\n";exit} + "/bin/dash" +} +expect { + timeout {puts "TESTING ERROR 2.2\n";exit} + "home" +} +send -- "exit\r" +sleep 1 + +puts "\n" + diff --git a/test/shell_zsh.exp b/test/shell_zsh.exp new file mode 100755 index 00000000000..79cd78a3e45 --- /dev/null +++ b/test/shell_zsh.exp @@ -0,0 +1,40 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --private --zsh\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "ls -al;pwd\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + ".zshrc" +} +expect { + timeout {puts "TESTING ERROR 1.1\n";exit} + "home" +} +send -- "env | grep SHELL;pwd\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "SHELL" +} +expect { + timeout {puts "TESTING ERROR 2.1\n";exit} + "/usr/bin/zsh" +} +expect { + timeout {puts "TESTING ERROR 2.2\n";exit} + "home" +} +send -- "exit\r" +sleep 1 + +puts "\n" + diff --git a/test/sysrq-trigger.exp b/test/sysrq-trigger.exp new file mode 100755 index 00000000000..18fb4a01a63 --- /dev/null +++ b/test/sysrq-trigger.exp @@ -0,0 +1,21 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "echo b > /proc/sysrq-trigger\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Read-only file system" +} +sleep 1 + +puts "\n" diff --git a/test/test-nonet.sh b/test/test-nonet.sh new file mode 100755 index 00000000000..3df8b2d4edc --- /dev/null +++ b/test/test-nonet.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +echo "TESTING: version" +./option_version.exp + +echo "TESTING: help" +./option_help.exp + +echo "TESTING: man" +./option_man.exp + +echo "TESTING: list" +./option_list.exp + +echo "TESTING: PID" +./pid.exp + +echo "TESTING: profile no permissions" +./profile_noperm.exp + +echo "TESTING: profile syntax" +./profile_syntax.exp + +echo "TESTING: profile read-only" +./profile_readonly.exp + +echo "TESTING: profile tmpfs" +./profile_tmpfs.exp + +echo "TESTING: private" +./private.exp `whoami` + +echo "TESTING: read/write /var/tmp" +./fs_var_tmp.exp + +echo "TESTING: read/write /var/run" +./fs_var_run.exp + +echo "TESTING: read/write /var/lock" +./fs_var_lock.exp + +echo "TESTING: read/write /dev/shm" +./fs_dev_shm.exp + diff --git a/test/test-root.sh b/test/test-root.sh new file mode 100755 index 00000000000..cd607b75b3f --- /dev/null +++ b/test/test-root.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +./chk_config.exp + +echo "TESTING: servers rsyslogd, sshd, nginx" +./servers.exp + +if [ -f /etc/init.d/snmpd ] +then + echo "TESTING: servers snmpd" + ./servers2.exp +fi + +if [ -f /etc/init.d/apache2 ] +then + echo "TESTING: servers apache2" + ./servers3.exp +fi + +if [ -f /etc/init.d/isc-dhcp-server ] +then + echo "TESTING: servers isc dhcp server" + ./servers4.exp +fi + +echo "TESTING: /proc/sysrq-trigger reset disabled" +./sysrq-trigger.exp + +echo "TESTING: seccomp umount" +./seccomp-umount.exp + +echo "TESTING: seccomp chmod (seccomp lists)" +./seccomp-chmod.exp + +echo "TESTING: seccomp chown (seccomp lists)" +./seccomp-chown.exp + +echo "TESTING: bind directory" +./option_bind_directory.exp + +echo "TESTING: bind file" +echo hello > tmpfile +./option_bind_file.exp +rm -f tmpfile + +echo "TESTING: chroot" +./fs_chroot.exp + +echo "TESTING: firemon --interface" +./firemon-interface.exp + +if [ -f /sys/fs/cgroup/g1/tasks ] +then + echo "TESTING: firemon --cgroup" + ./firemon-cgroup.exp +fi diff --git a/test/test.profile b/test/test.profile new file mode 100644 index 00000000000..716419fd061 --- /dev/null +++ b/test/test.profile @@ -0,0 +1,6 @@ + blacklist /sbin +blacklist /usr/sbin +blacklist /etc/shadow + blacklist /bin/rmdir +blacklist ${PATH}/umount +blacklist ${PATH}/mount diff --git a/test/test.rv b/test/test.rv new file mode 100644 index 00000000000..98a04fba2da --- /dev/null +++ b/test/test.rv @@ -0,0 +1,49 @@ +# run it as: +# ../src/tools/rvtest test.rv 2>/dev/null | grep TESTING +# + + +# invalid options +1 firejail -blablabla +1 firejail --blablabla +1 firejail --debug --blablabla + +# misc options +0 firejail --help +0 firejail --list + +# network testing +0 firejail --net=none exit +1 firejail --ip=none --net=none exit # noip requires at least one network +0 firejail --net=br0 exit +1 firejail --net=none --net=br0 exit # --net and --net=none are mutually exclusive +1 firejail --ip=none exit # noip requires at least one network +1 firejail --defaultgw=10.10.20.1 # no bridge configured +0 firejail --net=br0 --ip=10.10.20.6 exit +1 firejail --net=br0 --ip=192.168.5.6 exit # interface range +1 firejail --net=br0 --ip=10.10 # bad ip +1 firejail --net=br0 --ip=asdf #bad ip +1 firejail --ip=asdf # no bridge configured +0 firejail --net=br0 --defaultgw=10.10.20.1 exit +1 firejail --net=br0 --defaultgw=10.10.20 exit # invalid ip address +1 firejail --net=br0 --defaultgw=asdf exit # invalid ip address +0 firejail --net=br0 --ip=10.10.20.2 --defaultgw=10.10.20.1 exit +0 firejail --net=br0 --net=br1 --net=br2 --net=br3 exit +1 firejail --net +1 firejail --net= +1 firejail --net=bingo +1 firejail --net=loopback +1 firejail --net=lo #invalid network device +1 firejail --net=/br0 exit +1 firejail --net=br0 --net=br1 --net=br2 --net=br3 --net=br4 exit # only 4 networks allowed +0 firejail --net=eth0 exit +1 firejail --net=/dev/eth0 exit +1 firejail --net=br0 --net=br1 --net=/dev/eth0 exit +0 firejail --net=br0 --net=br0 exit # same device twice +0 firejail --net=eth0 --net=br2 --net=br3 --net=eth0 exit # same device twice +0 firejail --net=eth0 --net=br0 exit + +# private mode +0 firejail --private exit +1 firejail --private=/etc sleep 1 +1 firejail --private=bingo sleep 1 diff --git a/test/test.sh b/test/test.sh new file mode 100755 index 00000000000..5fe01eb2a82 --- /dev/null +++ b/test/test.sh @@ -0,0 +1,329 @@ +#!/bin/bash + +./chk_config.exp + +./fscheck.sh + +echo "TESTING: version" +./option_version.exp + +echo "TESTING: help" +./option_help.exp + +echo "TESTING: man" +./option_man.exp + +echo "TESTING: list" +./option_list.exp + +echo "TESTING: tree" +./option_tree.exp + +if [ -f /proc/self/uid_map ]; +then + echo "TESTING: noroot" + ./noroot.exp +else + echo "TESTING: user namespaces not available" +fi + +echo "TESTING: doubledash" +mkdir -- -testdir +touch -- -testdir/ttt +cp -- /bin/bash -testdir/. +./doubledash.exp +rm -fr -- -testdir + +echo "TESTING: trace1" +./option-trace.exp + +echo "TESTING: trace2" +rm -f index.html* +./trace.exp +rm -f index.html* + +echo "TESTING: extract command" +./extract_command.exp + +echo "TESTING: rlimit" +./option_rlimit.exp + +echo "TESTING: shutdown" +./option-shutdown.exp + +echo "TESTING: join" +./option-join.exp + +echo "TESTING: firejail in firejail" +./firejail-in-firejail.exp + +echo "TESTING: chroot overlay" +./option_chroot_overlay.exp + +echo "TESTING: tmpfs" +./option_tmpfs.exp + +echo "TESTING: blacklist directory" +./option_blacklist.exp + +echo "TESTING: blacklist file" +./option_blacklist_file.exp + +echo "TESTING: bind as user" +./option_bind_user.exp + +if [ -d /home/bingo ]; +then + echo "TESTING: home sanitize" + ./option_version.exp +fi + +echo "TESTING: chroot as user" +./fs_chroot.exp + +echo "TESTING: /sys" +./fs_sys.exp + +echo "TESTING: readonly" +ls -al > tmpreadonly +./option_readonly.exp +sleep 5 +rm -f tmpreadonly + +echo "TESTING: name" +./name.exp + +echo "TESTING: zsh" +./shell_zsh.exp + +echo "TESTING: csh" +./shell_csh.exp + +which dash +if [ "$?" -eq 0 ]; +then + echo "TESTING: dash" + ./shell_dash.exp +else + echo "TESTING: dash not found" +fi + +which firefox +if [ "$?" -eq 0 ]; +then + echo "TESTING: firefox" + ./firefox.exp +else + echo "TESTING: firefox not found" +fi + +which midori +if [ "$?" -eq 0 ]; +then + echo "TESTING: midori" + ./midori.exp +else + echo "TESTING: midori not found" +fi + +which chromium-browser +if [ "$?" -eq 0 ]; +then + echo "TESTING: chromium" + ./chromium.exp +else + echo "TESTING: chromium not found" +fi + +which opera +if [ "$?" -eq 0 ]; +then + echo "TESTING: opera" + ./opera.exp +else + echo "TESTING: opera not found" +fi + +which transmission-gtk +if [ "$?" -eq 0 ]; +then + echo "TESTING: transmission-gtk" + ./transmission-gtk.exp +else + echo "TESTING: transmission-gtk not found" +fi + +which transmission-qt +if [ "$?" -eq 0 ]; +then + echo "TESTING: transmission-qt" + ./transmission-qt.exp +else + echo "TESTING: transmission-qt not found" +fi + +which evince +if [ "$?" -eq 0 ]; +then + echo "TESTING: evince" + ./evince.exp +else + echo "TESTING: evince not found" +fi + +echo "TESTING: PID" +./pid.exp + +echo "TESTING: output" +./output.exp + +echo "TESTING: profile no permissions" +./profile_noperm.exp + +echo "TESTING: profile syntax" +./profile_syntax.exp + +echo "TESTING: profile syntax 2" +./profile_syntax2.exp + +echo "TESTING: profile rlimit" +./profile_rlimit.exp + +echo "TESTING: profile read-only" +./profile_readonly.exp + +echo "TESTING: profile tmpfs" +./profile_tmpfs.exp + +echo "TESTING: profile applications" +./profile_apps.exp + +echo "TESTING: private" +./private.exp `whoami` + +echo "TESTING: private directory" +rm -fr dirprivate +mkdir dirprivate +./private_dir.exp +rm -fr dirprivate + +echo "TESTING: private directory profile" +rm -fr dirprivate +mkdir dirprivate +./private_dir_profile.exp +rm -fr dirprivate + +echo "TESTING: private keep" +./private-keep.exp + +uname -r | grep "3.18" +if [ "$?" -eq 0 ]; +then + echo "TESTING: overlayfs on 3.18 kernel" + ./fs_overlay.exp +fi + +grep "openSUSE" /etc/os-release +if [ "$?" -eq 0 ]; +then + echo "TESTING: overlayfs" + ./fs_overlay.exp +fi + +grep "Ubuntu" /etc/os-release +if [ "$?" -eq 0 ]; +then + echo "TESTING: overlayfs" + ./fs_overlay.exp +fi + +echo "TESTING: seccomp debug" +./seccomp-debug.exp + +echo "TESTING: seccomp su" +./seccomp-su.exp + +echo "TESTING: seccomp ptrace" +./seccomp-ptrace.exp + +echo "TESTING: seccomp chmod (seccomp lists)" +./seccomp-chmod.exp + +echo "TESTING: seccomp chmod profile (seccomp lists)" +./seccomp-chmod-profile.exp + +echo "TESTING: seccomp empty" +./seccomp-empty.exp + +echo "TESTING: seccomp bad empty" +./seccomp-bad-empty.exp + +echo "TESTING: read/write /var/tmp" +./fs_var_tmp.exp + +echo "TESTING: read/write /var/lock" +./fs_var_lock.exp + +echo "TESTING: read/write /dev/shm" +./fs_dev_shm.exp + +echo "TESTING: local network" +./net_local.exp + +echo "TESTING: no network" +./net_none.exp + +echo "TESTING: network IP" +./net_ip.exp + +echo "TESTING: network MAC" +./net_mac.exp + +echo "TESTING: network bad IP" +./net_badip.exp + +echo "TESTING: network no IP test 1" +./net_noip.exp + +echo "TESTING: network no IP test 2" +./net_noip2.exp + +echo "TESTING: network default gateway test 1" +./net_defaultgw.exp + +echo "TESTING: network default gateway test 2" +./net_defaultgw2.exp + +echo "TESTING: network default gateway test 3" +./net_defaultgw3.exp + +echo "TESTING: netfilter" +./net_netfilter.exp + +echo "TESTING: 4 bridges ARP" +./4bridges_arp.exp + +echo "TESTING: 4 bridges IP" +./4bridges_ip.exp + +echo "TESTING: login SSH" +./login_ssh.exp + +echo "TESTING: ARP" +./net_arp.exp + +echo "TESTING: DNS" +./dns.exp + +echo "TESTING: firemon --arp" +./firemon-arp.exp + +echo "TESTING: firemon --route" +./firemon-route.exp + +echo "TESTING: firemon --seccomp" +./firemon-seccomp.exp + +echo "TESTING: firemon --caps" +./firemon-caps.exp + diff --git a/test/test2.profile b/test/test2.profile new file mode 100644 index 00000000000..d7e1a1f21ea --- /dev/null +++ b/test/test2.profile @@ -0,0 +1,4 @@ +caps +seccomp + private + include test.profile diff --git a/test/tmpfs.profile b/test/tmpfs.profile new file mode 100644 index 00000000000..0680f4d695a --- /dev/null +++ b/test/tmpfs.profile @@ -0,0 +1 @@ +tmpfs /tmp/firejailtestdir \ No newline at end of file diff --git a/test/trace.exp b/test/trace.exp new file mode 100755 index 00000000000..bca3ac3b3e7 --- /dev/null +++ b/test/trace.exp @@ -0,0 +1,95 @@ +#!/usr/bin/expect -f + +set timeout 30 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --trace mkdir ttt\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Child process initialized" +} +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "1:mkdir:mkdir ttt" +} +sleep 1 + +send -- "firejail --trace rmdir ttt\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Child process initialized" +} +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "1:rmdir:rmdir ttt" +} +sleep 1 + +send -- "firejail --trace touch ttt\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} +expect { + timeout {puts "TESTING ERROR 5\n";exit} + "1:touch:open ttt" {puts "OK\n";} + "1:touch:open64 ttt" {puts "OK\n";} +} +sleep 1 + +send -- "firejail --trace rm ttt\r" +expect { + timeout {puts "TESTING ERROR 6\n";exit} + "Child process initialized" +} +expect { + timeout {puts "TESTING ERROR 7\n";exit} + "1:rm:unlinkat ttt" +} +sleep 1 + +send -- "firejail --trace wget -q debian.org\r" +expect { + timeout {puts "TESTING ERROR 8.1\n";exit} + "Child process initialized" +} +expect { + timeout {puts "TESTING ERROR 8.2\n";exit} + "1:bash:open /dev/tty" {puts "OK\n";} + "1:bash:open64 /dev/tty" {puts "OK\n";} +} +expect { + timeout {puts "TESTING ERROR 8.3\n";exit} + "1:wget:fopen64 /etc/wgetrc" {puts "OK\n";} + "1:wget:fopen /etc/wgetrc" {puts "OK\n";} +} +expect { + timeout {puts "TESTING ERROR 8.4\n";exit} + "1:wget:fopen /etc/hosts" +} +expect { + timeout {puts "TESTING ERROR 8.5\n";exit} + "1:wget:connect" +} +expect { + timeout {puts "TESTING ERROR 8.6\n";exit} + "1:wget:fopen64 index.html" {puts "OK\n";} + "1:wget:fopen index.html" {puts "OK\n";} +} +sleep 1 + +send -- "firejail --trace rm index.html\r" +expect { + timeout {puts "TESTING ERROR 9\n";exit} + "Child process initialized" +} +expect { + timeout {puts "TESTING ERROR 10\n";exit} + "1:rm:unlinkat index.html" +} +sleep 1 + + +puts "\n" + diff --git a/test/transmission-gtk.exp b/test/transmission-gtk.exp new file mode 100755 index 00000000000..7760ae3ada4 --- /dev/null +++ b/test/transmission-gtk.exp @@ -0,0 +1,68 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail transmission-gtk\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +sleep 10 + +spawn $env(SHELL) +send -- "firejail --list\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + ":firejail" +} +expect { + timeout {puts "TESTING ERROR 3.1\n";exit} + "transmission-gtk" +} +sleep 1 + +send -- "firejail --name=blablabla\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} +sleep 2 + +spawn $env(SHELL) +send -- "firemon --seccomp\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + ":firejail transmission-gtk" +} +expect { + timeout {puts "TESTING ERROR 5.1 (seccomp)\n";exit} + "Seccomp: 2" +} +expect { + timeout {puts "TESTING ERROR 5.1\n";exit} + "name=blablabla" +} +sleep 1 +send -- "firemon --caps\r" +expect { + timeout {puts "TESTING ERROR 6\n";exit} + ":firejail transmission-gtk" +} +expect { + timeout {puts "TESTING ERROR 6.1\n";exit} + "CapBnd" +} +expect { + timeout {puts "TESTING ERROR 6.2\n";exit} + "0000000000000000" +} +expect { + timeout {puts "TESTING ERROR 6.3\n";exit} + "name=blablabla" +} +sleep 1 + +puts "\n" + diff --git a/test/transmission-qt.exp b/test/transmission-qt.exp new file mode 100755 index 00000000000..85457aeb821 --- /dev/null +++ b/test/transmission-qt.exp @@ -0,0 +1,72 @@ +#!/usr/bin/expect -f + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail transmission-qt\r" +expect { + timeout {puts "TESTING ERROR 0\n";exit} + "Reading profile /etc/firejail/transmission-qt.profile" +} +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +sleep 10 + +spawn $env(SHELL) +send -- "firejail --list\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + ":firejail" +} +expect { + timeout {puts "TESTING ERROR 3.1\n";exit} + "transmission-qt" +} +sleep 1 + +send -- "firejail --name=blablabla\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} +sleep 2 + +spawn $env(SHELL) +send -- "firemon --seccomp\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + ":firejail transmission-qt" +} +expect { + timeout {puts "TESTING ERROR 5.1 (seccomp)\n";exit} + "Seccomp: 2" +} +expect { + timeout {puts "TESTING ERROR 5.1\n";exit} + "name=blablabla" +} +sleep 1 +send -- "firemon --caps\r" +expect { + timeout {puts "TESTING ERROR 6\n";exit} + ":firejail transmission-qt" +} +expect { + timeout {puts "TESTING ERROR 6.1\n";exit} + "CapBnd" +} +expect { + timeout {puts "TESTING ERROR 6.2\n";exit} + "0000000000000000" +} +expect { + timeout {puts "TESTING ERROR 6.3\n";exit} + "name=blablabla" +} +sleep 1 + +puts "\n" +