Skip to content

Commit

Permalink
Allow changing error action in seccomp filters
Browse files Browse the repository at this point in the history
Let user specify the action when seccomp filters trigger:
- 'kill' (default): kill the process as before
- errno name like EPERM/ENOSYS: return errno and let the process continue.

Not killing the process weakens Firejail slightly when trying to
contain intrusion, but it may also allow tighter filters if the
alternative is to always allow a system call. It's still possible to
use errno return per syscall.
  • Loading branch information
topimiettinen committed Mar 27, 2020
1 parent d204775 commit 8d5b034
Show file tree
Hide file tree
Showing 13 changed files with 161 additions and 49 deletions.
2 changes: 2 additions & 0 deletions src/firejail/firejail.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ typedef struct config_t {
char *seccomp_list_drop, *seccomp_list_drop32; // seccomp drop list
char *seccomp_list_keep, *seccomp_list_keep32; // seccomp keep list
char *protocol; // protocol list
char *seccomp_error_action; // error action: kill or errno

// rlimits
long long unsigned rlimit_cpu;
Expand Down Expand Up @@ -571,6 +572,7 @@ int seccomp_install_filters(void);
int seccomp_load(const char *fname);
int seccomp_filter_drop(bool native);
int seccomp_filter_keep(bool native);
int seccomp_filter_mdwx(bool native);
void seccomp_print_filter(pid_t pid);

// caps.c
Expand Down
17 changes: 17 additions & 0 deletions src/firejail/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "../include/pid.h"
#include "../include/firejail_user.h"
#include "../include/syscall.h"
#include "../include/seccomp.h"
#define _GNU_SOURCE
#include <sys/utsname.h>
#include <sched.h>
Expand Down Expand Up @@ -76,6 +77,7 @@ int arg_seccomp = 0; // enable default seccomp filter
int arg_seccomp32 = 0; // enable default seccomp filter for 32 bit arch
int arg_seccomp_postexec = 0; // need postexec ld.preload library?
int arg_seccomp_block_secondary = 0; // block any secondary architectures
int arg_seccomp_error_action = SECCOMP_RET_KILL;

int arg_caps_default_filter = 0; // enable default capabilities filter
int arg_caps_drop = 0; // drop list
Expand Down Expand Up @@ -1362,6 +1364,21 @@ int main(int argc, char **argv) {
else
exit_err_feature("seccomp");
}
else if (strncmp(argv[i], "--seccomp-error-action=", 23) == 0) {
if (checkcfg(CFG_SECCOMP)) {
if (strcmp(argv[i] + 23, "kill") == 0)
arg_seccomp_error_action = SECCOMP_RET_KILL;
else {
arg_seccomp_error_action = errno_find_name(argv[i] + 23);
if (arg_seccomp_error_action == -1)
errExit("seccomp-error-action: unknown errno");
}
cfg.seccomp_error_action = strdup(argv[i] + 23);
if (!cfg.seccomp_error_action)
errExit("strdup");
} else
exit_err_feature("seccomp");
}
#endif
else if (strcmp(argv[i], "--caps") == 0) {
arg_caps_default_filter = 1;
Expand Down
22 changes: 22 additions & 0 deletions src/firejail/profile.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "firejail.h"
#include "../include/seccomp.h"
#include "../include/syscall.h"
#include <dirent.h>
#include <sys/stat.h>
extern char *xephyr_screen;
Expand Down Expand Up @@ -870,6 +872,26 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
return 0;
}

// seccomp error action
if (strncmp(ptr, "seccomp-error-action ", 21) == 0) {
#ifdef HAVE_SECCOMP
if (checkcfg(CFG_SECCOMP)) {
if (strcmp(ptr + 21, "kill") == 0)
arg_seccomp_error_action = SECCOMP_RET_KILL;
else {
arg_seccomp_error_action = errno_find_name(ptr + 21);
if (arg_seccomp_error_action == -1)
errExit("seccomp-error-action: unknown errno");
}
cfg.seccomp_error_action = strdup(ptr + 21);
if (!cfg.seccomp_error_action)
errExit("strdup");
} else
warning_feature_disabled("seccomp");
#endif
return 0;
}

// caps drop list
if (strncmp(ptr, "caps.drop ", 10) == 0) {
arg_caps_drop = 1;
Expand Down
5 changes: 5 additions & 0 deletions src/firejail/sandbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
*/

#include "firejail.h"
#include "../include/seccomp.h"
#include <sys/mount.h>
#include <sys/wait.h>
#include <sys/stat.h>
Expand Down Expand Up @@ -1129,6 +1130,10 @@ int sandbox(void* sandbox_arg) {
}

if (arg_memory_deny_write_execute) {
if (arg_seccomp_error_action != SECCOMP_RET_KILL) {
seccomp_filter_mdwx(true);
seccomp_filter_mdwx(false);
}
if (arg_debug)
printf("Install memory write&execute filter\n");
seccomp_load(RUN_SECCOMP_MDWX); // install filter
Expand Down
55 changes: 29 additions & 26 deletions src/firejail/sbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,27 @@
#define O_PATH 010000000
#endif

static struct sock_filter filter[] = {
int sbox_run(unsigned filtermask, int num, ...) {
va_list valist;
va_start(valist, num);

// build argument list
char **arg = malloc((num + 1) * sizeof(char *));
int i;
for (i = 0; i < num; i++)
arg[i] = va_arg(valist, char*);
arg[i] = NULL;
va_end(valist);

int status = sbox_run_v(filtermask, arg);

free(arg);

return status;
}

int sbox_run_v(unsigned filtermask, char * const arg[]) {
struct sock_filter filter[] = {
VALIDATE_ARCHITECTURE,
EXAMINE_SYSCALL,

Expand Down Expand Up @@ -105,33 +125,13 @@ static struct sock_filter filter[] = {
BLACKLIST(SYS_syslog), // kernel printk control
#endif
RETURN_ALLOW
};
};

static struct sock_fprog prog = {
.len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
.filter = filter,
};
struct sock_fprog prog = {
.len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
.filter = filter,
};

int sbox_run(unsigned filtermask, int num, ...) {
va_list valist;
va_start(valist, num);

// build argument list
char **arg = malloc((num + 1) * sizeof(char *));
int i;
for (i = 0; i < num; i++)
arg[i] = va_arg(valist, char*);
arg[i] = NULL;
va_end(valist);

int status = sbox_run_v(filtermask, arg);

free(arg);

return status;
}

int sbox_run_v(unsigned filtermask, char * const arg[]) {
EUID_ROOT();

if (arg_debug) {
Expand Down Expand Up @@ -161,6 +161,9 @@ int sbox_run_v(unsigned filtermask, char * const arg[]) {
new_environment[env_index++] = "FIREJAIL_QUIET=yes";
if (arg_debug) // --debug is passed as an environment variable
new_environment[env_index++] = "FIREJAIL_DEBUG=yes";
if (cfg.seccomp_error_action)
if (asprintf(&new_environment[env_index++], "FIREJAIL_SECCOMP_ERROR_ACTION=%s", cfg.seccomp_error_action) == -1)
errExit("asprintf");

if (filtermask & SBOX_STDIN_FROM_FILE) {
int fd;
Expand Down
35 changes: 33 additions & 2 deletions src/firejail/seccomp.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@ int seccomp_filter_drop(bool native) {
// - seccomp list
// - seccomp
if (cfg.seccomp_list_drop == NULL) {
// default seccomp
if (cfg.seccomp_list == NULL) {
// default seccomp if error action is not changed
if (cfg.seccomp_list == NULL && cfg.seccomp_error_action) {
if (arg_seccomp_block_secondary)
seccomp_filter_block_secondary();
else {
Expand Down Expand Up @@ -243,6 +243,8 @@ int seccomp_filter_drop(bool native) {
list = cfg.seccomp_list32;
}

if (list == NULL)
list = "";
// build the seccomp filter as a regular user
int rv;
if (arg_allow_debuggers)
Expand Down Expand Up @@ -367,6 +369,35 @@ int seccomp_filter_keep(bool native) {
return 0;
}

// create mdwx filter for non-default error action
int seccomp_filter_mdwx(bool native) {
if (arg_debug)
printf("Build memory-deny-write-execute filter\n");

const char *command, *filter, *postexec_filter, *list;
if (native) {
command = "memory-deny-write-execute";
filter = RUN_SECCOMP_MDWX;
} else {
command = "memory-deny-write-execute.32";
filter = RUN_SECCOMP_MDWX_32;
}

// build the seccomp filter as a regular user
int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 3,
PATH_FSECCOMP, command, filter);

if (rv) {
fprintf(stderr, "Error: cannot build memory-deny-write-execute filter\n");
exit(rv);
}

if (arg_debug)
printf("Memory-deny-write-execute filter configured\n");

return 0;
}

void seccomp_print_filter(pid_t pid) {
EUID_ASSERT();

Expand Down
13 changes: 13 additions & 0 deletions src/fseccomp/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "fseccomp.h"
#include "../include/seccomp.h"
int arg_quiet = 0;
int arg_seccomp_error_action = SECCOMP_RET_KILL; // error action: errno or kill

static void usage(void) {
printf("Usage:\n");
Expand Down Expand Up @@ -67,6 +69,17 @@ printf("\n");
if (quiet && strcmp(quiet, "yes") == 0)
arg_quiet = 1;

char *error_action = getenv("FIREJAIL_SECCOMP_ERROR_ACTION");
if (error_action)
if (strcmp(error_action, "kill") == 0)
arg_seccomp_error_action = SECCOMP_RET_KILL;
else {
arg_seccomp_error_action = errno_find_name(error_action);
if (arg_seccomp_error_action == -1)
errExit("seccomp-error-action: unknown errno");
arg_seccomp_error_action |= SECCOMP_RET_ERRNO;
}

if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) {
usage();
return 0;
Expand Down
20 changes: 10 additions & 10 deletions src/fseccomp/seccomp.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ void memory_deny_write_execute(const char *fname) {
EXAMINE_ARGUMENT(2),
BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_WRITE|PROT_EXEC),
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_WRITE|PROT_EXEC, 0, 1),
KILL_PROCESS,
KILL_OR_RETURN_ERRNO,
RETURN_ALLOW,
#endif

Expand All @@ -264,7 +264,7 @@ void memory_deny_write_execute(const char *fname) {
EXAMINE_ARGUMENT(2),
BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_EXEC),
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_EXEC, 0, 1),
KILL_PROCESS,
KILL_OR_RETURN_ERRNO,
RETURN_ALLOW,

// same for pkey_mprotect(,,PROT_EXEC), where available
Expand All @@ -273,7 +273,7 @@ void memory_deny_write_execute(const char *fname) {
EXAMINE_ARGUMENT(2),
BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_EXEC),
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_EXEC, 0, 1),
KILL_PROCESS,
KILL_OR_RETURN_ERRNO,
RETURN_ALLOW,
#endif

Expand All @@ -284,15 +284,15 @@ void memory_deny_write_execute(const char *fname) {
EXAMINE_ARGUMENT(2),
BPF_STMT(BPF_ALU+BPF_AND+BPF_K, SHM_EXEC),
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SHM_EXEC, 0, 1),
KILL_PROCESS,
KILL_OR_RETURN_ERRNO,
RETURN_ALLOW,
#endif
#ifdef SYS_memfd_create
// block memfd_create as it can be used to create
// arbitrary memory contents which can be later mapped
// as executable
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_memfd_create, 0, 1),
KILL_PROCESS,
KILL_OR_RETURN_ERRNO,
RETURN_ALLOW
#endif
};
Expand Down Expand Up @@ -327,7 +327,7 @@ void memory_deny_write_execute_32(const char *fname) {
EXAMINE_ARGUMENT(2),
BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_WRITE|PROT_EXEC),
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_WRITE|PROT_EXEC, 0, 1),
KILL_PROCESS,
KILL_OR_RETURN_ERRNO,
RETURN_ALLOW,
#endif
#ifdef mprotect_32
Expand All @@ -336,7 +336,7 @@ void memory_deny_write_execute_32(const char *fname) {
EXAMINE_ARGUMENT(2),
BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_EXEC),
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_EXEC, 0, 1),
KILL_PROCESS,
KILL_OR_RETURN_ERRNO,
RETURN_ALLOW,
#endif
#ifdef pkey_mprotect_32
Expand All @@ -345,7 +345,7 @@ void memory_deny_write_execute_32(const char *fname) {
EXAMINE_ARGUMENT(2),
BPF_STMT(BPF_ALU+BPF_AND+BPF_K, PROT_EXEC),
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, PROT_EXEC, 0, 1),
KILL_PROCESS,
KILL_OR_RETURN_ERRNO,
RETURN_ALLOW,
#endif

Expand All @@ -355,15 +355,15 @@ void memory_deny_write_execute_32(const char *fname) {
EXAMINE_ARGUMENT(2),
BPF_STMT(BPF_ALU+BPF_AND+BPF_K, SHM_EXEC),
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SHM_EXEC, 0, 1),
KILL_PROCESS,
KILL_OR_RETURN_ERRNO,
RETURN_ALLOW,
#endif
#ifdef memfd_create_32
// block memfd_create as it can be used to create
// arbitrary memory contents which can be later mapped
// as executable
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, memfd_create_32, 0, 1),
KILL_PROCESS,
KILL_OR_RETURN_ERRNO,
#endif
#endif
RETURN_ALLOW
Expand Down
2 changes: 1 addition & 1 deletion src/fseccomp/seccomp_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ void filter_end_blacklist(int fd) {

void filter_end_whitelist(int fd) {
struct sock_filter filter[] = {
KILL_PROCESS
KILL_OR_RETURN_ERRNO
};
write_to_file(fd, filter, sizeof(filter));
}
2 changes: 1 addition & 1 deletion src/fseccomp/seccomp_secondary.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ void seccomp_secondary_block(const char *fname) {
// 5: if MSW(arg0) == 0, goto 7 (allow) else continue to 6 (kill)
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, jmp_from_to(5, 7), 0),
// 6:
KILL_PROCESS,
KILL_OR_RETURN_ERRNO,
// 7:
RETURN_ALLOW
};
Expand Down
Loading

0 comments on commit 8d5b034

Please sign in to comment.