moving --profile to sbox

This commit is contained in:
netblue30 2016-10-28 17:34:16 -04:00
parent 196a857a11
commit ceb85ea65b
14 changed files with 90 additions and 269 deletions

View file

@ -1,6 +1,6 @@
all: apps man
MYLIBS = src/lib
APPS = src/firejail src/firemon src/firecfg src/libtrace src/libtracelog src/ftee src/faudit src/libconnect src/fnet
APPS = src/firejail src/firemon src/firecfg src/libtrace src/libtracelog src/ftee src/faudit src/libconnect src/fnet src/fseccomp
MANPAGES = firejail.1 firemon.1 firecfg.1 firejail-profile.5 firejail-login.5
prefix=@prefix@
@ -77,6 +77,7 @@ realinstall:
install -c -m 0644 src/firecfg/firecfg.config $(DESTDIR)/$(libdir)/firejail/.
install -c -m 0755 src/faudit/faudit $(DESTDIR)/$(libdir)/firejail/.
install -c -m 0755 src/fnet/fnet $(DESTDIR)/$(libdir)/firejail/.
install -c -m 0755 src/fseccomp/fseccomp $(DESTDIR)/$(libdir)/firejail/.
# documents
install -m 0755 -d $(DESTDIR)/$(DOCDIR)
install -c -m 0644 COPYING $(DESTDIR)/$(DOCDIR)/.
@ -126,6 +127,7 @@ install-strip: all
strip src/ftee/ftee
strip src/faudit/faudit
strip src/fnet/fnet
strip src/fseccomp/fseccomp
$(MAKE) realinstall
uninstall:

3
configure vendored
View file

@ -3759,7 +3759,7 @@ if test "$prefix" = /usr; then
sysconfdir="/etc"
fi
ac_config_files="$ac_config_files Makefile src/lib/Makefile src/fnet/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/libconnect/Makefile"
ac_config_files="$ac_config_files Makefile src/lib/Makefile src/fnet/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/libconnect/Makefile src/fseccomp/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@ -4479,6 +4479,7 @@ do
"src/ftee/Makefile") CONFIG_FILES="$CONFIG_FILES src/ftee/Makefile" ;;
"src/faudit/Makefile") CONFIG_FILES="$CONFIG_FILES src/faudit/Makefile" ;;
"src/libconnect/Makefile") CONFIG_FILES="$CONFIG_FILES src/libconnect/Makefile" ;;
"src/fseccomp/Makefile") CONFIG_FILES="$CONFIG_FILES src/fseccomp/Makefile" ;;
*) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
esac

View file

@ -148,7 +148,8 @@ if test "$prefix" = /usr; then
sysconfdir="/etc"
fi
AC_OUTPUT(Makefile src/lib/Makefile src/fnet/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/libconnect/Makefile)
AC_OUTPUT(Makefile src/lib/Makefile src/fnet/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile \
src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/libconnect/Makefile src/fseccomp/Makefile)
echo
echo "Configuration options:"

View file

@ -30,7 +30,7 @@ BINOBJS = $(foreach file, $(OBJS), $file)
CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_SECCOMP) $(HAVE_GLOBALCFG) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_BIND) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security
LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread
%.o : %.c $(H_FILE_LIST) ../include/common.h ../include/euid_common.h ../include/pid.h ../include/seccomp.h
%.o : %.c $(H_FILE_LIST) ../include/common.h ../include/euid_common.h ../include/pid.h ../include/seccomp.h ../include/syscall.h
$(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
firejail: $(OBJS) ../lib/libnetlink.o ../lib/common.o

View file

@ -206,15 +206,4 @@ char *errno_find_nr(int nr) {
return "unknown";
}
void errno_print(void) {
EUID_ASSERT();
int i;
int elems = sizeof(errnolist) / sizeof(errnolist[0]);
for (i = 0; i < elems; i++) {
printf("%d\t- %s\n", errnolist[i].nr, errnolist[i].name);
}
printf("\n");
}
#endif // HAVE_SECCOMP

View file

@ -39,6 +39,7 @@
#define RUN_RO_FILE "/run/firejail/firejail.ro.file"
#define RUN_MNT_DIR "/run/firejail/mnt" // a tmpfs is mounted on this directory before any of the files below are created
#define RUN_SECCOMP_CFG "/run/firejail/mnt/seccomp"
#define RUN_SECCOMP_PROTOCOL "/run/firejail/mnt/seccomp.protocol"
#define RUN_CGROUP_CFG "/run/firejail/mnt/cgroup"
#define RUN_CPU_CFG "/run/firejail/mnt/cpu"
#define RUN_GROUPS_CFG "/run/firejail/mnt/groups"
@ -514,8 +515,6 @@ void caps_print_filter_name(const char *name);
const char *syscall_find_nr(int nr);
// return -1 if error, 0 if no error
int syscall_check_list(const char *slist, void (*callback)(int syscall, int arg), int arg);
// print all available syscallsseccomp
void syscall_print(void);
// fs_trace.c
void fs_trace_preload(void);
@ -598,7 +597,7 @@ void protocol_list();
void protocol_print_filter_name(const char *name);
void protocol_print_filter(pid_t pid);
void protocol_store(const char *prlist);
void protocol_filter(void);
void protocol_filter(const char *fname);
void protocol_filter_save(void);
void protocol_filter_load(const char *fname);
@ -686,11 +685,13 @@ void build_cmdline(char **command_line, char **window_title, int argc, char **ar
// programs
#define PATH_FNET (LIBDIR "/firejail/fnet")
#define PATH_FIREMON (PREFIX "/bin/firemon")
#define PATH_FSECCOMP (LIBDIR "/firejail/fseccomp")
// bitmapped filters for sbox_run
#define SBOX_ROOT 1
#define SBOX_USER 2
#define SBOX_CAPS 4
#define SBOX_SECCOMP 8
// run sbox
int sbox_run(unsigned filter, int num, ...);

View file

@ -296,7 +296,7 @@ void join(pid_t pid, int argc, char **argv, int index) {
if (getuid() != 0)
protocol_filter_load(RUN_PROTOCOL_CFG);
if (cfg.protocol) { // not available for uid 0
protocol_filter();
protocol_filter(RUN_SECCOMP_PROTOCOL);
}
// set seccomp filter

View file

@ -404,8 +404,8 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
#ifdef HAVE_SECCOMP
else if (strcmp(argv[i], "--debug-syscalls") == 0) {
if (checkcfg(CFG_SECCOMP)) {
syscall_print();
exit(0);
int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FSECCOMP, "debug-syscalls");
exit(rv);
}
else {
fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n");
@ -414,7 +414,8 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
}
else if (strcmp(argv[i], "--debug-errnos") == 0) {
if (checkcfg(CFG_SECCOMP)) {
errno_print();
int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FSECCOMP, "debug-errnos");
exit(rv);
}
else {
fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n");
@ -438,8 +439,8 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
exit(0);
}
else if (strcmp(argv[i], "--debug-protocols") == 0) {
protocol_list();
exit(0);
int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 2, PATH_FSECCOMP, "debug-protocols");
exit(rv);
}
else if (strncmp(argv[i], "--protocol.print=", 17) == 0) {
if (checkcfg(CFG_SECCOMP)) {
@ -1117,7 +1118,16 @@ int main(int argc, char **argv) {
#ifdef HAVE_SECCOMP
else if (strncmp(argv[i], "--protocol=", 11) == 0) {
if (checkcfg(CFG_SECCOMP)) {
protocol_store(argv[i] + 11);
if (cfg.protocol) {
if (!arg_quiet)
fprintf(stderr, "Warning: a protocol list is present, the new list \"%s\" will not be installed\n", argv[i] + 11);
}
else {
// store list
cfg.protocol = strdup(argv[i] + 11);
if (!cfg.protocol)
errExit("strdup");
}
}
else {
fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n");

View file

@ -497,8 +497,18 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
if (strncmp(ptr, "protocol ", 9) == 0) {
#ifdef HAVE_SECCOMP
if (checkcfg(CFG_SECCOMP))
protocol_store(ptr + 9);
if (checkcfg(CFG_SECCOMP)) {
if (cfg.protocol) {
if (!arg_quiet)
fprintf(stderr, "Warning: a protocol list is present, the new list \"%s\" will not be installed\n", ptr + 9);
return 0;
}
// store list
cfg.protocol = strdup(ptr + 9);
if (!cfg.protocol)
errExit("strdup");
}
else
fprintf(stderr, "Warning: user seccomp feature is disabled in Firejail configuration file\n");
#endif

View file

@ -18,241 +18,44 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
struct sock_filter filter[] = {
VALIDATE_ARCHITECTURE,
EXAMINE_SYSCALL,
ONLY(SYS_socket),
EXAMINE_ARGUMENT(0), // allow only AF_INET and AF_INET6, drop everything else
WHITELIST(AF_INET),
WHITELIST(AF_INET6),
WHITELIST(AF_PACKET),
RETURN_ERRNO(ENOTSUP)
};
struct sock_fprog prog = {
.len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
.filter = filter,
};
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
perror("prctl(NO_NEW_PRIVS)");
return 1;
}
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
perror("prctl");
return 1;
}
*/
#ifdef HAVE_SECCOMP
#include "firejail.h"
#include "../include/seccomp.h"
#include <sys/types.h>
#include <sys/socket.h>
static char *protocol[] = {
"unix",
"inet",
"inet6",
"netlink",
"packet",
NULL
};
static struct sock_filter protocol_filter_command[] = {
WHITELIST(AF_UNIX),
WHITELIST(AF_INET),
WHITELIST(AF_INET6),
WHITELIST(AF_NETLINK),
WHITELIST(AF_PACKET)
};
// Note: protocol[] and protocol_filter_command are synchronized
// command length
struct sock_filter whitelist[] = {
WHITELIST(AF_UNIX)
};
unsigned whitelist_len = sizeof(whitelist) / sizeof(struct sock_filter);
static int is_protocol(const char *p) {
int i = 0;
while (protocol[i] != NULL) {
if (strcmp(protocol[i], p) == 0)
return 1;
i++;
}
return 0;
}
static struct sock_filter *find_protocol_domain(const char *p) {
int i = 0;
while (protocol[i] != NULL) {
if (strcmp(protocol[i], p) == 0)
return &protocol_filter_command[i * whitelist_len];
i++;
}
return NULL;
}
// --debug-protocols
void protocol_list(void) {
EUID_ASSERT();
#ifndef SYS_socket
fprintf(stderr, "Warning: --protocol not supported on this platform\n");
return;
#endif
int i = 0;
while (protocol[i] != NULL) {
printf("%s, ", protocol[i]);
i++;
}
printf("\n");
}
// check protocol list and store it in cfg structure
void protocol_store(const char *prlist) {
EUID_ASSERT();
assert(prlist);
if (cfg.protocol && !arg_quiet) {
fprintf(stderr, "Warning: a protocol list is present, the new list \"%s\" will not be installed\n", prlist);
return;
}
// temporary list
char *tmplist = strdup(prlist);
if (!tmplist)
errExit("strdup");
// check list
char *token = strtok(tmplist, ",");
if (!token)
goto errout;
while (token) {
if (!is_protocol(token))
goto errout;
token = strtok(NULL, ",");
}
free(tmplist);
// store list
cfg.protocol = strdup(prlist);
if (!cfg.protocol)
errExit("strdup");
return;
errout:
fprintf(stderr, "Error: invalid protocol list\n");
exit(1);
}
// install protocol filter
void protocol_filter(void) {
assert(cfg.protocol);
if (arg_debug)
printf("Set protocol filter: %s\n", cfg.protocol);
void protocol_filter(const char *fname) {
#ifndef SYS_socket
(void) find_protocol_domain;
fprintf(stderr, "Warning: --protocol not supported on this platform\n");
return;
if (arg_debug)
printf("No support for --protocol on this platform\n");
return;
#else
// build the filter
assert(fname);
// check file
struct stat s;
if (stat(fname, &s) == -1) {
fprintf(stderr, "Error: cannot read protocol filter file\n");
exit(1);
}
int size = s.st_size;
// read filter
struct sock_filter filter[32]; // big enough
memset(&filter[0], 0, sizeof(filter));
uint8_t *ptr = (uint8_t *) &filter[0];
// header
struct sock_filter filter_start[] = {
VALIDATE_ARCHITECTURE,
EXAMINE_SYSCALL,
ONLY(SYS_socket),
EXAMINE_ARGUMENT(0)
};
memcpy(ptr, &filter_start[0], sizeof(filter_start));
ptr += sizeof(filter_start);
#if 0
printf("entries %u\n", (unsigned) (sizeof(filter_start) / sizeof(struct sock_filter)));
{
unsigned j;
unsigned char *ptr2 = (unsigned char *) &filter[0];
for (j = 0; j < sizeof(filter); j++, ptr2++) {
if ((j % (sizeof(struct sock_filter))) == 0)
printf("\n%u: ", 1 + (unsigned) (j / (sizeof(struct sock_filter))));
printf("%02x, ", (*ptr2) & 0xff);
int src = open(fname, O_RDONLY);
int rd = 0;
while (rd < size) {
int rv = read(src, (unsigned char *) filter + rd, size - rd);
if (rv == -1) {
fprintf(stderr, "Error: cannot read %s file\n", fname);
exit(1);
}
rd += rv;
}
printf("\n");
}
printf("whitelist_len %u, struct sock_filter len %u\n", whitelist_len, (unsigned) sizeof(struct sock_filter));
#endif
// parse list and add commands
char *tmplist = strdup(cfg.protocol);
if (!tmplist)
errExit("strdup");
char *token = strtok(tmplist, ",");
if (!token)
errExit("strtok");
while (token) {
struct sock_filter *domain = find_protocol_domain(token);
assert(domain);
memcpy(ptr, domain, whitelist_len * sizeof(struct sock_filter));
ptr += whitelist_len * sizeof(struct sock_filter);
token = strtok(NULL, ",");
#if 0
printf("entries %u\n", (unsigned) ((uint64_t) ptr - (uint64_t) (filter)) / (unsigned) sizeof(struct sock_filter));
{
unsigned j;
unsigned char *ptr2 = (unsigned char *) &filter[0];
for (j = 0; j < sizeof(filter); j++, ptr2++) {
if ((j % (sizeof(struct sock_filter))) == 0)
printf("\n%u: ", 1 + (unsigned) (j / (sizeof(struct sock_filter))));
printf("%02x, ", (*ptr2) & 0xff);
}
printf("\n");
}
#endif
}
free(tmplist);
// add end of filter
struct sock_filter filter_end[] = {
RETURN_ERRNO(ENOTSUP)
};
memcpy(ptr, &filter_end[0], sizeof(filter_end));
ptr += sizeof(filter_end);
#if 0
printf("entries %u\n", (unsigned) ((uint64_t) ptr - (uint64_t) (filter)) / (unsigned) sizeof(struct sock_filter));
{
unsigned j;
unsigned char *ptr2 = (unsigned char *) &filter[0];
for (j = 0; j < sizeof(filter); j++, ptr2++) {
if ((j % (sizeof(struct sock_filter))) == 0)
printf("\n%u: ", 1 + (unsigned) (j / (sizeof(struct sock_filter))));
printf("%02x, ", (*ptr2) & 0xff);
}
printf("\n");
}
#endif
close(src);
// install filter
unsigned short entries = (unsigned short) ((uintptr_t) ptr - (uintptr_t) (filter)) / (unsigned) sizeof(struct sock_filter);
unsigned short entries = (unsigned short) size / (unsigned short) sizeof(struct sock_filter);
struct sock_fprog prog = {
.len = entries,
.filter = filter,
@ -262,7 +65,7 @@ printf("entries %u\n", (unsigned) ((uint64_t) ptr - (uint64_t) (filter)) / (uns
fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n");
return;
}
#endif // SYS_socket
#endif
}
void protocol_filter_save(void) {

View file

@ -819,8 +819,24 @@ int sandbox(void* sandbox_arg) {
#ifdef HAVE_SECCOMP
// install protocol filter
if (cfg.protocol) {
protocol_filter(); // install filter
protocol_filter_save(); // save filter in PROTOCOL_CFG
if (arg_debug)
printf("Set protocol filter: %s\n", cfg.protocol);
// as root, create RUN_SECCOMP_PROTOCOL file
// this is where fseccomp program will store the protocol filter
int dst = open(RUN_SECCOMP_PROTOCOL, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (dst == -1)
errExit("open");
close(dst);
if (chown(RUN_SECCOMP_PROTOCOL, getuid(), getgid()) == -1)
errExit("chown");
// build the seccomp filter as a regular user
int rv = sbox_run(SBOX_USER | SBOX_CAPS | SBOX_SECCOMP, 5,
PATH_FSECCOMP, "protocol", "build", cfg.protocol, RUN_SECCOMP_PROTOCOL);
if (rv)
exit(rv);
protocol_filter(RUN_SECCOMP_PROTOCOL); // install filter
protocol_filter_save(); // save filter in RUN_PROTOCOL_CFG
}
// if a keep list is available, disregard the drop list

View file

@ -124,14 +124,14 @@ int sbox_run(unsigned filter, int num, ...) {
arg[i] = NULL;
va_end(valist);
#if 0
//#if 0
{
int i;
for (i = 0; i <= num; i++)
printf("#%s# ", arg[i]);
printf("\n");
}
#endif
//#endif
pid_t child = fork();
if (child < 0)
errExit("fork");
@ -169,7 +169,7 @@ printf("\n");
errExit("waitpid");
}
if (WIFEXITED(status) && status != 0) {
fprintf(stderr, "Error: cannot run fnet\n");
fprintf(stderr, "Error: failed to run %s\n", arg[0]);
exit(1);
}

View file

@ -31,7 +31,7 @@ static SyscallEntry syslist[] = {
//
// code generated using tools/extract-syscall
//
#include "syscall.h"
#include "../include/syscall.h"
//
// end of generated code
//
@ -102,15 +102,4 @@ int syscall_check_list(const char *slist, void (*callback)(int syscall, int arg)
return 0;
}
void syscall_print(void) {
EUID_ASSERT();
int i;
int elems = sizeof(syslist) / sizeof(syslist[0]);
for (i = 0; i < elems; i++) {
printf("%d\t- %s\n", syslist[i].nr, syslist[i].name);
}
printf("\n");
}
#endif // HAVE_SECCOMP

View file

@ -20,7 +20,6 @@
// content extracted from /bits/syscall.h file form glibc 2.22
// using ../tools/extract_syscall tool
#if !defined __x86_64__
#ifdef SYS__llseek
#ifdef __NR__llseek