Skip to content

Changeable seccomp error action #3301

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions RELNOTES
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
firejail (0.9.63) baseline; urgency=low
* work in progress
* The blocking action of seccomp filters has been changed from
killing the process to returning EPERM to the caller. To get the
previous behaviour, use --seccomp-error-action=kill or
syscall:kill syntax when constructing filters, or override in
/etc/firejail/firejail.config file.
* DHCP client support
* SELinux labeling support
* 32-bit seccomp filter
3 changes: 3 additions & 0 deletions etc/firejail.config
Original file line number Diff line number Diff line change
@@ -146,3 +146,6 @@

# Xvfb command extra parameters. None by default; this is an example.
# xvfb-extra-params -pixdepths 8 24 32

# Seccomp error action, kill or errno (EPERM, ENOSYS etc)
# seccomp-error-action EPERM
22 changes: 22 additions & 0 deletions src/firejail/checkcfg.c
Original file line number Diff line number Diff line change
@@ -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 <sys/stat.h>
#include <linux/loop.h>

@@ -32,6 +34,7 @@ char *xvfb_screen = "800x600x24";
char *xvfb_extra_params = "";
char *netfilter_default = NULL;
unsigned long join_timeout = 5000000; // microseconds
char *config_seccomp_error_action_str = "EPERM";

int checkcfg(int val) {
assert(val < CFG_MAX);
@@ -51,6 +54,7 @@ int checkcfg(int val) {
cfg_val[CFG_DISABLE_MNT] = 0;
cfg_val[CFG_ARP_PROBES] = DEFAULT_ARP_PROBES;
cfg_val[CFG_XPRA_ATTACH] = 0;
cfg_val[CFG_SECCOMP_ERROR_ACTION] = -1;

// open configuration file
const char *fname = SYSCONFDIR "/firejail.config";
@@ -219,6 +223,24 @@ int checkcfg(int val) {
else if (strncmp(ptr, "join-timeout ", 13) == 0)
join_timeout = strtoul(ptr + 13, NULL, 10) * 1000000; // seconds to microseconds

// seccomp error action
else if (strncmp(ptr, "seccomp-error-action ", 21) == 0) {
#ifdef HAVE_SECCOMP
if (strcmp(ptr + 21, "kill") == 0)
cfg_val[CFG_SECCOMP_ERROR_ACTION] = SECCOMP_RET_KILL;
else {
cfg_val[CFG_SECCOMP_ERROR_ACTION] = errno_find_name(ptr + 21);
if (cfg_val[CFG_SECCOMP_ERROR_ACTION] == -1)
errExit("seccomp-error-action: unknown errno");
}
config_seccomp_error_action_str = strdup(ptr + 21);
if (!config_seccomp_error_action_str)
errExit("strdup");
#else
warning_feature_disabled("seccomp");
#endif
}

else
goto errout;

5 changes: 5 additions & 0 deletions src/firejail/firejail.h
Original file line number Diff line number Diff line change
@@ -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;
@@ -572,6 +573,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
@@ -754,6 +756,7 @@ enum {
CFG_PRIVATE_CACHE,
CFG_CGROUP,
CFG_NAME_CHANGE,
CFG_SECCOMP_ERROR_ACTION,
// CFG_FILE_COPY_LIMIT - file copy limit handled using setenv/getenv
CFG_MAX // this should always be the last entry
};
@@ -764,6 +767,8 @@ extern char *xvfb_screen;
extern char *xvfb_extra_params;
extern char *netfilter_default;
extern unsigned long join_timeout;
extern char *config_seccomp_error_action_str;

int checkcfg(int val);
void print_compiletime_support(void);

32 changes: 32 additions & 0 deletions src/firejail/main.c
Original file line number Diff line number Diff line change
@@ -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>
@@ -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 = 0;

int arg_caps_default_filter = 0; // enable default capabilities filter
int arg_caps_drop = 0; // drop list
@@ -349,6 +351,9 @@ static void init_cfg(int argc, char **argv) {
sandbox_pid = getpid();
time_t t = time(NULL);
srand(t ^ sandbox_pid);

arg_seccomp_error_action = EPERM;
cfg.seccomp_error_action = "EPERM";
}

static void check_network(Bridge *br) {
@@ -973,6 +978,13 @@ void filter_add_errno(int fd, int syscall, int arg, void *ptrarg, bool native) {
(void) ptrarg;
(void) native;
}
void filter_add_blacklist_override(int fd, int syscall, int arg, void *ptrarg, bool native) {
(void) fd;
(void) syscall;
(void) arg;
(void) ptrarg;
(void) native;
}

#ifdef HAVE_SECCOMP
static int check_postexec(const char *list) {
@@ -1398,6 +1410,26 @@ int main(int argc, char **argv, char **envp) {
else
exit_err_feature("seccomp");
}
else if (strncmp(argv[i], "--seccomp-error-action=", 23) == 0) {
if (checkcfg(CFG_SECCOMP)) {
int config_seccomp_error_action = checkcfg(CFG_SECCOMP_ERROR_ACTION);
if (config_seccomp_error_action == -1) {
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-error-action");

} else
exit_err_feature("seccomp");
}
#endif
else if (strcmp(argv[i], "--caps") == 0) {
arg_caps_default_filter = 1;
29 changes: 29 additions & 0 deletions src/firejail/profile.c
Original file line number Diff line number Diff line change
@@ -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;
@@ -870,6 +872,33 @@ 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)) {
int config_seccomp_error_action = checkcfg(CFG_SECCOMP_ERROR_ACTION);
if (config_seccomp_error_action == -1) {
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 {
arg_seccomp_error_action = config_seccomp_error_action;
cfg.seccomp_error_action = config_seccomp_error_action_str;
warning_feature_disabled("seccomp-error-action");
}
} else
warning_feature_disabled("seccomp");
#endif
return 0;
}

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

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

if (arg_memory_deny_write_execute) {
if (arg_seccomp_error_action != EPERM) {
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
55 changes: 29 additions & 26 deletions src/firejail/sbox.c
Original file line number Diff line number Diff line change
@@ -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,

@@ -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) {
@@ -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;
35 changes: 33 additions & 2 deletions src/firejail/seccomp.c
Original file line number Diff line number Diff line change
@@ -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 {
@@ -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)
@@ -365,6 +367,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();

1 change: 1 addition & 0 deletions src/firejail/usage.c
Original file line number Diff line number Diff line change
@@ -209,6 +209,7 @@ static char *usage_str =
" --seccomp.print=name|pid - print the seccomp filter for the sandbox\n"
"\tidentified by name or PID.\n"
" --seccomp.32[.drop,.keep][=syscall] - like above but for 32 bit architecture.\n"
" --seccomp-error-action=errno|kill - change error code or kill process.\n"
#endif
" --shell=none - run the program directly without a user shell.\n"
" --shell=program - set default user shell.\n"
8 changes: 8 additions & 0 deletions src/fsec-print/main.c
Original file line number Diff line number Diff line change
@@ -33,6 +33,14 @@ void filter_add_errno(int fd, int syscall, int arg, void *ptrarg, bool native) {
(void) native;
}

void filter_add_blacklist_override(int fd, int syscall, int arg, void *ptrarg, bool native) {
(void) fd;
(void) syscall;
(void) arg;
(void) ptrarg;
(void) native;
}

int main(int argc, char **argv) {
#if 0
{
13 changes: 13 additions & 0 deletions src/fseccomp/main.c
Original file line number Diff line number Diff line change
@@ -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 = EPERM; // error action: errno or kill

static void usage(void) {
printf("Usage:\n");
@@ -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;
20 changes: 10 additions & 10 deletions src/fseccomp/seccomp.c
Original file line number Diff line number Diff line change
@@ -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

@@ -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
@@ -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

@@ -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
};
@@ -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
@@ -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
@@ -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

@@ -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
15 changes: 14 additions & 1 deletion src/fseccomp/seccomp_file.c
Original file line number Diff line number Diff line change
@@ -112,6 +112,19 @@ void filter_add_blacklist(int fd, int syscall, int arg, void *ptrarg, bool nativ
}
}

void filter_add_blacklist_override(int fd, int syscall, int arg, void *ptrarg, bool native) {
(void) arg;
(void) ptrarg;
(void) native;

if (syscall >= 0) {
int saved_error_action = arg_seccomp_error_action;
arg_seccomp_error_action = SECCOMP_RET_KILL;
write_blacklist(fd, syscall);
arg_seccomp_error_action = saved_error_action;
}
}

// handle seccomp list exceptions (seccomp x,y,!z)
void filter_add_blacklist_for_excluded(int fd, int syscall, int arg, void *ptrarg, bool native) {
(void) arg;
@@ -142,7 +155,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
@@ -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
};
9 changes: 5 additions & 4 deletions src/include/seccomp.h
Original file line number Diff line number Diff line change
@@ -243,7 +243,7 @@ struct seccomp_data {
#define HANDLE_X32_KILL \
BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, X32_SYSCALL_BIT, 1, 0), \
BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0, 1, 0), \
KILL_PROCESS
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)
#endif

#define EXAMINE_SYSCALL BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
@@ -258,7 +258,7 @@ struct seccomp_data {

#define BLACKLIST(syscall_nr) \
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), \
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)
KILL_OR_RETURN_ERRNO

#define WHITELIST(syscall_nr) \
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), \
@@ -274,7 +274,8 @@ struct seccomp_data {
#define RETURN_ERRNO(nr) \
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO | nr)

#define KILL_PROCESS \
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)
extern int arg_seccomp_error_action; // error action: errno or kill
#define KILL_OR_RETURN_ERRNO \
BPF_STMT(BPF_RET+BPF_K, arg_seccomp_error_action)

#endif
1 change: 1 addition & 0 deletions src/include/syscall.h
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@ extern int arg_quiet;

// seccomp_file.c or dummy versions in firejail/main.c and fsec-print/main.c
void filter_add_errno(int fd, int syscall, int arg, void *ptrarg, bool native);
void filter_add_blacklist_override(int fd, int syscall, int arg, void *ptrarg, bool native);

// errno.c
void errno_print(void);
31 changes: 20 additions & 11 deletions src/lib/syscall.c
Original file line number Diff line number Diff line change
@@ -20,11 +20,16 @@
#define _GNU_SOURCE
#include "../include/syscall.h"
#include <assert.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/syscall.h>
#include "../include/common.h"
#include "../include/seccomp.h"

#define SYSCALL_ERROR INT_MAX
#define ERRNO_KILL -2

typedef struct {
const char * const name;
@@ -1430,7 +1435,7 @@ static const SyscallGroupList sysgroups[] = {
}
};

// return -1 if error, or syscall number
// return SYSCALL_ERROR if error, or syscall number
static int syscall_find_name(const char *name) {
int i;
int elems = sizeof(syslist) / sizeof(syslist[0]);
@@ -1439,7 +1444,7 @@ static int syscall_find_name(const char *name) {
return syslist[i].nr;
}

return -1;
return SYSCALL_ERROR;
}

static int syscall_find_name_32(const char *name) {
@@ -1450,7 +1455,7 @@ static int syscall_find_name_32(const char *name) {
return syslist32[i].nr;
}

return -1;
return SYSCALL_ERROR;
}

const char *syscall_find_nr(int nr) {
@@ -1538,9 +1543,13 @@ static void syscall_process_name(const char *name, int *syscall_nr, int *error_n
*syscall_nr = syscall_find_name_32(syscall_name);
}
if (error_name) {
*error_nr = errno_find_name(error_name);
if (*error_nr == -1)
*syscall_nr = -1;
if (strcmp(error_name, "kill") == 0)
*error_nr = ERRNO_KILL;
else {
*error_nr = errno_find_name(error_name);
if (*error_nr == -1)
*syscall_nr = SYSCALL_ERROR;
}
}

free(str);
@@ -1589,15 +1598,15 @@ int syscall_check_list(const char *slist, filter_fn *callback, int fd, int arg,
ptr++;
}
syscall_process_name(ptr, &syscall_nr, &error_nr, native);
if (syscall_nr == -1) {;}
else if (callback != NULL) {
if (syscall_nr != SYSCALL_ERROR && callback != NULL) {
if (negate) {
syscall_nr = -syscall_nr;
}
if (error_nr != -1 && fd > 0) {
if (error_nr >= 0 && fd > 0)
filter_add_errno(fd, syscall_nr, error_nr, ptrarg, native);
}
else if (error_nr != -1 && fd == 0) {
else if (error_nr == ERRNO_KILL && fd > 0)
filter_add_blacklist_override(fd, syscall_nr, 0, ptrarg, native);
else if (error_nr >= 0 && fd == 0) {
callback(fd, syscall_nr, error_nr, ptrarg, native);
}
else {
3 changes: 3 additions & 0 deletions src/man/firejail-profile.txt
Original file line number Diff line number Diff line change
@@ -411,6 +411,9 @@ Enable seccomp filter and whitelist the system calls in the list.
\fBseccomp.32.keep syscall,syscall,syscall
Enable seccomp filter and whitelist the system calls in the list for 32 bit system calls on a 64 bit architecture system.
.TP
\fBseccomp-error-action kill | ERRNO
Return a different error instead of EPERM to the process or kill it when an attempt is made to call a blocked system call.
.TP
\fBx11
Enable X11 sandboxing.
.TP
33 changes: 27 additions & 6 deletions src/man/firejail.txt
Original file line number Diff line number Diff line change
@@ -814,8 +814,9 @@ $ firejail \-\-machine-id
Install a seccomp filter to block attempts to create memory mappings
that are both writable and executable, to change mappings to be
executable, or to create executable shared memory. The filter examines
the arguments of mmap, mmap2, mprotect, pkey_mprotect, memfd_create and
shmat system calls and kills the process if necessary.
the arguments of mmap, mmap2, mprotect, pkey_mprotect, memfd_create
and shmat system calls and returns error EPERM to the process (or
kills it, see \-\-seccomp-error-action below) if necessary.
.br

.br
@@ -1865,8 +1866,12 @@ $ firejail \-\-seccomp=@clock,mkdir,unlinkat transmission-gtk
.br

.br
Instead of dropping the syscall, a specific error number can be returned
using \fBsyscall:errorno\fR syntax.
Instead of dropping the syscall by returning EPERM, another error
number can be returned using \fBsyscall:errno\fR syntax. This can be
also changed globally with \-\-seccomp-error-action or
in /etc/firejail/firejail.config file. The process can also be killed
by using \fBsyscall:kill\fR syntax.

.br

.br
@@ -1932,8 +1937,11 @@ $ firejail \-\-seccomp.drop=utime,utimensat,utimes,@clock
.br

.br
Instead of dropping the syscall, a specific error number can be returned
using \fBsyscall:errorno\fR syntax.
Instead of dropping the syscall by returning EPERM, another error
number can be returned using \fBsyscall:errno\fR syntax. This can be
also changed globally with \-\-seccomp-error-action or
in /etc/firejail/firejail.config file. The process can also be killed
by using \fBsyscall:kill\fR syntax.
.br

.br
@@ -2135,6 +2143,19 @@ $ firejail --seccomp.print=browser
0049: 06 00 01 00000000 ret KILL
.br
$

.TP
\fB\-\-seccomp-error-action= kill | ERRNO
By default, if a seccomp filter blocks a system call, the process gets
EPERM as the error. With \-\-seccomp-error-action=error, another error
number can be returned, for example ENOSYS or EACCES. The process can
also be killed (like in versions <0.9.63 of Firejail) by using
\-\-seccomp-error-action=kill syntax. Not killing the process weakens
Firejail slightly when trying to contain intrusion, but it may also
allow tighter filters if the only alternative is to allow a system
call.
.br

.TP
\fB\-\-shell=none
Run the program directly, without a user shell.