Skip to content

Commit

Permalink
jaitest - simple sandbox testing utility program
Browse files Browse the repository at this point in the history
  • Loading branch information
netblue30 committed Feb 20, 2021
1 parent 836989b commit 42e2db1
Show file tree
Hide file tree
Showing 14 changed files with 794 additions and 5 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ firejail-users.5
firejail.1
firemon.1
firecfg.1
jailtest.5
mkdeb.sh
src/firejail/firejail
src/firemon/firemon
Expand All @@ -40,6 +41,7 @@ src/fbuilder/fbuilder
src/profstats/profstats
src/bash_completion/firejail.bash_completion
src/zsh_completion/_firejail
src/jailtest/jailtest
uids.h
seccomp
seccomp.debug
Expand Down
7 changes: 5 additions & 2 deletions Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ endif

COMPLETIONDIRS = src/zsh_completion src/bash_completion
all: all_items mydirs $(MAN_TARGET) filters
APPS = src/firecfg/firecfg src/firejail/firejail src/firemon/firemon src/profstats/profstats
APPS = src/firecfg/firecfg src/firejail/firejail src/firemon/firemon src/profstats/profstats src/jailtest/jailtest
SBOX_APPS = src/faudit/faudit src/fbuilder/fbuilder src/ftee/ftee
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
COMPLETIONS = src/zsh_completion/_firejail src/bash_completion/firejail.bash_completion
MANPAGES = firejail.1 firemon.1 firecfg.1 firejail-profile.5 firejail-login.5 firejail-users.5
MANPAGES = firejail.1 firemon.1 firecfg.1 firejail-profile.5 firejail-login.5 firejail-users.5 jailtest.5
SBOX_APPS_NON_DUMPABLE += src/fsec-optimize/fsec-optimize src/fsec-print/fsec-print src/fseccomp/fseccomp
SECCOMP_FILTERS = seccomp seccomp.debug seccomp.32 seccomp.block_secondary seccomp.mdwx seccomp.mdwx.32
ALL_ITEMS = $(APPS) $(SBOX_APPS) $(SBOX_APPS_NON_DUMPABLE) $(MYLIBS)
Expand Down Expand Up @@ -109,6 +109,8 @@ endif
install -m 0755 src/firemon/firemon $(DESTDIR)$(bindir)
# firecfg executable
install -m 0755 src/firecfg/firecfg $(DESTDIR)$(bindir)
# jailtest executable
install -m 0755 src/jailtest/jailtest $(DESTDIR)$(bindir)
# libraries and plugins
install -m 0755 -d $(DESTDIR)$(libdir)/firejail
install -m 0644 -t $(DESTDIR)$(libdir)/firejail $(MYLIBS) $(SECCOMP_FILTERS) src/firecfg/firecfg.config
Expand Down Expand Up @@ -177,6 +179,7 @@ uninstall:
rm -f $(DESTDIR)$(bindir)/firemon
rm -f $(DESTDIR)$(bindir)/firecfg
rm -fr $(DESTDIR)$(libdir)/firejail
rm -fr $(DESTDIR)$(libdir)/jailtest
rm -fr $(DESTDIR)$(datarootdir)/doc/firejail
for man in $(MANPAGES); do \
rm -f $(DESTDIR)$(mandir)/man5/$$man*; \
Expand Down
77 changes: 77 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,84 @@ We also keep a list of profile fixes for previous released versions in [etc-fixe
Milestone page: https://github.com/netblue30/firejail/milestone/1
Release discussion: https://github.com/netblue30/firejail/issues/3696

### jailtest
`````
JAILTEST(1) JAILTEST man page JAILTEST(1)
NAME
jailtest - Simple utility program to test running sandboxes
SYNOPSIS
sudo jailtest [OPTIONS] [directory]
DESCRIPTION
WORK IN PROGRESS! jailtest attaches itself to all sandboxes started by
the user and performs some basic tests on the sandbox filesystem:
1. Virtual directories
jailtest extracts a list with the main virtual directories in‐
stalled by the sandbox. These directories are build by firejail
at startup using --private* and --whitelist commands.
2. Noexec test
jailtest inserts executable programs in /home/username, /tmp,
and /var/tmp directories and tries to run them form inside the
sandbox, thus testing if the directory is executable or not.
3. Read access test
jailtest creates test files in the directories specified by the
user and tries to read them from inside the sandbox.
The program is running as root exclusively under sudo.
OPTIONS
--debug
Print debug messages
-?, --help
Print options end exit.
--version
Print program version and exit.
[directory]
One or more directories in user home to test for read access.
OUTPUT
For each sandbox detected we print the following line:
PID:USER:Sandbox Name:Command
It is followed by relevant sandbox information, such as the virtual di‐
rectories and various warnings.
EXAMPLE
$ sudo jailtest ~/.ssh ~/.gnupg
1429:netblue::/usr/bin/firejail /opt/firefox/firefox
Virtual dirs: /home/netblue, /tmp, /var/tmp, /dev, /etc,
5602:netblue::/usr/bin/firejail /usr/bin/ssh [email protected]
Virtual dirs: /var/tmp, /dev,
Warning: I can read ~/.ssh
5926:netblue::/usr/bin/firejail /usr/bin/gimp-2.10
Virtual dirs: /tmp, /var/tmp, /dev,
Warning: I can run programs in /home/netblue
6394:netblue:libreoffice:/usr/bin/firejail libreoffice
Virtual dirs: /tmp, /var/tmp, /dev,
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.
Homepage: https://firejail.wordpress.com
SEE ALSO
firejail(1), firecfg(1), firejail-profile(5), firejail-login(5) fire‐
jail-users(5)
0.9.65 Feb 2021 JAILTEST(1)
`````

### Profile Statistics

Expand Down
5 changes: 4 additions & 1 deletion configure
Original file line number Diff line number Diff line change
Expand Up @@ -4269,7 +4269,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/faudit/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"
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/faudit/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/jailtest/Makefile"

cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
Expand Down Expand Up @@ -5000,7 +5000,10 @@ do
"src/fsec-optimize/Makefile") CONFIG_FILES="$CONFIG_FILES src/fsec-optimize/Makefile" ;;
"src/profstats/Makefile") CONFIG_FILES="$CONFIG_FILES src/profstats/Makefile" ;;
"src/man/Makefile") CONFIG_FILES="$CONFIG_FILES src/man/Makefile" ;;
"src/zsh_completion/Makefile") CONFIG_FILES="$CONFIG_FILES src/zsh_completion/Makefile" ;;
"src/bash_completion/Makefile") CONFIG_FILES="$CONFIG_FILES src/bash_completion/Makefile" ;;
"test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;;
"src/jailtest/Makefile") CONFIG_FILES="$CONFIG_FILES src/jailtest/Makefile" ;;
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
esac
Expand Down
3 changes: 2 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,8 @@ AC_CONFIG_FILES([mkdeb.sh], [chmod +x mkdeb.sh])
AC_OUTPUT(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/faudit/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/profstats/Makefile src/man/Makefile src/zsh_completion/Makefile src/bash_completion/Makefile test/Makefile \
src/jailtest/Makefile)

echo
echo "Configuration options:"
Expand Down
14 changes: 14 additions & 0 deletions src/jailtest/Makefile.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
all: jailtest

include ../common.mk

%.o : %.c $(H_FILE_LIST) ../include/common.h ../include/pid.h
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@

jailtest: $(OBJS)
$(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/common.o ../lib/pid.o $(LIBS) $(EXTRA_LDFLAGS)

clean:; rm -fr *.o jailtest *.gcov *.gcda *.gcno *.plist

distclean: clean
rm -fr Makefile
124 changes: 124 additions & 0 deletions src/jailtest/access.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#include "jailtest.h"
#include <dirent.h>
#include <sys/wait.h>

typedef struct {
char *tfile;
char *tdir;
} TestDir;

#define MAX_TEST_FILES 16
TestDir td[MAX_TEST_FILES];
static int files_cnt = 0;

void access_setup(const char *directory) {
// I am root!
assert(directory);
assert(user_home_dir);

if (files_cnt >= MAX_TEST_FILES) {
fprintf(stderr, "Error: maximum number of test directories exceded\n");
exit(1);
}

char *fname = strdup(directory);
if (!fname)
errExit("strdup");
if (strncmp(fname, "~/", 2) == 0) {
free(fname);
if (asprintf(&fname, "%s/%s", user_home_dir, directory + 2) == -1)
errExit("asprintf");
}

char *path = realpath(fname, NULL);
free(fname);
if (path == NULL) {
fprintf(stderr, "Warning: invalid directory %s, skipping...\n", directory);
return;
}

// file in home directory
if (strncmp(path, user_home_dir, strlen(user_home_dir)) != 0) {
fprintf(stderr, "Warning: file %s is not in user home directory, skipping...\n", directory);
free(path);
return;
}

// try to open the dir as root
DIR *dir = opendir(path);
if (!dir) {
fprintf(stderr, "Warning: directory %s not found, skipping\n", directory);
free(path);
return;
}
closedir(dir);

// create a test file
char *test_file;
if (asprintf(&test_file, "%s/jailtest-access-%d", path, getpid()) == -1)
errExit("asprintf");

FILE *fp = fopen(test_file, "w");
if (!fp) {
printf("Warning: I cannot create test file in directory %s, skipping...\n", directory);
return;
}
fprintf(fp, "this file was created by firetest utility, you can safely delete it\n");
fclose(fp);
int rv = chown(test_file, user_uid, user_gid);
if (rv)
errExit("chown");

char *dname = strdup(directory);
if (!dname)
errExit("strdup");
td[files_cnt].tdir = dname;
td[files_cnt].tfile = test_file;
files_cnt++;
}

void access_destroy(void) {
// remove test files
int i;

for (i = 0; i < files_cnt; i++) {
int rv = unlink(td[i].tfile);
(void) rv;
}
files_cnt = 0;
}

void access_test(void) {
// I am root in sandbox mount namespace
assert(user_uid);
int i;

pid_t child = fork();
if (child == -1)
errExit("fork");

if (child == 0) { // child
// drop privileges
if (setgid(user_gid) != 0)
errExit("setgid");
if (setuid(user_uid) != 0)
errExit("setuid");

for (i = 0; i < files_cnt; i++) {
assert(td[i].tfile);

// try to open the file for reading
FILE *fp = fopen(td[i].tfile, "r");
if (fp) {

printf(" Warning: I can read %s\n", td[i].tdir);
fclose(fp);
}
}
exit(0);
}

// wait for the child to finish
int status;
wait(&status);
}
32 changes: 32 additions & 0 deletions src/jailtest/jailtest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#ifndef JAILTEST_H
#define JAILTEST_H

#include "../include/common.h"

// main.c
extern uid_t user_uid;
extern gid_t user_gid;
extern char *user_name;
extern char *user_home_dir;

// access.c
void access_setup(const char *directory);
void access_test(void);
void access_destroy(void);

// noexec.c
void noexec_setup(void);
void noexec_test(const char *msg);

// virtual.c
void virtual_setup(const char *directory);
void virtual_destroy(void);
void virtual_test(void);

// utils.c
char *get_sudo_user(void);
char *get_homedir(const char *user, uid_t *uid, gid_t *gid);
int find_child(pid_t parent, pid_t *child);
pid_t switch_to_child(pid_t pid);

#endif

0 comments on commit 42e2db1

Please sign in to comment.