mirror of
https://github.com/netblue30/firejail.git
synced 2026-05-15 14:16:14 -06:00
intrusion detection system
This commit is contained in:
parent
8b50039a1f
commit
a627071b33
18 changed files with 1118 additions and 10 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -22,12 +22,13 @@ firejail-users.5
|
|||
firejail.1
|
||||
firemon.1
|
||||
firecfg.1
|
||||
jailcheck.5
|
||||
jailcheck.1
|
||||
mkdeb.sh
|
||||
src/firejail/firejail
|
||||
src/firemon/firemon
|
||||
src/firecfg/firecfg
|
||||
src/ftee/ftee
|
||||
src/fids/fids
|
||||
src/tags
|
||||
src/faudit/faudit
|
||||
src/fnet/fnet
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ COMPLETIONDIRS = src/zsh_completion src/bash_completion
|
|||
.PHONY: all
|
||||
all: all_items mydirs $(MAN_TARGET) filters
|
||||
APPS = src/firecfg/firecfg src/firejail/firejail src/firemon/firemon src/profstats/profstats src/jailcheck/jailcheck
|
||||
SBOX_APPS = src/fbuilder/fbuilder src/ftee/ftee
|
||||
SBOX_APPS = src/fbuilder/fbuilder src/ftee/ftee src/fids/fids
|
||||
SBOX_APPS_NON_DUMPABLE = src/fcopy/fcopy src/fldd/fldd src/fnet/fnet src/fnetfilter/fnetfilter
|
||||
MYDIRS = src/lib $(MAN_SRC) $(COMPLETIONDIRS)
|
||||
MYLIBS = src/libpostexecseccomp/libpostexecseccomp.so src/libtrace/libtrace.so src/libtracelog/libtracelog.so
|
||||
|
|
@ -135,7 +135,7 @@ endif
|
|||
install -m 0644 -t $(DESTDIR)$(DOCDIR) COPYING README RELNOTES etc/templates/*
|
||||
# profiles and settings
|
||||
install -m 0755 -d $(DESTDIR)$(sysconfdir)/firejail
|
||||
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
|
||||
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
|
||||
sh -c "if [ ! -f $(DESTDIR)/$(sysconfdir)/firejail/login.users ]; then install -c -m 0644 etc/login.users $(DESTDIR)/$(sysconfdir)/firejail/.; fi;"
|
||||
ifeq ($(BUSYBOX_WORKAROUND),yes)
|
||||
./mketc.sh $(DESTDIR)$(sysconfdir)/firejail/disable-common.inc
|
||||
|
|
|
|||
30
README.md
30
README.md
|
|
@ -202,6 +202,36 @@ The old whitelist/blacklist will remain as aliasses for the next one or two rele
|
|||
in order to give users a chance to switch their local profiles.
|
||||
The latest discussion on this issue is here: https://github.com/netblue30/firejail/issues/4379
|
||||
|
||||
### Intrusion Detection System ###
|
||||
|
||||
We 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),
|
||||
and we generate a [BLAKE2](https://en.wikipedia.org/wiki/BLAKE_%28hash_function%29) checksum in /var/lib/firejail/username.ids.
|
||||
The program runs as regular user, each user has his own file in /var/lib/firejail.
|
||||
|
||||
Initialize the database:
|
||||
`````
|
||||
$ firejail --ids-init
|
||||
Loading /etc/firejail/ids.config config file
|
||||
500 1000 1500 2000
|
||||
2457 files scanned
|
||||
IDS database initialized
|
||||
`````
|
||||
|
||||
Later, we check it:
|
||||
`````
|
||||
$ firejail --ids-check
|
||||
Loading /etc/firejail/ids.config config file
|
||||
500 1000 1500
|
||||
Warning: modified /home/netblue/.bashrc
|
||||
2000
|
||||
2457 files scanned: modified 1, permissions 0, new 0, removed 0
|
||||
`````
|
||||
The program will print the files that have been modified since the database was created, or the files with different access permissions.
|
||||
New files and deleted files are also flagged.
|
||||
|
||||
Currently while scanning the file system symbolic links are not followed, and files the user doesn't have read access are silently dropped.
|
||||
The program can also be run as root (sudo firejail --ids-init/--ids-check).
|
||||
|
||||
### Profile Statistics
|
||||
|
||||
A small tool to print profile statistics. Compile as usual and run in /etc/profiles:
|
||||
|
|
|
|||
3
configure
vendored
3
configure
vendored
|
|
@ -4350,7 +4350,7 @@ fi
|
|||
|
||||
ac_config_files="$ac_config_files mkdeb.sh"
|
||||
|
||||
ac_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"
|
||||
ac_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"
|
||||
|
||||
cat >confcache <<\_ACEOF
|
||||
# This file is a shell script that caches the results of configure
|
||||
|
|
@ -5084,6 +5084,7 @@ do
|
|||
"src/bash_completion/Makefile") CONFIG_FILES="$CONFIG_FILES src/bash_completion/Makefile" ;;
|
||||
"test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;;
|
||||
"src/jailcheck/Makefile") CONFIG_FILES="$CONFIG_FILES src/jailcheck/Makefile" ;;
|
||||
"src/fids/Makefile") CONFIG_FILES="$CONFIG_FILES src/fids/Makefile" ;;
|
||||
|
||||
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
|
||||
esac
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ AC_CONFIG_FILES([Makefile src/common.mk src/lib/Makefile src/fcopy/Makefile src/
|
|||
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/jailcheck/Makefile src/fids/Makefile])
|
||||
AC_OUTPUT
|
||||
|
||||
cat <<EOF
|
||||
|
|
|
|||
134
etc/ids.config
Normal file
134
etc/ids.config
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
# /etc/firejail/ids.config - configuration file for Firejail's Intrusion Detection System
|
||||
#
|
||||
# Each line is a file or directory name such as
|
||||
# /usr/bin
|
||||
# or
|
||||
# ${HOME}/Desktop/*.desktop
|
||||
#
|
||||
# ${HOME} is expanded to user home directory, and * is the regular
|
||||
# globbing match for zero or more characters.
|
||||
#
|
||||
# File or directory names starting with ! are not scanned. For example
|
||||
# !${HOME}/.ssh/known_hosts
|
||||
# ${HOME}/.ssh
|
||||
# will scan all files in ~/.ssh directory with the exception of knonw_hosts
|
||||
#
|
||||
# This config file is overwritten when a new version of Firejail is installed.
|
||||
# For global customization use /etc/firejal/ids.config.local.
|
||||
|
||||
include ids.config.local
|
||||
|
||||
### system executables ###
|
||||
/bin
|
||||
/sbin
|
||||
/usr/bin
|
||||
/usr/sbin
|
||||
/usr/games
|
||||
/usr/libexec
|
||||
|
||||
### user executables ###
|
||||
#/usr/local
|
||||
#/opt
|
||||
|
||||
### system libraries ###
|
||||
#/lib
|
||||
#/usr/lib
|
||||
#/usr/lib32
|
||||
#/usr/lib64
|
||||
#/usr/libx32
|
||||
|
||||
### shells local ###
|
||||
${HOME}/.bashrc # bash
|
||||
${HOME}/.bash_profile
|
||||
${HOME}/.bash_login
|
||||
${HOME}/.bash_logout
|
||||
${HOME}/.zshenv #zsh
|
||||
${HOME}/.zshprofile
|
||||
${HOME}/.zshrc
|
||||
${HOME}/.zlogin
|
||||
${HOME}/.zlogout
|
||||
${HOME}/.config/fish/config.fish # fish
|
||||
${HOME}/.profile # others
|
||||
${HOME}/.login
|
||||
${HOME}/.logout
|
||||
${HOME}/.cshrc
|
||||
${HOME}/.tcshrc
|
||||
${HOME}/.kshrc
|
||||
|
||||
### shells global ###
|
||||
/etc/shells # all
|
||||
/etc/profile
|
||||
/etc/profile.d
|
||||
/etc/environment
|
||||
/etc/skel
|
||||
/etc/dircolors
|
||||
/etc/bash.bashrc # bash
|
||||
/etc/bash_completion*
|
||||
/etc/bashrc
|
||||
/etc/zshenv # zsh
|
||||
/etc/zprofile
|
||||
/etc/zshrc
|
||||
/etc/zlogin
|
||||
/etc/zlogout
|
||||
/etc/fish # fish
|
||||
/etc/complete.tcsh # tcsh
|
||||
/etc/csh.cshrc
|
||||
/etc/csh.login
|
||||
/etc/csh.logout
|
||||
/etc/ksh.kshrc # ksh
|
||||
|
||||
### X11 ###
|
||||
${HOME}/.xsessionrc
|
||||
${HOME}/.xsession
|
||||
${HOME}/.Xsession
|
||||
${HOME}/.xinitrc
|
||||
${HOME}/.xprofile
|
||||
${HOME}/.xmodmaprc
|
||||
${HOME}/.xserverrc
|
||||
${HOME}/.Xresurces
|
||||
/etc/X11
|
||||
|
||||
### window/desktop manager ###
|
||||
${HOME}/.config/autostart
|
||||
${HOME}/Desktop/*.desktop
|
||||
${HOME}/.config/lxsession/LXDE/autostart
|
||||
${HOME}/.gnomerc
|
||||
${HOME}/.gtkrc
|
||||
${HOME}/.kderc
|
||||
|
||||
### security ###
|
||||
${HOME}/.gnupg
|
||||
${HOME}/.config/firejail
|
||||
/etc/apparmor*
|
||||
/etc/selinux
|
||||
/etc/security
|
||||
/etc/group*
|
||||
/etc/gshadow*
|
||||
/etc/passwd*
|
||||
/etc/shadow*
|
||||
/etc/pam.*
|
||||
/etc/sudoers*
|
||||
/etc/securetty
|
||||
/etc/cracklib
|
||||
/etc/libaudit.conf
|
||||
/etc/tripwire
|
||||
/etc/aide
|
||||
/etc/chkrootkit.conf
|
||||
/etc/rkhunter.conf
|
||||
|
||||
*** network security ***
|
||||
/etc/services
|
||||
/etc/hosts.*
|
||||
/etc/ssl
|
||||
/etc/ca-certificates*
|
||||
/usr/share/ca-certificates
|
||||
!${HOME}/.ssh/known_hosts # excluding
|
||||
${HOME}/.ssh
|
||||
/etc/ssh
|
||||
/etc/snort
|
||||
/etc/wireshark
|
||||
|
||||
### system config ###
|
||||
/etc/default
|
||||
/etc/crontab
|
||||
/etc/cron.*
|
||||
|
|
@ -40,7 +40,7 @@ BINOBJS = $(foreach file, $(OBJS), $file)
|
|||
|
||||
CFLAGS = @CFLAGS@
|
||||
CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' $(HAVE_GCOV)
|
||||
CFLAGS += -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' -DBINDIR='"$(bindir)"'
|
||||
CFLAGS += -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' -DBINDIR='"$(bindir)"' -DVARDIR='"/var/lib/firejail"'
|
||||
MANFLAGS = $(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)
|
||||
CFLAGS += $(MANFLAGS)
|
||||
CFLAGS += -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -Wformat -Wformat-security
|
||||
|
|
|
|||
18
src/fids/Makefile.in
Normal file
18
src/fids/Makefile.in
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
.PHONY: all
|
||||
all: fids
|
||||
|
||||
include ../common.mk
|
||||
|
||||
%.o : %.c $(H_FILE_LIST) ../include/common.h
|
||||
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@
|
||||
|
||||
#fseccomp: $(OBJS) ../lib/common.o ../lib/errno.o ../lib/syscall.o
|
||||
fids: $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(EXTRA_LDFLAGS)
|
||||
|
||||
.PHONY: clean
|
||||
clean:; rm -fr *.o fids *.gcov *.gcda *.gcno *.plist
|
||||
|
||||
.PHONY: distclean
|
||||
distclean: clean
|
||||
rm -fr Makefile
|
||||
176
src/fids/blake2b.c
Normal file
176
src/fids/blake2b.c
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2021 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.
|
||||
*/
|
||||
|
||||
/* A simple unkeyed BLAKE2b Implementation based on the official reference
|
||||
* from https://github.com/BLAKE2/BLAKE2.
|
||||
*
|
||||
* The original code was released under CC0 1.0 Universal license (Creative Commons),
|
||||
* a public domain license.
|
||||
*/
|
||||
|
||||
#include "fids.h"
|
||||
|
||||
// little-endian vs big-endian is irrelevant since the checksum is calculated and checked on the same computer.
|
||||
static inline uint64_t load64( const void *src ) {
|
||||
uint64_t w;
|
||||
memcpy( &w, src, sizeof( w ) );
|
||||
return w;
|
||||
}
|
||||
|
||||
// mixing function
|
||||
#define ROTR64(x, y) (((x) >> (y)) ^ ((x) << (64 - (y))))
|
||||
#define G(a, b, c, d, x, y) { \
|
||||
v[a] = v[a] + v[b] + x; \
|
||||
v[d] = ROTR64(v[d] ^ v[a], 32); \
|
||||
v[c] = v[c] + v[d]; \
|
||||
v[b] = ROTR64(v[b] ^ v[c], 24); \
|
||||
v[a] = v[a] + v[b] + y; \
|
||||
v[d] = ROTR64(v[d] ^ v[a], 16); \
|
||||
v[c] = v[c] + v[d]; \
|
||||
v[b] = ROTR64(v[b] ^ v[c], 63); }
|
||||
|
||||
// init vector
|
||||
static const uint64_t iv[8] = {
|
||||
0x6A09E667F3BCC908, 0xBB67AE8584CAA73B,
|
||||
0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1,
|
||||
0x510E527FADE682D1, 0x9B05688C2B3E6C1F,
|
||||
0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179
|
||||
};
|
||||
|
||||
|
||||
const uint8_t sigma[12][16] = {
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
|
||||
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
|
||||
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
|
||||
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
|
||||
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
|
||||
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
|
||||
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
|
||||
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
|
||||
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }
|
||||
};
|
||||
|
||||
// blake2b context
|
||||
typedef struct {
|
||||
uint8_t b[128]; // input buffer
|
||||
uint64_t h[8]; // chained state
|
||||
uint64_t t[2]; // total number of bytes
|
||||
size_t c; // pointer for b[]
|
||||
size_t outlen; // digest size
|
||||
} CTX;
|
||||
|
||||
// compress function
|
||||
static void compress(CTX *ctx, int last) {
|
||||
uint64_t m[16];
|
||||
uint64_t v[16];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
m[i] = load64(&ctx->b[8 * i]);
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
v[i] = ctx->h[i];
|
||||
v[i + 8] = iv[i];
|
||||
}
|
||||
|
||||
v[12] ^= ctx->t[0];
|
||||
v[13] ^= ctx->t[1];
|
||||
if (last)
|
||||
v[14] = ~v[14];
|
||||
|
||||
for (i = 0; i < 12; i++) {
|
||||
G( 0, 4, 8, 12, m[sigma[i][ 0]], m[sigma[i][ 1]]);
|
||||
G( 1, 5, 9, 13, m[sigma[i][ 2]], m[sigma[i][ 3]]);
|
||||
G( 2, 6, 10, 14, m[sigma[i][ 4]], m[sigma[i][ 5]]);
|
||||
G( 3, 7, 11, 15, m[sigma[i][ 6]], m[sigma[i][ 7]]);
|
||||
G( 0, 5, 10, 15, m[sigma[i][ 8]], m[sigma[i][ 9]]);
|
||||
G( 1, 6, 11, 12, m[sigma[i][10]], m[sigma[i][11]]);
|
||||
G( 2, 7, 8, 13, m[sigma[i][12]], m[sigma[i][13]]);
|
||||
G( 3, 4, 9, 14, m[sigma[i][14]], m[sigma[i][15]]);
|
||||
}
|
||||
|
||||
for( i = 0; i < 8; ++i )
|
||||
ctx->h[i] ^= v[i] ^ v[i + 8];
|
||||
}
|
||||
|
||||
static int init(CTX *ctx, size_t outlen) { // (keylen=0: no key)
|
||||
size_t i;
|
||||
|
||||
if (outlen == 0 || outlen > 64)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
ctx->h[i] = iv[i];
|
||||
ctx->h[0] ^= 0x01010000 ^ outlen;
|
||||
|
||||
ctx->t[0] = 0;
|
||||
ctx->t[1] = 0;
|
||||
ctx->c = 0;
|
||||
ctx->outlen = outlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void update(CTX *ctx, const void *in, size_t inlen) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < inlen; i++) {
|
||||
if (ctx->c == 128) {
|
||||
ctx->t[0] += ctx->c;
|
||||
if (ctx->t[0] < ctx->c)
|
||||
ctx->t[1]++;
|
||||
compress(ctx, 0);
|
||||
ctx->c = 0;
|
||||
}
|
||||
ctx->b[ctx->c++] = ((const uint8_t *) in)[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void final(CTX *ctx, void *out) {
|
||||
size_t i;
|
||||
|
||||
ctx->t[0] += ctx->c;
|
||||
if (ctx->t[0] < ctx->c)
|
||||
ctx->t[1]++;
|
||||
|
||||
while (ctx->c < 128)
|
||||
ctx->b[ctx->c++] = 0;
|
||||
compress(ctx, 1);
|
||||
|
||||
for (i = 0; i < ctx->outlen; i++) {
|
||||
((uint8_t *) out)[i] =
|
||||
(ctx->h[i >> 3] >> (8 * (i & 7))) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
// public function
|
||||
int blake2b(void *out, size_t outlen, const void *in, size_t inlen) {
|
||||
CTX ctx;
|
||||
|
||||
if (init(&ctx, outlen))
|
||||
return -1;
|
||||
update(&ctx, in, inlen);
|
||||
final(&ctx, out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
16
src/fids/config
Normal file
16
src/fids/config
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/bin
|
||||
/sbin
|
||||
/usr/bin
|
||||
/usr/sbin
|
||||
/usr/games
|
||||
/opt
|
||||
/usr/share/ca-certificates
|
||||
|
||||
|
||||
/home/netblue/.bashrc
|
||||
/home/netblue/.config/firejail
|
||||
/home/netblue/.config/autostart
|
||||
/home/netblue/Desktop/*.desktop
|
||||
/home/netblue/.ssh
|
||||
/home/netblue/.gnupg
|
||||
|
||||
159
src/fids/db.c
Normal file
159
src/fids/db.c
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2021 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"fids.h"
|
||||
|
||||
typedef struct db_t {
|
||||
struct db_t *next;
|
||||
char *fname;
|
||||
char *checksum;
|
||||
char *mode;
|
||||
int checked;
|
||||
} DB;
|
||||
|
||||
#define MAXBUF 4096
|
||||
static DB *database[HASH_MAX] = {NULL};
|
||||
|
||||
// djb2 hash function by Dan Bernstein
|
||||
static unsigned hash(const char *str) {
|
||||
const unsigned char *s = (unsigned char *) str;
|
||||
unsigned long hash = 5381;
|
||||
int c;
|
||||
|
||||
while (c = *s++)
|
||||
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||
|
||||
return hash & (HASH_MAX - 1);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// for testing the hash table
|
||||
static void db_print(void) {
|
||||
int i;
|
||||
for (i = 0; i < HASH_MAX; i++) {
|
||||
int cnt = 0;
|
||||
DB *ptr = database[i];
|
||||
while (ptr) {
|
||||
cnt++;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
printf("%d ", cnt);
|
||||
fflush(0);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
static void db_add(const char *fname, const char *checksum, const char *mode) {
|
||||
DB *ptr = malloc(sizeof(DB));
|
||||
if (!ptr)
|
||||
errExit("malloc");
|
||||
ptr->fname = strdup(fname);
|
||||
ptr->checksum = strdup(checksum);
|
||||
ptr->mode = strdup(mode);
|
||||
ptr->checked = 0;
|
||||
if (!ptr->fname || !ptr->checksum || !ptr->mode)
|
||||
errExit("strdup");
|
||||
|
||||
unsigned h = hash(fname);
|
||||
ptr->next = database[h];
|
||||
database[h] = ptr;
|
||||
}
|
||||
|
||||
void db_check(const char *fname, const char *checksum, const char *mode) {
|
||||
assert(fname);
|
||||
assert(checksum);
|
||||
assert(mode);
|
||||
|
||||
unsigned h =hash(fname);
|
||||
DB *ptr = database[h];
|
||||
while (ptr) {
|
||||
if (strcmp(fname, ptr->fname) == 0) {
|
||||
ptr->checked = 1;
|
||||
break;
|
||||
}
|
||||
ptr = ptr->next;
|
||||
}
|
||||
|
||||
if (ptr ) {
|
||||
if (strcmp(checksum, ptr->checksum)) {
|
||||
f_modified++;
|
||||
fprintf(stderr, "\nWarning: modified %s\n", fname);
|
||||
}
|
||||
if (strcmp(mode, ptr->mode)) {
|
||||
f_permissions++;
|
||||
fprintf(stderr, "\nWarning: permissions %s: old %s, new %s\n",
|
||||
fname, ptr->mode, mode);
|
||||
}
|
||||
}
|
||||
else {
|
||||
f_new++;
|
||||
fprintf(stderr, "\nWarning: new file %s\n", fname);
|
||||
}
|
||||
}
|
||||
|
||||
void db_missing(void) {
|
||||
int i;
|
||||
for (i = 0; i < HASH_MAX; i++) {
|
||||
DB *ptr = database[i];
|
||||
while (ptr) {
|
||||
if (!ptr->checked) {
|
||||
f_removed++;
|
||||
fprintf(stderr, "Warning: removed %s\n", ptr->fname);
|
||||
}
|
||||
ptr = ptr->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return 0 if ok, 1 if error
|
||||
int db_init(void) {
|
||||
char buf[MAXBUF];
|
||||
while(fgets(buf, MAXBUF, stdin)) {
|
||||
// split - tab separated
|
||||
|
||||
char *mode = buf;
|
||||
char *ptr = strchr(buf, '\t');
|
||||
if (!ptr)
|
||||
goto errexit;
|
||||
*ptr = '\0';
|
||||
|
||||
char *checksum = ptr + 1;
|
||||
ptr = strchr(checksum, '\t');
|
||||
if (!ptr)
|
||||
goto errexit;
|
||||
*ptr = '\0';
|
||||
|
||||
char *fname = ptr + 1;
|
||||
ptr = strchr(fname, '\n');
|
||||
if (!ptr)
|
||||
goto errexit;
|
||||
*ptr = '\0';
|
||||
|
||||
db_add(fname, checksum, mode);
|
||||
}
|
||||
// db_print();
|
||||
|
||||
return 0;
|
||||
|
||||
errexit:
|
||||
fprintf(stderr, "Error fids: database corrupted\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
56
src/fids/db_exclude.c
Normal file
56
src/fids/db_exclude.c
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2021 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"fids.h"
|
||||
|
||||
typedef struct db_exclude_t {
|
||||
struct db_exclude_t *next;
|
||||
char *fname;
|
||||
int len;
|
||||
} DB_EXCLUDE;
|
||||
static DB_EXCLUDE *database = NULL;
|
||||
|
||||
void db_exclude_add(const char *fname) {
|
||||
assert(fname);
|
||||
|
||||
DB_EXCLUDE *ptr = malloc(sizeof(DB_EXCLUDE));
|
||||
if (!ptr)
|
||||
errExit("malloc");
|
||||
|
||||
ptr->fname = strdup(fname);
|
||||
if (!ptr->fname)
|
||||
errExit("strdup");
|
||||
ptr->len = strlen(fname);
|
||||
ptr->next = database;
|
||||
database = ptr;
|
||||
}
|
||||
|
||||
int db_exclude_check(const char *fname) {
|
||||
assert(fname);
|
||||
|
||||
DB_EXCLUDE *ptr = database;
|
||||
while (ptr != NULL) {
|
||||
if (strncmp(fname, ptr->fname, ptr->len) == 0)
|
||||
return 1;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
51
src/fids/fids.h
Normal file
51
src/fids/fids.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2021 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 FIDS_H
|
||||
#define FIDS_H
|
||||
|
||||
#include "../include/common.h"
|
||||
|
||||
// main.c
|
||||
#define MAX_DIR_LEVEL 20 // max directory tree depth
|
||||
#define MAX_INCLUDE_LEVEL 10 // max include level for config files
|
||||
extern int f_scanned;
|
||||
extern int f_modified;
|
||||
extern int f_new;
|
||||
extern int f_removed;
|
||||
extern int f_permissions;
|
||||
|
||||
// db.c
|
||||
#define HASH_MAX 2048 // power of 2
|
||||
int db_init(void);
|
||||
void db_check(const char *fname, const char *checksum, const char *mode);
|
||||
void db_missing(void);
|
||||
|
||||
// db_exclude.c
|
||||
void db_exclude_add(const char *fname);
|
||||
int db_exclude_check(const char *fname);
|
||||
|
||||
|
||||
// blake2b.c
|
||||
//#define KEY_SIZE 128 // key size in bytes
|
||||
#define KEY_SIZE 256
|
||||
//#define KEY_SIZE 512
|
||||
int blake2b(void *out, size_t outlen, const void *in, size_t inlen);
|
||||
|
||||
#endif
|
||||
370
src/fids/main.c
Normal file
370
src/fids/main.c
Normal file
|
|
@ -0,0 +1,370 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2021 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 "fids.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <dirent.h>
|
||||
#include <glob.h>
|
||||
|
||||
#define MAXBUF 4096
|
||||
|
||||
static int dir_level = 1;
|
||||
static int include_level = 0;
|
||||
int arg_init = 0;
|
||||
int arg_check = 0;
|
||||
char *arg_homedir = NULL;
|
||||
char *arg_dbfile = NULL;
|
||||
|
||||
int f_scanned = 0;
|
||||
int f_modified = 0;
|
||||
int f_new = 0;
|
||||
int f_removed = 0;
|
||||
int f_permissions = 0;
|
||||
|
||||
|
||||
|
||||
static inline int is_dir(const char *fname) {
|
||||
assert(fname);
|
||||
|
||||
struct stat s;
|
||||
int rv = stat(fname, &s);
|
||||
if (S_ISDIR(s.st_mode))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int is_link(const char *fname) {
|
||||
assert(fname);
|
||||
|
||||
char c;
|
||||
ssize_t rv = readlink(fname, &c, 1);
|
||||
return (rv != -1);
|
||||
}
|
||||
|
||||
// mode is an array of 10 chars or more
|
||||
static inline void file_mode(const char *fname, char *mode) {
|
||||
assert(fname);
|
||||
assert(mode);
|
||||
|
||||
struct stat s;
|
||||
if (stat(fname, &s)) {
|
||||
*mode = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(mode, (s.st_mode & S_IRUSR) ? "r" : "-");
|
||||
sprintf(mode + 1, (s.st_mode & S_IWUSR) ? "w" : "-");
|
||||
sprintf(mode + 2, (s.st_mode & S_IXUSR) ? "x" : "-");
|
||||
sprintf(mode + 3, (s.st_mode & S_IRGRP) ? "r" : "-");
|
||||
sprintf(mode + 4, (s.st_mode & S_IWGRP) ? "w" : "-");
|
||||
sprintf(mode + 5, (s.st_mode & S_IXGRP) ? "x" : "-");
|
||||
sprintf(mode + 6, (s.st_mode & S_IROTH) ? "r" : "-");
|
||||
sprintf(mode + 7, (s.st_mode & S_IWOTH) ? "w" : "-");
|
||||
sprintf(mode + 8, (s.st_mode & S_IXOTH) ? "x" : "-");
|
||||
}
|
||||
|
||||
|
||||
static void file_checksum(const char *fname) {
|
||||
assert(fname);
|
||||
|
||||
int fd = open(fname, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return;
|
||||
|
||||
off_t size = lseek(fd, 0, SEEK_END);
|
||||
if (size < 0) {
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
char *content = "empty";
|
||||
int mmapped = 0;
|
||||
if (size == 0) {
|
||||
// empty files don't mmap - use "empty" string as the file content
|
||||
size = 6; // strlen("empty") + 1
|
||||
}
|
||||
else {
|
||||
content = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
close(fd);
|
||||
mmapped = 1;
|
||||
}
|
||||
|
||||
unsigned char checksum[KEY_SIZE / 8];
|
||||
blake2b(checksum, sizeof(checksum), content, size);
|
||||
if (mmapped)
|
||||
munmap(content, size);
|
||||
|
||||
// calculate blake2 checksum
|
||||
char str_checksum[(KEY_SIZE / 8) * 2 + 1];
|
||||
int i;
|
||||
char *ptr = str_checksum;
|
||||
for (i = 0; i < sizeof(checksum); i++, ptr += 2)
|
||||
sprintf(ptr, "%02x", (unsigned char ) checksum[i]);
|
||||
|
||||
// build permissions string
|
||||
char mode[10];
|
||||
file_mode(fname, mode);
|
||||
|
||||
if (arg_init)
|
||||
printf("%s\t%s\t%s\n", mode, str_checksum, fname);
|
||||
else if (arg_check)
|
||||
db_check(fname, str_checksum, mode);
|
||||
else
|
||||
assert(0);
|
||||
|
||||
f_scanned++;
|
||||
if (f_scanned % 500 == 0)
|
||||
fprintf(stderr, "%d ", f_scanned);
|
||||
fflush(0);
|
||||
}
|
||||
|
||||
void list_directory(const char *fname) {
|
||||
assert(fname);
|
||||
if (dir_level > MAX_DIR_LEVEL) {
|
||||
fprintf(stderr, "Warning fids: maximum depth level exceeded for %s\n", fname);
|
||||
return;
|
||||
}
|
||||
|
||||
if (db_exclude_check(fname))
|
||||
return;
|
||||
|
||||
if (is_link(fname))
|
||||
return;
|
||||
|
||||
if (!is_dir(fname)) {
|
||||
file_checksum(fname);
|
||||
return;
|
||||
}
|
||||
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
|
||||
if (!(dir = opendir(fname)))
|
||||
return;
|
||||
|
||||
dir_level++;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
continue;
|
||||
char *path;
|
||||
if (asprintf(&path, "%s/%s", fname, entry->d_name) == -1)
|
||||
errExit("asprintf");
|
||||
list_directory(path);
|
||||
free(path);
|
||||
}
|
||||
closedir(dir);
|
||||
dir_level--;
|
||||
}
|
||||
|
||||
void globbing(const char *fname) {
|
||||
assert(fname);
|
||||
|
||||
// filter top directory
|
||||
if (strcmp(fname, "/") == 0)
|
||||
return;
|
||||
|
||||
glob_t globbuf;
|
||||
int globerr = glob(fname, GLOB_NOCHECK | GLOB_NOSORT | GLOB_PERIOD, NULL, &globbuf);
|
||||
if (globerr) {
|
||||
fprintf(stderr, "Error fids: failed to glob pattern %s\n", fname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < globbuf.gl_pathc; i++) {
|
||||
char *path = globbuf.gl_pathv[i];
|
||||
assert(path);
|
||||
|
||||
list_directory(path);
|
||||
}
|
||||
|
||||
globfree(&globbuf);
|
||||
}
|
||||
|
||||
static void process_config(const char *fname) {
|
||||
assert(fname);
|
||||
|
||||
if (++include_level >= MAX_INCLUDE_LEVEL) {
|
||||
fprintf(stderr, "Error ids: maximum include level for config files exceeded\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// make sure the file is owned by root
|
||||
struct stat s;
|
||||
if (stat(fname, &s)) {
|
||||
if (include_level == 1) {
|
||||
fprintf(stderr, "Error ids: config file not found\n");
|
||||
exit(1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (s.st_uid || s.st_gid) {
|
||||
fprintf(stderr, "Error ids: config file not owned by root\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Loading %s config file\n", fname);
|
||||
FILE *fp = fopen(fname, "r");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "Error fids: cannot open config file %s\n", fname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char buf[MAXBUF];
|
||||
int line = 0;
|
||||
while (fgets(buf, MAXBUF, fp)) {
|
||||
line++;
|
||||
|
||||
// trim \n
|
||||
char *ptr = strchr(buf, '\n');
|
||||
if (ptr)
|
||||
*ptr = '\0';
|
||||
|
||||
// comments
|
||||
ptr = strchr(buf, '#');
|
||||
if (ptr)
|
||||
*ptr = '\0';
|
||||
|
||||
// empty space
|
||||
ptr = buf;
|
||||
while (*ptr == ' ' || *ptr == '\t')
|
||||
ptr++;
|
||||
char *start = ptr;
|
||||
|
||||
// empty line
|
||||
if (*start == '\0')
|
||||
continue;
|
||||
|
||||
// trailing spaces
|
||||
ptr = start + strlen(start);
|
||||
ptr--;
|
||||
while (*ptr == ' ' || *ptr == '\t')
|
||||
*ptr-- = '\0';
|
||||
|
||||
// replace ${HOME}
|
||||
if (strncmp(start, "include", 7) == 0) {
|
||||
ptr = start + 7;
|
||||
if ((*ptr != ' ' && *ptr != '\t') || *ptr == '\0') {
|
||||
fprintf(stderr, "Error fids: invalid line %d in %s\n", line, fname);
|
||||
exit(1);
|
||||
}
|
||||
while (*ptr == ' ' || *ptr == '\t')
|
||||
ptr++;
|
||||
|
||||
if (*ptr == '/')
|
||||
process_config(ptr);
|
||||
else {
|
||||
// assume the file is in /etc/firejail
|
||||
char *tmp;
|
||||
if (asprintf(&tmp, "/etc/firejail/%s", ptr) == -1)
|
||||
errExit("asprintf");
|
||||
process_config(tmp);
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
else if (*start == '!') {
|
||||
// exclude file or dir
|
||||
start++;
|
||||
if (strncmp(start, "${HOME}", 7))
|
||||
db_exclude_add(start);
|
||||
else {
|
||||
char *fname;
|
||||
if (asprintf(&fname, "%s%s", arg_homedir, start + 7) == -1)
|
||||
errExit("asprintf");
|
||||
db_exclude_add(fname);
|
||||
free(fname);
|
||||
}
|
||||
}
|
||||
else if (strncmp(start, "${HOME}", 7))
|
||||
globbing(start);
|
||||
else {
|
||||
char *fname;
|
||||
if (asprintf(&fname, "%s%s", arg_homedir, start + 7) == -1)
|
||||
errExit("asprintf");
|
||||
globbing(fname);
|
||||
free(fname);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
include_level--;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void usage(void) {
|
||||
printf("Usage: fids [--help|-h|-?] --init|--check homedir\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int i;
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-h") == 0 ||
|
||||
strcmp(argv[i], "-?") == 0 ||
|
||||
strcmp(argv[i], "--help") == 0) {
|
||||
usage();
|
||||
return 0;
|
||||
}
|
||||
else if (strcmp(argv[i], "--init") == 0)
|
||||
arg_init = 1;
|
||||
else if (strcmp(argv[i], "--check") == 0)
|
||||
arg_check = 1;
|
||||
else if (strncmp(argv[i], "--", 2) == 0) {
|
||||
fprintf(stderr, "Error fids: invalid argument %s\n", argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Error fids: invalid number of arguments\n");
|
||||
exit(1);
|
||||
}
|
||||
arg_homedir = argv[2];
|
||||
|
||||
int op = arg_check + arg_init;
|
||||
if (op == 0 || op == 2) {
|
||||
fprintf(stderr, "Error fids: use either --init or --check\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (arg_init) {
|
||||
process_config(SYSCONFDIR"/ids.config");
|
||||
fprintf(stderr, "\n%d files scanned\n", f_scanned);
|
||||
fprintf(stderr, "IDS database initialized\n");
|
||||
}
|
||||
else if (arg_check) {
|
||||
if (db_init()) {
|
||||
fprintf(stderr, "Error: IDS database not initialized, please run \"firejail --ids-init\"\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
process_config(SYSCONFDIR"/ids.config");
|
||||
fprintf(stderr, "\n%d files scanned: modified %d, permissions %d, new %d, removed %d\n",
|
||||
f_scanned, f_modified, f_permissions, f_new, f_removed);
|
||||
db_missing();
|
||||
}
|
||||
else
|
||||
assert(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -835,7 +835,6 @@ void build_appimage_cmdline(char **command_line, char **window_title, int argc,
|
|||
#define PATH_FNET_MAIN (LIBDIR "/firejail/fnet") // when called from main thread
|
||||
#define PATH_FNET (RUN_FIREJAIL_LIB_DIR "/fnet") // when called from sandbox thread
|
||||
|
||||
//#define PATH_FNETFILTER (LIBDIR "/firejail/fnetfilter")
|
||||
#define PATH_FNETFILTER (RUN_FIREJAIL_LIB_DIR "/fnetfilter")
|
||||
|
||||
#define PATH_FIREMON (PREFIX "/bin/firemon")
|
||||
|
|
@ -848,17 +847,16 @@ void build_appimage_cmdline(char **command_line, char **window_title, int argc,
|
|||
// it is also run from inside the sandbox by --debug; in this case we do an access(filename, X_OK) test first
|
||||
#define PATH_FSEC_PRINT (LIBDIR "/firejail/fsec-print")
|
||||
|
||||
//#define PATH_FSEC_OPTIMIZE (LIBDIR "/firejail/fsec-optimize")
|
||||
#define PATH_FSEC_OPTIMIZE (RUN_FIREJAIL_LIB_DIR "/fsec-optimize")
|
||||
|
||||
//#define PATH_FCOPY (LIBDIR "/firejail/fcopy")
|
||||
#define PATH_FCOPY (RUN_FIREJAIL_LIB_DIR "/fcopy")
|
||||
|
||||
#define SBOX_STDIN_FILE "/run/firejail/mnt/sbox_stdin"
|
||||
|
||||
//#define PATH_FLDD (LIBDIR "/firejail/fldd")
|
||||
#define PATH_FLDD (RUN_FIREJAIL_LIB_DIR "/fldd")
|
||||
|
||||
#define PATH_FIDS (LIBDIR "/firejail/fids")
|
||||
|
||||
// bitmapped filters for sbox_run
|
||||
#define SBOX_ROOT (1 << 0) // run the sandbox as root
|
||||
#define SBOX_USER (1 << 1) // run the sandbox as a regular user
|
||||
|
|
@ -903,4 +901,7 @@ void dhcp_start(void);
|
|||
// selinux.c
|
||||
void selinux_relabel_path(const char *path, const char *inside_path);
|
||||
|
||||
// ids.c
|
||||
void run_ids(int argc, char **argv);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
89
src/firejail/ids.c
Normal file
89
src/firejail/ids.c
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2021 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 <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
static void ids_init(void) {
|
||||
// store checksums as root in /var/lib/firejail/${USERNAME}.ids
|
||||
char *fname;
|
||||
if (asprintf(&fname, VARDIR"/%s.ids", cfg.username) == -1)
|
||||
errExit("asprintf");
|
||||
|
||||
int rv = unlink(fname);
|
||||
(void) rv;
|
||||
int fd = open(fname, O_CREAT | O_TRUNC | O_WRONLY, 0600);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Error: cannot create %s\n", fname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// redirect output
|
||||
close(STDOUT_FILENO);
|
||||
if (dup(fd) != STDOUT_FILENO)
|
||||
errExit("dup");
|
||||
close(fd);
|
||||
|
||||
sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 3, PATH_FIDS, "--init", cfg.homedir);
|
||||
}
|
||||
|
||||
static void ids_check(void) {
|
||||
// store checksums as root in /var/lib/firejail/${USERNAME}.ids
|
||||
char *fname;
|
||||
if (asprintf(&fname, VARDIR"/%s.ids", cfg.username) == -1)
|
||||
errExit("asprintf");
|
||||
|
||||
int fd = open(fname, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Error: cannot open %s\n", fname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// redirect input
|
||||
close(STDIN_FILENO);
|
||||
if (dup(fd) != STDIN_FILENO)
|
||||
errExit("dup");
|
||||
close(fd);
|
||||
|
||||
sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP| SBOX_ALLOW_STDIN, 3, PATH_FIDS, "--check", cfg.homedir);
|
||||
}
|
||||
|
||||
void run_ids(int argc, char **argv) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Error: only one IDS command expected\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
EUID_ROOT();
|
||||
struct stat s;
|
||||
if (stat(VARDIR, &s)) // /var/lib/firejail
|
||||
create_empty_dir_as_root(VARDIR, 0700);
|
||||
|
||||
if (strcmp(argv[1], "--ids-init") == 0)
|
||||
ids_init();
|
||||
else if (strcmp(argv[1], "--ids-check") == 0)
|
||||
ids_check();
|
||||
else
|
||||
fprintf(stderr, "Error: unrecognized IDS command\n");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
|
@ -1068,6 +1068,10 @@ int main(int argc, char **argv, char **envp) {
|
|||
if (check_arg(argc, argv, "--build", 0)) // supports both --build and --build=filename
|
||||
run_builder(argc, argv); // this function will not return
|
||||
|
||||
// intrusion detection system
|
||||
if (check_arg(argc, argv, "--ids-", 0)) // supports both --ids-init and --ids-check
|
||||
run_ids(argc, argv); // this function will not return
|
||||
|
||||
EUID_ROOT();
|
||||
#ifndef HAVE_SUID
|
||||
if (geteuid() != 0) {
|
||||
|
|
|
|||
|
|
@ -98,6 +98,8 @@ static char *usage_str =
|
|||
" --help, -? - this help screen.\n"
|
||||
" --hostname=name - set sandbox hostname.\n"
|
||||
" --hosts-file=file - use file as /etc/hosts.\n"
|
||||
" --ids-check - verify file system.\n"
|
||||
" --ids-init - initialize IDS database.\n"
|
||||
" --ignore=command - ignore command in profile files.\n"
|
||||
#ifdef HAVE_NETWORK
|
||||
" --interface=name - move interface in sandbox.\n"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue