aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@protonmail.com>2021-07-28 08:30:24 -0400
committerLibravatar netblue30 <netblue30@protonmail.com>2021-07-28 08:30:24 -0400
commita627071b33b42dd24a90070236d2f85eeebc423c (patch)
tree5388f450044f8b205812e5f6e740874d40b4dd62
parentMerge pull request #4410 from kmk3/revert-allow-deny-etc (diff)
downloadfirejail-a627071b3.tar.gz
firejail-a627071b3.tar.zst
firejail-a627071b3.zip
intrusion detection system
-rw-r--r--.gitignore3
-rw-r--r--Makefile.in4
-rw-r--r--README.md30
-rwxr-xr-xconfigure3
-rw-r--r--configure.ac2
-rw-r--r--etc/ids.config134
-rw-r--r--src/common.mk.in2
-rw-r--r--src/fids/Makefile.in18
-rw-r--r--src/fids/blake2b.c176
-rw-r--r--src/fids/config16
-rw-r--r--src/fids/db.c159
-rw-r--r--src/fids/db_exclude.c56
-rw-r--r--src/fids/fids.h51
-rw-r--r--src/fids/main.c370
-rw-r--r--src/firejail/firejail.h9
-rw-r--r--src/firejail/ids.c89
-rw-r--r--src/firejail/main.c4
-rw-r--r--src/firejail/usage.c2
18 files changed, 1118 insertions, 10 deletions
diff --git a/.gitignore b/.gitignore
index ea053b503..ace86f218 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,12 +22,13 @@ firejail-users.5
22firejail.1 22firejail.1
23firemon.1 23firemon.1
24firecfg.1 24firecfg.1
25jailcheck.5 25jailcheck.1
26mkdeb.sh 26mkdeb.sh
27src/firejail/firejail 27src/firejail/firejail
28src/firemon/firemon 28src/firemon/firemon
29src/firecfg/firecfg 29src/firecfg/firecfg
30src/ftee/ftee 30src/ftee/ftee
31src/fids/fids
31src/tags 32src/tags
32src/faudit/faudit 33src/faudit/faudit
33src/fnet/fnet 34src/fnet/fnet
diff --git a/Makefile.in b/Makefile.in
index 17bd76464..c94d8c7a4 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -26,7 +26,7 @@ COMPLETIONDIRS = src/zsh_completion src/bash_completion
26.PHONY: all 26.PHONY: all
27all: all_items mydirs $(MAN_TARGET) filters 27all: all_items mydirs $(MAN_TARGET) filters
28APPS = src/firecfg/firecfg src/firejail/firejail src/firemon/firemon src/profstats/profstats src/jailcheck/jailcheck 28APPS = src/firecfg/firecfg src/firejail/firejail src/firemon/firemon src/profstats/profstats src/jailcheck/jailcheck
29SBOX_APPS = src/fbuilder/fbuilder src/ftee/ftee 29SBOX_APPS = src/fbuilder/fbuilder src/ftee/ftee src/fids/fids
30SBOX_APPS_NON_DUMPABLE = src/fcopy/fcopy src/fldd/fldd src/fnet/fnet src/fnetfilter/fnetfilter 30SBOX_APPS_NON_DUMPABLE = src/fcopy/fcopy src/fldd/fldd src/fnet/fnet src/fnetfilter/fnetfilter
31MYDIRS = src/lib $(MAN_SRC) $(COMPLETIONDIRS) 31MYDIRS = src/lib $(MAN_SRC) $(COMPLETIONDIRS)
32MYLIBS = src/libpostexecseccomp/libpostexecseccomp.so src/libtrace/libtrace.so src/libtracelog/libtracelog.so 32MYLIBS = src/libpostexecseccomp/libpostexecseccomp.so src/libtrace/libtrace.so src/libtracelog/libtracelog.so
@@ -135,7 +135,7 @@ endif
135 install -m 0644 -t $(DESTDIR)$(DOCDIR) COPYING README RELNOTES etc/templates/* 135 install -m 0644 -t $(DESTDIR)$(DOCDIR) COPYING README RELNOTES etc/templates/*
136 # profiles and settings 136 # profiles and settings
137 install -m 0755 -d $(DESTDIR)$(sysconfdir)/firejail 137 install -m 0755 -d $(DESTDIR)$(sysconfdir)/firejail
138 install -m 0644 -t $(DESTDIR)$(sysconfdir)/firejail etc/profile-a-l/*.profile etc/profile-m-z/*.profile etc/inc/*.inc etc/net/*.net etc/firejail.config 138 install -m 0644 -t $(DESTDIR)$(sysconfdir)/firejail etc/profile-a-l/*.profile etc/profile-m-z/*.profile etc/inc/*.inc etc/net/*.net etc/firejail.config etc/ids.config
139 sh -c "if [ ! -f $(DESTDIR)/$(sysconfdir)/firejail/login.users ]; then install -c -m 0644 etc/login.users $(DESTDIR)/$(sysconfdir)/firejail/.; fi;" 139 sh -c "if [ ! -f $(DESTDIR)/$(sysconfdir)/firejail/login.users ]; then install -c -m 0644 etc/login.users $(DESTDIR)/$(sysconfdir)/firejail/.; fi;"
140ifeq ($(BUSYBOX_WORKAROUND),yes) 140ifeq ($(BUSYBOX_WORKAROUND),yes)
141 ./mketc.sh $(DESTDIR)$(sysconfdir)/firejail/disable-common.inc 141 ./mketc.sh $(DESTDIR)$(sysconfdir)/firejail/disable-common.inc
diff --git a/README.md b/README.md
index 2fd8e3009..5fde0b74b 100644
--- a/README.md
+++ b/README.md
@@ -202,6 +202,36 @@ The old whitelist/blacklist will remain as aliasses for the next one or two rele
202in order to give users a chance to switch their local profiles. 202in order to give users a chance to switch their local profiles.
203The latest discussion on this issue is here: https://github.com/netblue30/firejail/issues/4379 203The latest discussion on this issue is here: https://github.com/netblue30/firejail/issues/4379
204 204
205### Intrusion Detection System ###
206
207We are adding IDS capabilities in the next release. We have the list of files in [/etc/firejail/ids.config](https://github.com/netblue30/firejail/blob/master/etc/ids.config),
208and we generate a [BLAKE2](https://en.wikipedia.org/wiki/BLAKE_%28hash_function%29) checksum in /var/lib/firejail/username.ids.
209The program runs as regular user, each user has his own file in /var/lib/firejail.
210
211Initialize the database:
212`````
213$ firejail --ids-init
214Loading /etc/firejail/ids.config config file
215500 1000 1500 2000
2162457 files scanned
217IDS database initialized
218`````
219
220Later, we check it:
221`````
222$ firejail --ids-check
223Loading /etc/firejail/ids.config config file
224500 1000 1500
225Warning: modified /home/netblue/.bashrc
2262000
2272457 files scanned: modified 1, permissions 0, new 0, removed 0
228`````
229The program will print the files that have been modified since the database was created, or the files with different access permissions.
230New files and deleted files are also flagged.
231
232Currently while scanning the file system symbolic links are not followed, and files the user doesn't have read access are silently dropped.
233The program can also be run as root (sudo firejail --ids-init/--ids-check).
234
205### Profile Statistics 235### Profile Statistics
206 236
207A small tool to print profile statistics. Compile as usual and run in /etc/profiles: 237A small tool to print profile statistics. Compile as usual and run in /etc/profiles:
diff --git a/configure b/configure
index 9e883191a..f78bbaded 100755
--- a/configure
+++ b/configure
@@ -4350,7 +4350,7 @@ fi
4350 4350
4351ac_config_files="$ac_config_files mkdeb.sh" 4351ac_config_files="$ac_config_files mkdeb.sh"
4352 4352
4353ac_config_files="$ac_config_files Makefile src/common.mk src/lib/Makefile src/fcopy/Makefile src/fnet/Makefile src/firejail/Makefile src/fnetfilter/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/fbuilder/Makefile src/fsec-print/Makefile src/ftee/Makefile src/fseccomp/Makefile src/fldd/Makefile src/libpostexecseccomp/Makefile src/fsec-optimize/Makefile src/profstats/Makefile src/man/Makefile src/zsh_completion/Makefile src/bash_completion/Makefile test/Makefile src/jailcheck/Makefile" 4353ac_config_files="$ac_config_files Makefile src/common.mk src/lib/Makefile src/fcopy/Makefile src/fnet/Makefile src/firejail/Makefile src/fnetfilter/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/fbuilder/Makefile src/fsec-print/Makefile src/ftee/Makefile src/fseccomp/Makefile src/fldd/Makefile src/libpostexecseccomp/Makefile src/fsec-optimize/Makefile src/profstats/Makefile src/man/Makefile src/zsh_completion/Makefile src/bash_completion/Makefile test/Makefile src/jailcheck/Makefile src/fids/Makefile"
4354 4354
4355cat >confcache <<\_ACEOF 4355cat >confcache <<\_ACEOF
4356# This file is a shell script that caches the results of configure 4356# This file is a shell script that caches the results of configure
@@ -5084,6 +5084,7 @@ do
5084 "src/bash_completion/Makefile") CONFIG_FILES="$CONFIG_FILES src/bash_completion/Makefile" ;; 5084 "src/bash_completion/Makefile") CONFIG_FILES="$CONFIG_FILES src/bash_completion/Makefile" ;;
5085 "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;; 5085 "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;;
5086 "src/jailcheck/Makefile") CONFIG_FILES="$CONFIG_FILES src/jailcheck/Makefile" ;; 5086 "src/jailcheck/Makefile") CONFIG_FILES="$CONFIG_FILES src/jailcheck/Makefile" ;;
5087 "src/fids/Makefile") CONFIG_FILES="$CONFIG_FILES src/fids/Makefile" ;;
5087 5088
5088 *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; 5089 *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
5089 esac 5090 esac
diff --git a/configure.ac b/configure.ac
index 1f8e802b5..7879a5239 100644
--- a/configure.ac
+++ b/configure.ac
@@ -300,7 +300,7 @@ AC_CONFIG_FILES([Makefile src/common.mk src/lib/Makefile src/fcopy/Makefile src/
300src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/fbuilder/Makefile src/fsec-print/Makefile \ 300src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/fbuilder/Makefile src/fsec-print/Makefile \
301src/ftee/Makefile src/fseccomp/Makefile src/fldd/Makefile src/libpostexecseccomp/Makefile src/fsec-optimize/Makefile \ 301src/ftee/Makefile src/fseccomp/Makefile src/fldd/Makefile src/libpostexecseccomp/Makefile src/fsec-optimize/Makefile \
302src/profstats/Makefile src/man/Makefile src/zsh_completion/Makefile src/bash_completion/Makefile test/Makefile \ 302src/profstats/Makefile src/man/Makefile src/zsh_completion/Makefile src/bash_completion/Makefile test/Makefile \
303src/jailcheck/Makefile]) 303src/jailcheck/Makefile src/fids/Makefile])
304AC_OUTPUT 304AC_OUTPUT
305 305
306cat <<EOF 306cat <<EOF
diff --git a/etc/ids.config b/etc/ids.config
new file mode 100644
index 000000000..7e03841c9
--- /dev/null
+++ b/etc/ids.config
@@ -0,0 +1,134 @@
1# /etc/firejail/ids.config - configuration file for Firejail's Intrusion Detection System
2#
3# Each line is a file or directory name such as
4# /usr/bin
5# or
6# ${HOME}/Desktop/*.desktop
7#
8# ${HOME} is expanded to user home directory, and * is the regular
9# globbing match for zero or more characters.
10#
11# File or directory names starting with ! are not scanned. For example
12# !${HOME}/.ssh/known_hosts
13# ${HOME}/.ssh
14# will scan all files in ~/.ssh directory with the exception of knonw_hosts
15#
16# This config file is overwritten when a new version of Firejail is installed.
17# For global customization use /etc/firejal/ids.config.local.
18
19include ids.config.local
20
21### system executables ###
22/bin
23/sbin
24/usr/bin
25/usr/sbin
26/usr/games
27/usr/libexec
28
29### user executables ###
30#/usr/local
31#/opt
32
33### system libraries ###
34#/lib
35#/usr/lib
36#/usr/lib32
37#/usr/lib64
38#/usr/libx32
39
40### shells local ###
41${HOME}/.bashrc # bash
42${HOME}/.bash_profile
43${HOME}/.bash_login
44${HOME}/.bash_logout
45${HOME}/.zshenv #zsh
46${HOME}/.zshprofile
47${HOME}/.zshrc
48${HOME}/.zlogin
49${HOME}/.zlogout
50${HOME}/.config/fish/config.fish # fish
51${HOME}/.profile # others
52${HOME}/.login
53${HOME}/.logout
54${HOME}/.cshrc
55${HOME}/.tcshrc
56${HOME}/.kshrc
57
58### shells global ###
59/etc/shells # all
60/etc/profile
61/etc/profile.d
62/etc/environment
63/etc/skel
64/etc/dircolors
65/etc/bash.bashrc # bash
66/etc/bash_completion*
67/etc/bashrc
68/etc/zshenv # zsh
69/etc/zprofile
70/etc/zshrc
71/etc/zlogin
72/etc/zlogout
73/etc/fish # fish
74/etc/complete.tcsh # tcsh
75/etc/csh.cshrc
76/etc/csh.login
77/etc/csh.logout
78/etc/ksh.kshrc # ksh
79
80### X11 ###
81${HOME}/.xsessionrc
82${HOME}/.xsession
83${HOME}/.Xsession
84${HOME}/.xinitrc
85${HOME}/.xprofile
86${HOME}/.xmodmaprc
87${HOME}/.xserverrc
88${HOME}/.Xresurces
89/etc/X11
90
91### window/desktop manager ###
92${HOME}/.config/autostart
93${HOME}/Desktop/*.desktop
94${HOME}/.config/lxsession/LXDE/autostart
95${HOME}/.gnomerc
96${HOME}/.gtkrc
97${HOME}/.kderc
98
99### security ###
100${HOME}/.gnupg
101${HOME}/.config/firejail
102/etc/apparmor*
103/etc/selinux
104/etc/security
105/etc/group*
106/etc/gshadow*
107/etc/passwd*
108/etc/shadow*
109/etc/pam.*
110/etc/sudoers*
111/etc/securetty
112/etc/cracklib
113/etc/libaudit.conf
114/etc/tripwire
115/etc/aide
116/etc/chkrootkit.conf
117/etc/rkhunter.conf
118
119*** network security ***
120/etc/services
121/etc/hosts.*
122/etc/ssl
123/etc/ca-certificates*
124/usr/share/ca-certificates
125!${HOME}/.ssh/known_hosts # excluding
126${HOME}/.ssh
127/etc/ssh
128/etc/snort
129/etc/wireshark
130
131### system config ###
132/etc/default
133/etc/crontab
134/etc/cron.*
diff --git a/src/common.mk.in b/src/common.mk.in
index 5ae8bf204..d117433dc 100644
--- a/src/common.mk.in
+++ b/src/common.mk.in
@@ -40,7 +40,7 @@ BINOBJS = $(foreach file, $(OBJS), $file)
40 40
41CFLAGS = @CFLAGS@ 41CFLAGS = @CFLAGS@
42CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' $(HAVE_GCOV) 42CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' $(HAVE_GCOV)
43CFLAGS += -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' -DBINDIR='"$(bindir)"' 43CFLAGS += -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' -DBINDIR='"$(bindir)"' -DVARDIR='"/var/lib/firejail"'
44MANFLAGS = $(HAVE_LTS) $(HAVE_OUTPUT) $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_USERTMPFS) $(HAVE_DBUSPROXY) $(HAVE_FIRETUNNEL) $(HAVE_GLOBALCFG) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_FILE_TRANSFER) $(HAVE_SELINUX) $(HAVE_SUID) $(HAVE_FORCE_NONEWPRIVS) 44MANFLAGS = $(HAVE_LTS) $(HAVE_OUTPUT) $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_USERTMPFS) $(HAVE_DBUSPROXY) $(HAVE_FIRETUNNEL) $(HAVE_GLOBALCFG) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_FILE_TRANSFER) $(HAVE_SELINUX) $(HAVE_SUID) $(HAVE_FORCE_NONEWPRIVS)
45CFLAGS += $(MANFLAGS) 45CFLAGS += $(MANFLAGS)
46CFLAGS += -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -Wformat -Wformat-security 46CFLAGS += -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -Wformat -Wformat-security
diff --git a/src/fids/Makefile.in b/src/fids/Makefile.in
new file mode 100644
index 000000000..5530bcee2
--- /dev/null
+++ b/src/fids/Makefile.in
@@ -0,0 +1,18 @@
1.PHONY: all
2all: fids
3
4include ../common.mk
5
6%.o : %.c $(H_FILE_LIST) ../include/common.h
7 $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@
8
9#fseccomp: $(OBJS) ../lib/common.o ../lib/errno.o ../lib/syscall.o
10fids: $(OBJS)
11 $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(EXTRA_LDFLAGS)
12
13.PHONY: clean
14clean:; rm -fr *.o fids *.gcov *.gcda *.gcno *.plist
15
16.PHONY: distclean
17distclean: clean
18 rm -fr Makefile
diff --git a/src/fids/blake2b.c b/src/fids/blake2b.c
new file mode 100644
index 000000000..f2aa5ae66
--- /dev/null
+++ b/src/fids/blake2b.c
@@ -0,0 +1,176 @@
1/*
2 * Copyright (C) 2014-2021 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21/* A simple unkeyed BLAKE2b Implementation based on the official reference
22 * from https://github.com/BLAKE2/BLAKE2.
23 *
24 * The original code was released under CC0 1.0 Universal license (Creative Commons),
25 * a public domain license.
26 */
27
28#include "fids.h"
29
30// little-endian vs big-endian is irrelevant since the checksum is calculated and checked on the same computer.
31static inline uint64_t load64( const void *src ) {
32 uint64_t w;
33 memcpy( &w, src, sizeof( w ) );
34 return w;
35}
36
37// mixing function
38#define ROTR64(x, y) (((x) >> (y)) ^ ((x) << (64 - (y))))
39#define G(a, b, c, d, x, y) { \
40 v[a] = v[a] + v[b] + x; \
41 v[d] = ROTR64(v[d] ^ v[a], 32); \
42 v[c] = v[c] + v[d]; \
43 v[b] = ROTR64(v[b] ^ v[c], 24); \
44 v[a] = v[a] + v[b] + y; \
45 v[d] = ROTR64(v[d] ^ v[a], 16); \
46 v[c] = v[c] + v[d]; \
47 v[b] = ROTR64(v[b] ^ v[c], 63); }
48
49// init vector
50static const uint64_t iv[8] = {
51 0x6A09E667F3BCC908, 0xBB67AE8584CAA73B,
52 0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1,
53 0x510E527FADE682D1, 0x9B05688C2B3E6C1F,
54 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179
55};
56
57
58const uint8_t sigma[12][16] = {
59 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
60 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
61 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
62 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
63 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
64 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
65 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
66 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
67 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
68 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
69 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
70 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }
71};
72
73// blake2b context
74typedef struct {
75 uint8_t b[128]; // input buffer
76 uint64_t h[8]; // chained state
77 uint64_t t[2]; // total number of bytes
78 size_t c; // pointer for b[]
79 size_t outlen; // digest size
80} CTX;
81
82// compress function
83static void compress(CTX *ctx, int last) {
84 uint64_t m[16];
85 uint64_t v[16];
86 size_t i;
87
88 for (i = 0; i < 16; i++)
89 m[i] = load64(&ctx->b[8 * i]);
90
91 for (i = 0; i < 8; i++) {
92 v[i] = ctx->h[i];
93 v[i + 8] = iv[i];
94 }
95
96 v[12] ^= ctx->t[0];
97 v[13] ^= ctx->t[1];
98 if (last)
99 v[14] = ~v[14];
100
101 for (i = 0; i < 12; i++) {
102 G( 0, 4, 8, 12, m[sigma[i][ 0]], m[sigma[i][ 1]]);
103 G( 1, 5, 9, 13, m[sigma[i][ 2]], m[sigma[i][ 3]]);
104 G( 2, 6, 10, 14, m[sigma[i][ 4]], m[sigma[i][ 5]]);
105 G( 3, 7, 11, 15, m[sigma[i][ 6]], m[sigma[i][ 7]]);
106 G( 0, 5, 10, 15, m[sigma[i][ 8]], m[sigma[i][ 9]]);
107 G( 1, 6, 11, 12, m[sigma[i][10]], m[sigma[i][11]]);
108 G( 2, 7, 8, 13, m[sigma[i][12]], m[sigma[i][13]]);
109 G( 3, 4, 9, 14, m[sigma[i][14]], m[sigma[i][15]]);
110 }
111
112 for( i = 0; i < 8; ++i )
113 ctx->h[i] ^= v[i] ^ v[i + 8];
114}
115
116static int init(CTX *ctx, size_t outlen) { // (keylen=0: no key)
117 size_t i;
118
119 if (outlen == 0 || outlen > 64)
120 return -1;
121
122 for (i = 0; i < 8; i++)
123 ctx->h[i] = iv[i];
124 ctx->h[0] ^= 0x01010000 ^ outlen;
125
126 ctx->t[0] = 0;
127 ctx->t[1] = 0;
128 ctx->c = 0;
129 ctx->outlen = outlen;
130
131 return 0;
132}
133
134static void update(CTX *ctx, const void *in, size_t inlen) {
135 size_t i;
136
137 for (i = 0; i < inlen; i++) {
138 if (ctx->c == 128) {
139 ctx->t[0] += ctx->c;
140 if (ctx->t[0] < ctx->c)
141 ctx->t[1]++;
142 compress(ctx, 0);
143 ctx->c = 0;
144 }
145 ctx->b[ctx->c++] = ((const uint8_t *) in)[i];
146 }
147}
148
149static void final(CTX *ctx, void *out) {
150 size_t i;
151
152 ctx->t[0] += ctx->c;
153 if (ctx->t[0] < ctx->c)
154 ctx->t[1]++;
155
156 while (ctx->c < 128)
157 ctx->b[ctx->c++] = 0;
158 compress(ctx, 1);
159
160 for (i = 0; i < ctx->outlen; i++) {
161 ((uint8_t *) out)[i] =
162 (ctx->h[i >> 3] >> (8 * (i & 7))) & 0xFF;
163 }
164}
165
166// public function
167int blake2b(void *out, size_t outlen, const void *in, size_t inlen) {
168 CTX ctx;
169
170 if (init(&ctx, outlen))
171 return -1;
172 update(&ctx, in, inlen);
173 final(&ctx, out);
174
175 return 0;
176}
diff --git a/src/fids/config b/src/fids/config
new file mode 100644
index 000000000..c18c97260
--- /dev/null
+++ b/src/fids/config
@@ -0,0 +1,16 @@
1/bin
2/sbin
3/usr/bin
4/usr/sbin
5/usr/games
6/opt
7/usr/share/ca-certificates
8
9
10/home/netblue/.bashrc
11/home/netblue/.config/firejail
12/home/netblue/.config/autostart
13/home/netblue/Desktop/*.desktop
14/home/netblue/.ssh
15/home/netblue/.gnupg
16
diff --git a/src/fids/db.c b/src/fids/db.c
new file mode 100644
index 000000000..e0021bc48
--- /dev/null
+++ b/src/fids/db.c
@@ -0,0 +1,159 @@
1/*
2 * Copyright (C) 2014-2021 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20#include"fids.h"
21
22typedef struct db_t {
23 struct db_t *next;
24 char *fname;
25 char *checksum;
26 char *mode;
27 int checked;
28} DB;
29
30#define MAXBUF 4096
31static DB *database[HASH_MAX] = {NULL};
32
33// djb2 hash function by Dan Bernstein
34static unsigned hash(const char *str) {
35 const unsigned char *s = (unsigned char *) str;
36 unsigned long hash = 5381;
37 int c;
38
39 while (c = *s++)
40 hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
41
42 return hash & (HASH_MAX - 1);
43}
44
45#if 0
46// for testing the hash table
47static void db_print(void) {
48 int i;
49 for (i = 0; i < HASH_MAX; i++) {
50 int cnt = 0;
51 DB *ptr = database[i];
52 while (ptr) {
53 cnt++;
54 ptr = ptr->next;
55 }
56 printf("%d ", cnt);
57 fflush(0);
58 }
59 printf("\n");
60}
61#endif
62
63static void db_add(const char *fname, const char *checksum, const char *mode) {
64 DB *ptr = malloc(sizeof(DB));
65 if (!ptr)
66 errExit("malloc");
67 ptr->fname = strdup(fname);
68 ptr->checksum = strdup(checksum);
69 ptr->mode = strdup(mode);
70 ptr->checked = 0;
71 if (!ptr->fname || !ptr->checksum || !ptr->mode)
72 errExit("strdup");
73
74 unsigned h = hash(fname);
75 ptr->next = database[h];
76 database[h] = ptr;
77}
78
79void db_check(const char *fname, const char *checksum, const char *mode) {
80 assert(fname);
81 assert(checksum);
82 assert(mode);
83
84 unsigned h =hash(fname);
85 DB *ptr = database[h];
86 while (ptr) {
87 if (strcmp(fname, ptr->fname) == 0) {
88 ptr->checked = 1;
89 break;
90 }
91 ptr = ptr->next;
92 }
93
94 if (ptr ) {
95 if (strcmp(checksum, ptr->checksum)) {
96 f_modified++;
97 fprintf(stderr, "\nWarning: modified %s\n", fname);
98 }
99 if (strcmp(mode, ptr->mode)) {
100 f_permissions++;
101 fprintf(stderr, "\nWarning: permissions %s: old %s, new %s\n",
102 fname, ptr->mode, mode);
103 }
104 }
105 else {
106 f_new++;
107 fprintf(stderr, "\nWarning: new file %s\n", fname);
108 }
109}
110
111void db_missing(void) {
112 int i;
113 for (i = 0; i < HASH_MAX; i++) {
114 DB *ptr = database[i];
115 while (ptr) {
116 if (!ptr->checked) {
117 f_removed++;
118 fprintf(stderr, "Warning: removed %s\n", ptr->fname);
119 }
120 ptr = ptr->next;
121 }
122 }
123}
124
125// return 0 if ok, 1 if error
126int db_init(void) {
127 char buf[MAXBUF];
128 while(fgets(buf, MAXBUF, stdin)) {
129 // split - tab separated
130
131 char *mode = buf;
132 char *ptr = strchr(buf, '\t');
133 if (!ptr)
134 goto errexit;
135 *ptr = '\0';
136
137 char *checksum = ptr + 1;
138 ptr = strchr(checksum, '\t');
139 if (!ptr)
140 goto errexit;
141 *ptr = '\0';
142
143 char *fname = ptr + 1;
144 ptr = strchr(fname, '\n');
145 if (!ptr)
146 goto errexit;
147 *ptr = '\0';
148
149 db_add(fname, checksum, mode);
150 }
151// db_print();
152
153 return 0;
154
155errexit:
156 fprintf(stderr, "Error fids: database corrupted\n");
157 exit(1);
158}
159
diff --git a/src/fids/db_exclude.c b/src/fids/db_exclude.c
new file mode 100644
index 000000000..994e6f9df
--- /dev/null
+++ b/src/fids/db_exclude.c
@@ -0,0 +1,56 @@
1/*
2 * Copyright (C) 2014-2021 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20#include"fids.h"
21
22typedef struct db_exclude_t {
23 struct db_exclude_t *next;
24 char *fname;
25 int len;
26} DB_EXCLUDE;
27static DB_EXCLUDE *database = NULL;
28
29void db_exclude_add(const char *fname) {
30 assert(fname);
31
32 DB_EXCLUDE *ptr = malloc(sizeof(DB_EXCLUDE));
33 if (!ptr)
34 errExit("malloc");
35
36 ptr->fname = strdup(fname);
37 if (!ptr->fname)
38 errExit("strdup");
39 ptr->len = strlen(fname);
40 ptr->next = database;
41 database = ptr;
42}
43
44int db_exclude_check(const char *fname) {
45 assert(fname);
46
47 DB_EXCLUDE *ptr = database;
48 while (ptr != NULL) {
49 if (strncmp(fname, ptr->fname, ptr->len) == 0)
50 return 1;
51 ptr = ptr->next;
52 }
53
54 return 0;
55}
56
diff --git a/src/fids/fids.h b/src/fids/fids.h
new file mode 100644
index 000000000..a2e2886fe
--- /dev/null
+++ b/src/fids/fids.h
@@ -0,0 +1,51 @@
1/*
2 * Copyright (C) 2014-2021 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20#ifndef FIDS_H
21#define FIDS_H
22
23#include "../include/common.h"
24
25// main.c
26#define MAX_DIR_LEVEL 20 // max directory tree depth
27#define MAX_INCLUDE_LEVEL 10 // max include level for config files
28extern int f_scanned;
29extern int f_modified;
30extern int f_new;
31extern int f_removed;
32extern int f_permissions;
33
34// db.c
35#define HASH_MAX 2048 // power of 2
36int db_init(void);
37void db_check(const char *fname, const char *checksum, const char *mode);
38void db_missing(void);
39
40// db_exclude.c
41void db_exclude_add(const char *fname);
42int db_exclude_check(const char *fname);
43
44
45// blake2b.c
46//#define KEY_SIZE 128 // key size in bytes
47#define KEY_SIZE 256
48//#define KEY_SIZE 512
49int blake2b(void *out, size_t outlen, const void *in, size_t inlen);
50
51#endif \ No newline at end of file
diff --git a/src/fids/main.c b/src/fids/main.c
new file mode 100644
index 000000000..b53a9828e
--- /dev/null
+++ b/src/fids/main.c
@@ -0,0 +1,370 @@
1/*
2 * Copyright (C) 2014-2021 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20#include "fids.h"
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <unistd.h>
24#include <fcntl.h>
25#include <sys/mman.h>
26#include <dirent.h>
27#include <glob.h>
28
29#define MAXBUF 4096
30
31static int dir_level = 1;
32static int include_level = 0;
33int arg_init = 0;
34int arg_check = 0;
35char *arg_homedir = NULL;
36char *arg_dbfile = NULL;
37
38int f_scanned = 0;
39int f_modified = 0;
40int f_new = 0;
41int f_removed = 0;
42int f_permissions = 0;
43
44
45
46static inline int is_dir(const char *fname) {
47 assert(fname);
48
49 struct stat s;
50 int rv = stat(fname, &s);
51 if (S_ISDIR(s.st_mode))
52 return 1;
53 return 0;
54}
55
56static inline int is_link(const char *fname) {
57 assert(fname);
58
59 char c;
60 ssize_t rv = readlink(fname, &c, 1);
61 return (rv != -1);
62}
63
64// mode is an array of 10 chars or more
65static inline void file_mode(const char *fname, char *mode) {
66 assert(fname);
67 assert(mode);
68
69 struct stat s;
70 if (stat(fname, &s)) {
71 *mode = '\0';
72 return;
73 }
74
75 sprintf(mode, (s.st_mode & S_IRUSR) ? "r" : "-");
76 sprintf(mode + 1, (s.st_mode & S_IWUSR) ? "w" : "-");
77 sprintf(mode + 2, (s.st_mode & S_IXUSR) ? "x" : "-");
78 sprintf(mode + 3, (s.st_mode & S_IRGRP) ? "r" : "-");
79 sprintf(mode + 4, (s.st_mode & S_IWGRP) ? "w" : "-");
80 sprintf(mode + 5, (s.st_mode & S_IXGRP) ? "x" : "-");
81 sprintf(mode + 6, (s.st_mode & S_IROTH) ? "r" : "-");
82 sprintf(mode + 7, (s.st_mode & S_IWOTH) ? "w" : "-");
83 sprintf(mode + 8, (s.st_mode & S_IXOTH) ? "x" : "-");
84}
85
86
87static void file_checksum(const char *fname) {
88 assert(fname);
89
90 int fd = open(fname, O_RDONLY);
91 if (fd == -1)
92 return;
93
94 off_t size = lseek(fd, 0, SEEK_END);
95 if (size < 0) {
96 close(fd);
97 return;
98 }
99
100 char *content = "empty";
101 int mmapped = 0;
102 if (size == 0) {
103 // empty files don't mmap - use "empty" string as the file content
104 size = 6; // strlen("empty") + 1
105 }
106 else {
107 content = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
108 close(fd);
109 mmapped = 1;
110 }
111
112 unsigned char checksum[KEY_SIZE / 8];
113 blake2b(checksum, sizeof(checksum), content, size);
114 if (mmapped)
115 munmap(content, size);
116
117 // calculate blake2 checksum
118 char str_checksum[(KEY_SIZE / 8) * 2 + 1];
119 int i;
120 char *ptr = str_checksum;
121 for (i = 0; i < sizeof(checksum); i++, ptr += 2)
122 sprintf(ptr, "%02x", (unsigned char ) checksum[i]);
123
124 // build permissions string
125 char mode[10];
126 file_mode(fname, mode);
127
128 if (arg_init)
129 printf("%s\t%s\t%s\n", mode, str_checksum, fname);
130 else if (arg_check)
131 db_check(fname, str_checksum, mode);
132 else
133 assert(0);
134
135 f_scanned++;
136 if (f_scanned % 500 == 0)
137 fprintf(stderr, "%d ", f_scanned);
138 fflush(0);
139}
140
141void list_directory(const char *fname) {
142 assert(fname);
143 if (dir_level > MAX_DIR_LEVEL) {
144 fprintf(stderr, "Warning fids: maximum depth level exceeded for %s\n", fname);
145 return;
146 }
147
148 if (db_exclude_check(fname))
149 return;
150
151 if (is_link(fname))
152 return;
153
154 if (!is_dir(fname)) {
155 file_checksum(fname);
156 return;
157 }
158
159 DIR *dir;
160 struct dirent *entry;
161
162 if (!(dir = opendir(fname)))
163 return;
164
165 dir_level++;
166 while ((entry = readdir(dir)) != NULL) {
167 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
168 continue;
169 char *path;
170 if (asprintf(&path, "%s/%s", fname, entry->d_name) == -1)
171 errExit("asprintf");
172 list_directory(path);
173 free(path);
174 }
175 closedir(dir);
176 dir_level--;
177}
178
179void globbing(const char *fname) {
180 assert(fname);
181
182 // filter top directory
183 if (strcmp(fname, "/") == 0)
184 return;
185
186 glob_t globbuf;
187 int globerr = glob(fname, GLOB_NOCHECK | GLOB_NOSORT | GLOB_PERIOD, NULL, &globbuf);
188 if (globerr) {
189 fprintf(stderr, "Error fids: failed to glob pattern %s\n", fname);
190 exit(1);
191 }
192
193 int i;
194 for (i = 0; i < globbuf.gl_pathc; i++) {
195 char *path = globbuf.gl_pathv[i];
196 assert(path);
197
198 list_directory(path);
199 }
200
201 globfree(&globbuf);
202}
203
204static void process_config(const char *fname) {
205 assert(fname);
206
207 if (++include_level >= MAX_INCLUDE_LEVEL) {
208 fprintf(stderr, "Error ids: maximum include level for config files exceeded\n");
209 exit(1);
210 }
211
212 // make sure the file is owned by root
213 struct stat s;
214 if (stat(fname, &s)) {
215 if (include_level == 1) {
216 fprintf(stderr, "Error ids: config file not found\n");
217 exit(1);
218 }
219 return;
220 }
221 if (s.st_uid || s.st_gid) {
222 fprintf(stderr, "Error ids: config file not owned by root\n");
223 exit(1);
224 }
225
226 fprintf(stderr, "Loading %s config file\n", fname);
227 FILE *fp = fopen(fname, "r");
228 if (!fp) {
229 fprintf(stderr, "Error fids: cannot open config file %s\n", fname);
230 exit(1);
231 }
232
233 char buf[MAXBUF];
234 int line = 0;
235 while (fgets(buf, MAXBUF, fp)) {
236 line++;
237
238 // trim \n
239 char *ptr = strchr(buf, '\n');
240 if (ptr)
241 *ptr = '\0';
242
243 // comments
244 ptr = strchr(buf, '#');
245 if (ptr)
246 *ptr = '\0';
247
248 // empty space
249 ptr = buf;
250 while (*ptr == ' ' || *ptr == '\t')
251 ptr++;
252 char *start = ptr;
253
254 // empty line
255 if (*start == '\0')
256 continue;
257
258 // trailing spaces
259 ptr = start + strlen(start);
260 ptr--;
261 while (*ptr == ' ' || *ptr == '\t')
262 *ptr-- = '\0';
263
264 // replace ${HOME}
265 if (strncmp(start, "include", 7) == 0) {
266 ptr = start + 7;
267 if ((*ptr != ' ' && *ptr != '\t') || *ptr == '\0') {
268 fprintf(stderr, "Error fids: invalid line %d in %s\n", line, fname);
269 exit(1);
270 }
271 while (*ptr == ' ' || *ptr == '\t')
272 ptr++;
273
274 if (*ptr == '/')
275 process_config(ptr);
276 else {
277 // assume the file is in /etc/firejail
278 char *tmp;
279 if (asprintf(&tmp, "/etc/firejail/%s", ptr) == -1)
280 errExit("asprintf");
281 process_config(tmp);
282 free(tmp);
283 }
284 }
285 else if (*start == '!') {
286 // exclude file or dir
287 start++;
288 if (strncmp(start, "${HOME}", 7))
289 db_exclude_add(start);
290 else {
291 char *fname;
292 if (asprintf(&fname, "%s%s", arg_homedir, start + 7) == -1)
293 errExit("asprintf");
294 db_exclude_add(fname);
295 free(fname);
296 }
297 }
298 else if (strncmp(start, "${HOME}", 7))
299 globbing(start);
300 else {
301 char *fname;
302 if (asprintf(&fname, "%s%s", arg_homedir, start + 7) == -1)
303 errExit("asprintf");
304 globbing(fname);
305 free(fname);
306 }
307 }
308
309 fclose(fp);
310 include_level--;
311}
312
313
314
315void usage(void) {
316 printf("Usage: fids [--help|-h|-?] --init|--check homedir\n");
317}
318
319int main(int argc, char **argv) {
320 int i;
321 for (i = 1; i < argc; i++) {
322 if (strcmp(argv[i], "-h") == 0 ||
323 strcmp(argv[i], "-?") == 0 ||
324 strcmp(argv[i], "--help") == 0) {
325 usage();
326 return 0;
327 }
328 else if (strcmp(argv[i], "--init") == 0)
329 arg_init = 1;
330 else if (strcmp(argv[i], "--check") == 0)
331 arg_check = 1;
332 else if (strncmp(argv[i], "--", 2) == 0) {
333 fprintf(stderr, "Error fids: invalid argument %s\n", argv[i]);
334 exit(1);
335 }
336 }
337
338 if (argc != 3) {
339 fprintf(stderr, "Error fids: invalid number of arguments\n");
340 exit(1);
341 }
342 arg_homedir = argv[2];
343
344 int op = arg_check + arg_init;
345 if (op == 0 || op == 2) {
346 fprintf(stderr, "Error fids: use either --init or --check\n");
347 exit(1);
348 }
349
350 if (arg_init) {
351 process_config(SYSCONFDIR"/ids.config");
352 fprintf(stderr, "\n%d files scanned\n", f_scanned);
353 fprintf(stderr, "IDS database initialized\n");
354 }
355 else if (arg_check) {
356 if (db_init()) {
357 fprintf(stderr, "Error: IDS database not initialized, please run \"firejail --ids-init\"\n");
358 exit(1);
359 }
360
361 process_config(SYSCONFDIR"/ids.config");
362 fprintf(stderr, "\n%d files scanned: modified %d, permissions %d, new %d, removed %d\n",
363 f_scanned, f_modified, f_permissions, f_new, f_removed);
364 db_missing();
365 }
366 else
367 assert(0);
368
369 return 0;
370}
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 545573c08..2a7d88575 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -835,7 +835,6 @@ void build_appimage_cmdline(char **command_line, char **window_title, int argc,
835#define PATH_FNET_MAIN (LIBDIR "/firejail/fnet") // when called from main thread 835#define PATH_FNET_MAIN (LIBDIR "/firejail/fnet") // when called from main thread
836#define PATH_FNET (RUN_FIREJAIL_LIB_DIR "/fnet") // when called from sandbox thread 836#define PATH_FNET (RUN_FIREJAIL_LIB_DIR "/fnet") // when called from sandbox thread
837 837
838//#define PATH_FNETFILTER (LIBDIR "/firejail/fnetfilter")
839#define PATH_FNETFILTER (RUN_FIREJAIL_LIB_DIR "/fnetfilter") 838#define PATH_FNETFILTER (RUN_FIREJAIL_LIB_DIR "/fnetfilter")
840 839
841#define PATH_FIREMON (PREFIX "/bin/firemon") 840#define PATH_FIREMON (PREFIX "/bin/firemon")
@@ -848,17 +847,16 @@ void build_appimage_cmdline(char **command_line, char **window_title, int argc,
848// it is also run from inside the sandbox by --debug; in this case we do an access(filename, X_OK) test first 847// it is also run from inside the sandbox by --debug; in this case we do an access(filename, X_OK) test first
849#define PATH_FSEC_PRINT (LIBDIR "/firejail/fsec-print") 848#define PATH_FSEC_PRINT (LIBDIR "/firejail/fsec-print")
850 849
851//#define PATH_FSEC_OPTIMIZE (LIBDIR "/firejail/fsec-optimize")
852#define PATH_FSEC_OPTIMIZE (RUN_FIREJAIL_LIB_DIR "/fsec-optimize") 850#define PATH_FSEC_OPTIMIZE (RUN_FIREJAIL_LIB_DIR "/fsec-optimize")
853 851
854//#define PATH_FCOPY (LIBDIR "/firejail/fcopy")
855#define PATH_FCOPY (RUN_FIREJAIL_LIB_DIR "/fcopy") 852#define PATH_FCOPY (RUN_FIREJAIL_LIB_DIR "/fcopy")
856 853
857#define SBOX_STDIN_FILE "/run/firejail/mnt/sbox_stdin" 854#define SBOX_STDIN_FILE "/run/firejail/mnt/sbox_stdin"
858 855
859//#define PATH_FLDD (LIBDIR "/firejail/fldd")
860#define PATH_FLDD (RUN_FIREJAIL_LIB_DIR "/fldd") 856#define PATH_FLDD (RUN_FIREJAIL_LIB_DIR "/fldd")
861 857
858#define PATH_FIDS (LIBDIR "/firejail/fids")
859
862// bitmapped filters for sbox_run 860// bitmapped filters for sbox_run
863#define SBOX_ROOT (1 << 0) // run the sandbox as root 861#define SBOX_ROOT (1 << 0) // run the sandbox as root
864#define SBOX_USER (1 << 1) // run the sandbox as a regular user 862#define SBOX_USER (1 << 1) // run the sandbox as a regular user
@@ -903,4 +901,7 @@ void dhcp_start(void);
903// selinux.c 901// selinux.c
904void selinux_relabel_path(const char *path, const char *inside_path); 902void selinux_relabel_path(const char *path, const char *inside_path);
905 903
904// ids.c
905void run_ids(int argc, char **argv);
906
906#endif 907#endif
diff --git a/src/firejail/ids.c b/src/firejail/ids.c
new file mode 100644
index 000000000..59acdb1fe
--- /dev/null
+++ b/src/firejail/ids.c
@@ -0,0 +1,89 @@
1/*
2 * Copyright (C) 2014-2021 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20#include "firejail.h"
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <fcntl.h>
24
25
26static void ids_init(void) {
27 // store checksums as root in /var/lib/firejail/${USERNAME}.ids
28 char *fname;
29 if (asprintf(&fname, VARDIR"/%s.ids", cfg.username) == -1)
30 errExit("asprintf");
31
32 int rv = unlink(fname);
33 (void) rv;
34 int fd = open(fname, O_CREAT | O_TRUNC | O_WRONLY, 0600);
35 if (fd < 0) {
36 fprintf(stderr, "Error: cannot create %s\n", fname);
37 exit(1);
38 }
39
40 // redirect output
41 close(STDOUT_FILENO);
42 if (dup(fd) != STDOUT_FILENO)
43 errExit("dup");
44 close(fd);
45
46 sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 3, PATH_FIDS, "--init", cfg.homedir);
47}
48
49static void ids_check(void) {
50 // store checksums as root in /var/lib/firejail/${USERNAME}.ids
51 char *fname;
52 if (asprintf(&fname, VARDIR"/%s.ids", cfg.username) == -1)
53 errExit("asprintf");
54
55 int fd = open(fname, O_RDONLY);
56 if (fd < 0) {
57 fprintf(stderr, "Error: cannot open %s\n", fname);
58 exit(1);
59 }
60
61 // redirect input
62 close(STDIN_FILENO);
63 if (dup(fd) != STDIN_FILENO)
64 errExit("dup");
65 close(fd);
66
67 sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP| SBOX_ALLOW_STDIN, 3, PATH_FIDS, "--check", cfg.homedir);
68}
69
70void run_ids(int argc, char **argv) {
71 if (argc != 2) {
72 fprintf(stderr, "Error: only one IDS command expected\n");
73 exit(1);
74 }
75
76 EUID_ROOT();
77 struct stat s;
78 if (stat(VARDIR, &s)) // /var/lib/firejail
79 create_empty_dir_as_root(VARDIR, 0700);
80
81 if (strcmp(argv[1], "--ids-init") == 0)
82 ids_init();
83 else if (strcmp(argv[1], "--ids-check") == 0)
84 ids_check();
85 else
86 fprintf(stderr, "Error: unrecognized IDS command\n");
87
88 exit(0);
89} \ No newline at end of file
diff --git a/src/firejail/main.c b/src/firejail/main.c
index 655e6e9d0..ef3bf8bf5 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -1068,6 +1068,10 @@ int main(int argc, char **argv, char **envp) {
1068 if (check_arg(argc, argv, "--build", 0)) // supports both --build and --build=filename 1068 if (check_arg(argc, argv, "--build", 0)) // supports both --build and --build=filename
1069 run_builder(argc, argv); // this function will not return 1069 run_builder(argc, argv); // this function will not return
1070 1070
1071 // intrusion detection system
1072 if (check_arg(argc, argv, "--ids-", 0)) // supports both --ids-init and --ids-check
1073 run_ids(argc, argv); // this function will not return
1074
1071 EUID_ROOT(); 1075 EUID_ROOT();
1072#ifndef HAVE_SUID 1076#ifndef HAVE_SUID
1073 if (geteuid() != 0) { 1077 if (geteuid() != 0) {
diff --git a/src/firejail/usage.c b/src/firejail/usage.c
index b4f3021c7..d843c74ae 100644
--- a/src/firejail/usage.c
+++ b/src/firejail/usage.c
@@ -98,6 +98,8 @@ static char *usage_str =
98 " --help, -? - this help screen.\n" 98 " --help, -? - this help screen.\n"
99 " --hostname=name - set sandbox hostname.\n" 99 " --hostname=name - set sandbox hostname.\n"
100 " --hosts-file=file - use file as /etc/hosts.\n" 100 " --hosts-file=file - use file as /etc/hosts.\n"
101 " --ids-check - verify file system.\n"
102 " --ids-init - initialize IDS database.\n"
101 " --ignore=command - ignore command in profile files.\n" 103 " --ignore=command - ignore command in profile files.\n"
102#ifdef HAVE_NETWORK 104#ifdef HAVE_NETWORK
103 " --interface=name - move interface in sandbox.\n" 105 " --interface=name - move interface in sandbox.\n"