mirror of
https://github.com/netblue30/firejail.git
synced 2026-05-15 14:16:14 -06:00
Add seccomp errno filter support
This commit is contained in:
parent
5db7520b29
commit
081d1fbf2a
8 changed files with 393 additions and 38 deletions
214
src/firejail/errno.c
Normal file
214
src/firejail/errno.c
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_SECCOMP
|
||||
#include "firejail.h"
|
||||
#include <errno.h>
|
||||
#include <attr/xattr.h>
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int nr;
|
||||
} ErrnoEntry;
|
||||
|
||||
static ErrnoEntry errnolist[] = {
|
||||
//
|
||||
// code generated using tools/extract-errnos
|
||||
//
|
||||
"EPERM", EPERM,
|
||||
"ENOENT", ENOENT,
|
||||
"ESRCH", ESRCH,
|
||||
"EINTR", EINTR,
|
||||
"EIO", EIO,
|
||||
"ENXIO", ENXIO,
|
||||
"E2BIG", E2BIG,
|
||||
"ENOEXEC", ENOEXEC,
|
||||
"EBADF", EBADF,
|
||||
"ECHILD", ECHILD,
|
||||
"EAGAIN", EAGAIN,
|
||||
"ENOMEM", ENOMEM,
|
||||
"EACCES", EACCES,
|
||||
"EFAULT", EFAULT,
|
||||
"ENOTBLK", ENOTBLK,
|
||||
"EBUSY", EBUSY,
|
||||
"EEXIST", EEXIST,
|
||||
"EXDEV", EXDEV,
|
||||
"ENODEV", ENODEV,
|
||||
"ENOTDIR", ENOTDIR,
|
||||
"EISDIR", EISDIR,
|
||||
"EINVAL", EINVAL,
|
||||
"ENFILE", ENFILE,
|
||||
"EMFILE", EMFILE,
|
||||
"ENOTTY", ENOTTY,
|
||||
"ETXTBSY", ETXTBSY,
|
||||
"EFBIG", EFBIG,
|
||||
"ENOSPC", ENOSPC,
|
||||
"ESPIPE", ESPIPE,
|
||||
"EROFS", EROFS,
|
||||
"EMLINK", EMLINK,
|
||||
"EPIPE", EPIPE,
|
||||
"EDOM", EDOM,
|
||||
"ERANGE", ERANGE,
|
||||
"EDEADLK", EDEADLK,
|
||||
"ENAMETOOLONG", ENAMETOOLONG,
|
||||
"ENOLCK", ENOLCK,
|
||||
"ENOSYS", ENOSYS,
|
||||
"ENOTEMPTY", ENOTEMPTY,
|
||||
"ELOOP", ELOOP,
|
||||
"EWOULDBLOCK", EWOULDBLOCK,
|
||||
"ENOMSG", ENOMSG,
|
||||
"EIDRM", EIDRM,
|
||||
"ECHRNG", ECHRNG,
|
||||
"EL2NSYNC", EL2NSYNC,
|
||||
"EL3HLT", EL3HLT,
|
||||
"EL3RST", EL3RST,
|
||||
"ELNRNG", ELNRNG,
|
||||
"EUNATCH", EUNATCH,
|
||||
"ENOCSI", ENOCSI,
|
||||
"EL2HLT", EL2HLT,
|
||||
"EBADE", EBADE,
|
||||
"EBADR", EBADR,
|
||||
"EXFULL", EXFULL,
|
||||
"ENOANO", ENOANO,
|
||||
"EBADRQC", EBADRQC,
|
||||
"EBADSLT", EBADSLT,
|
||||
"EDEADLOCK", EDEADLOCK,
|
||||
"EBFONT", EBFONT,
|
||||
"ENOSTR", ENOSTR,
|
||||
"ENODATA", ENODATA,
|
||||
"ETIME", ETIME,
|
||||
"ENOSR", ENOSR,
|
||||
"ENONET", ENONET,
|
||||
"ENOPKG", ENOPKG,
|
||||
"EREMOTE", EREMOTE,
|
||||
"ENOLINK", ENOLINK,
|
||||
"EADV", EADV,
|
||||
"ESRMNT", ESRMNT,
|
||||
"ECOMM", ECOMM,
|
||||
"EPROTO", EPROTO,
|
||||
"EMULTIHOP", EMULTIHOP,
|
||||
"EDOTDOT", EDOTDOT,
|
||||
"EBADMSG", EBADMSG,
|
||||
"EOVERFLOW", EOVERFLOW,
|
||||
"ENOTUNIQ", ENOTUNIQ,
|
||||
"EBADFD", EBADFD,
|
||||
"EREMCHG", EREMCHG,
|
||||
"ELIBACC", ELIBACC,
|
||||
"ELIBBAD", ELIBBAD,
|
||||
"ELIBSCN", ELIBSCN,
|
||||
"ELIBMAX", ELIBMAX,
|
||||
"ELIBEXEC", ELIBEXEC,
|
||||
"EILSEQ", EILSEQ,
|
||||
"ERESTART", ERESTART,
|
||||
"ESTRPIPE", ESTRPIPE,
|
||||
"EUSERS", EUSERS,
|
||||
"ENOTSOCK", ENOTSOCK,
|
||||
"EDESTADDRREQ", EDESTADDRREQ,
|
||||
"EMSGSIZE", EMSGSIZE,
|
||||
"EPROTOTYPE", EPROTOTYPE,
|
||||
"ENOPROTOOPT", ENOPROTOOPT,
|
||||
"EPROTONOSUPPORT", EPROTONOSUPPORT,
|
||||
"ESOCKTNOSUPPORT", ESOCKTNOSUPPORT,
|
||||
"EOPNOTSUPP", EOPNOTSUPP,
|
||||
"EPFNOSUPPORT", EPFNOSUPPORT,
|
||||
"EAFNOSUPPORT", EAFNOSUPPORT,
|
||||
"EADDRINUSE", EADDRINUSE,
|
||||
"EADDRNOTAVAIL", EADDRNOTAVAIL,
|
||||
"ENETDOWN", ENETDOWN,
|
||||
"ENETUNREACH", ENETUNREACH,
|
||||
"ENETRESET", ENETRESET,
|
||||
"ECONNABORTED", ECONNABORTED,
|
||||
"ECONNRESET", ECONNRESET,
|
||||
"ENOBUFS", ENOBUFS,
|
||||
"EISCONN", EISCONN,
|
||||
"ENOTCONN", ENOTCONN,
|
||||
"ESHUTDOWN", ESHUTDOWN,
|
||||
"ETOOMANYREFS", ETOOMANYREFS,
|
||||
"ETIMEDOUT", ETIMEDOUT,
|
||||
"ECONNREFUSED", ECONNREFUSED,
|
||||
"EHOSTDOWN", EHOSTDOWN,
|
||||
"EHOSTUNREACH", EHOSTUNREACH,
|
||||
"EALREADY", EALREADY,
|
||||
"EINPROGRESS", EINPROGRESS,
|
||||
"ESTALE", ESTALE,
|
||||
"EUCLEAN", EUCLEAN,
|
||||
"ENOTNAM", ENOTNAM,
|
||||
"ENAVAIL", ENAVAIL,
|
||||
"EISNAM", EISNAM,
|
||||
"EREMOTEIO", EREMOTEIO,
|
||||
"EDQUOT", EDQUOT,
|
||||
"ENOMEDIUM", ENOMEDIUM,
|
||||
"EMEDIUMTYPE", EMEDIUMTYPE,
|
||||
"ECANCELED", ECANCELED,
|
||||
"ENOKEY", ENOKEY,
|
||||
"EKEYEXPIRED", EKEYEXPIRED,
|
||||
"EKEYREVOKED", EKEYREVOKED,
|
||||
"EKEYREJECTED", EKEYREJECTED,
|
||||
"EOWNERDEAD", EOWNERDEAD,
|
||||
"ENOTRECOVERABLE", ENOTRECOVERABLE,
|
||||
"ERFKILL", ERFKILL,
|
||||
"EHWPOISON", EHWPOISON,
|
||||
"ENOTSUP", ENOTSUP,
|
||||
"ENOATTR", ENOATTR,
|
||||
};
|
||||
|
||||
int errno_highest_nr(void) {
|
||||
int i, max = 0;
|
||||
int elems = sizeof(errnolist) / sizeof(errnolist[0]);
|
||||
for (i = 0; i < elems; i++) {
|
||||
if (errnolist[i].nr > max)
|
||||
max = errnolist[i].nr;
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
int errno_find_name(const char *name) {
|
||||
int i;
|
||||
int elems = sizeof(errnolist) / sizeof(errnolist[0]);
|
||||
for (i = 0; i < elems; i++) {
|
||||
if (strcasecmp(name, errnolist[i].name) == 0)
|
||||
return errnolist[i].nr;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *errno_find_nr(int nr) {
|
||||
int i;
|
||||
int elems = sizeof(errnolist) / sizeof(errnolist[0]);
|
||||
for (i = 0; i < elems; i++) {
|
||||
if (nr == errnolist[i].nr)
|
||||
return errnolist[i].name;
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
void errno_print(void) {
|
||||
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
|
||||
|
|
@ -147,6 +147,7 @@ extern int arg_seccomp; // enable default seccomp filter
|
|||
extern char *arg_seccomp_list;// optional seccomp list on top of default filter
|
||||
extern char *arg_seccomp_list_drop; // seccomp drop list
|
||||
extern char *arg_seccomp_list_keep; // seccomp keep list
|
||||
extern char **arg_seccomp_list_errno; // seccomp errno[nr] lists
|
||||
|
||||
extern int arg_caps_default_filter; // enable default capabilities filter
|
||||
extern int arg_caps_drop; // drop list
|
||||
|
|
@ -335,7 +336,7 @@ void caps_print_filter_name(const char *name);
|
|||
// syscall.c
|
||||
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));
|
||||
int syscall_check_list(const char *slist, void (*callback)(int syscall, int arg), int arg);
|
||||
// print all available syscalls
|
||||
void syscall_print(void);
|
||||
|
||||
|
|
@ -392,5 +393,11 @@ void env_apply(void);
|
|||
// fs_whitelist.c
|
||||
void fs_whitelist(void);
|
||||
|
||||
// errno.c
|
||||
int errno_highest_errno(void);
|
||||
int errno_find_name(const char *name);
|
||||
char *errno_find_nr(int nr);
|
||||
void errno_print(void);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ int arg_seccomp = 0; // enable default seccomp filter
|
|||
char *arg_seccomp_list = NULL; // optional seccomp list on top of default filter
|
||||
char *arg_seccomp_list_drop = NULL; // seccomp drop list
|
||||
char *arg_seccomp_list_keep = NULL; // seccomp keep list
|
||||
char **arg_seccomp_list_errno = NULL; // seccomp errno[nr] lists
|
||||
|
||||
int arg_caps_default_filter = 0; // enable default capabilities filter
|
||||
int arg_caps_drop = 0; // drop list
|
||||
|
|
@ -302,6 +303,10 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
|
|||
syscall_print();
|
||||
exit(0);
|
||||
}
|
||||
else if (strcmp(argv[i], "--debug-errnos") == 0) {
|
||||
errno_print();
|
||||
exit(0);
|
||||
}
|
||||
else if (strncmp(argv[i], "--seccomp.print=", 16) == 0) {
|
||||
// join sandbox by pid or by name
|
||||
pid_t pid;
|
||||
|
|
@ -387,6 +392,7 @@ int main(int argc, char **argv) {
|
|||
int arg_cgroup = 0;
|
||||
int custom_profile = 0; // custom profile loaded
|
||||
int arg_noprofile = 0; // use generic.profile if none other found/specified
|
||||
int highest_errno = errno_highest_nr();
|
||||
|
||||
// check if we already have a sandbox running
|
||||
int rv = check_kernel_procs();
|
||||
|
|
@ -478,6 +484,34 @@ int main(int argc, char **argv) {
|
|||
if (!arg_seccomp_list_keep)
|
||||
errExit("strdup");
|
||||
}
|
||||
else if (strncmp(argv[i], "--seccomp.e", 11) == 0 && strchr(argv[i], '=')) {
|
||||
if (arg_seccomp && !arg_seccomp_list_errno) {
|
||||
fprintf(stderr, "Error: seccomp already enabled\n");
|
||||
exit(1);
|
||||
}
|
||||
char *eq = strchr(argv[i], '=');
|
||||
char *errnoname = strndup(argv[i] + 10, eq - (argv[i] + 10));
|
||||
int nr = errno_find_name(errnoname);
|
||||
if (nr == -1) {
|
||||
fprintf(stderr, "Error: unknown errno %s\n", errnoname);
|
||||
free(errnoname);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!arg_seccomp_list_errno)
|
||||
arg_seccomp_list_errno = calloc(highest_errno+1, sizeof(arg_seccomp_list_errno[0]));
|
||||
|
||||
if (arg_seccomp_list_errno[nr]) {
|
||||
fprintf(stderr, "Error: errno %s already configured\n", errnoname);
|
||||
free(errnoname);
|
||||
exit(1);
|
||||
}
|
||||
arg_seccomp = 1;
|
||||
arg_seccomp_list_errno[nr] = strdup(eq+1);
|
||||
if (!arg_seccomp_list_errno[nr])
|
||||
errExit("strdup");
|
||||
free(errnoname);
|
||||
}
|
||||
#endif
|
||||
else if (strcmp(argv[i], "--caps") == 0)
|
||||
arg_caps_default_filter = 1;
|
||||
|
|
@ -1288,6 +1322,15 @@ int main(int argc, char **argv) {
|
|||
|
||||
// wait for the child to finish
|
||||
waitpid(child, NULL, 0);
|
||||
|
||||
// free globals
|
||||
if (arg_seccomp_list_errno) {
|
||||
for (i = 0; i < highest_errno; i++)
|
||||
free(arg_seccomp_list_errno[i]);
|
||||
free(arg_seccomp_list_errno);
|
||||
}
|
||||
|
||||
myexit(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -410,6 +410,8 @@ int sandbox(void* sandbox_arg) {
|
|||
if (arg_seccomp == 1) {
|
||||
if (arg_seccomp_list_keep)
|
||||
seccomp_filter_keep(); // this will also save the fmyilter to MNT_DIR/seccomp file
|
||||
else if (arg_seccomp_list_errno)
|
||||
seccomp_filter_errno(); // this will also save the filter to MNT_DIR/seccomp file
|
||||
else
|
||||
seccomp_filter_drop(); // this will also save the filter to MNT_DIR/seccomp file
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,10 @@ struct seccomp_data {
|
|||
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), \
|
||||
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
|
||||
|
||||
#define ERRNO(syscall_nr, nr) \
|
||||
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, syscall_nr, 0, 1), \
|
||||
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO | nr)
|
||||
|
||||
#define RETURN_ALLOW \
|
||||
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
|
||||
|
||||
|
|
@ -157,6 +161,11 @@ void filter_debug(void) {
|
|||
printf(" BLACKLIST %d %s\n", *nr, syscall_find_nr(*nr));
|
||||
i += 2;
|
||||
}
|
||||
else if (*ptr == 0x15 && *(ptr +14) == 0x5 && *(ptr + 15) == 0) {
|
||||
int err = *(ptr + 13) << 8 | *(ptr + 12);
|
||||
printf(" ERRNO %d %s %d %s\n", *nr, syscall_find_nr(*nr), err, errno_find_nr(err));
|
||||
i += 2;
|
||||
}
|
||||
else if (*ptr == 0x06 && *(ptr +6) == 0 && *(ptr + 7) == 0 ) {
|
||||
printf(" KILL_PROCESS\n");
|
||||
i++;
|
||||
|
|
@ -216,7 +225,7 @@ static void filter_realloc(void) {
|
|||
sfilter_alloc_size += SECSIZE;
|
||||
}
|
||||
|
||||
static void filter_add_whitelist(int syscall) {
|
||||
static void filter_add_whitelist(int syscall, int arg) {
|
||||
assert(sfilter);
|
||||
assert(sfilter_alloc_size);
|
||||
assert(sfilter_index);
|
||||
|
|
@ -242,7 +251,7 @@ static void filter_add_whitelist(int syscall) {
|
|||
sfilter_index += sizeof(filter) / sizeof(struct sock_filter);
|
||||
}
|
||||
|
||||
static void filter_add_blacklist(int syscall) {
|
||||
static void filter_add_blacklist(int syscall, int arg) {
|
||||
assert(sfilter);
|
||||
assert(sfilter_alloc_size);
|
||||
assert(sfilter_index);
|
||||
|
|
@ -268,6 +277,32 @@ static void filter_add_blacklist(int syscall) {
|
|||
sfilter_index += sizeof(filter) / sizeof(struct sock_filter);
|
||||
}
|
||||
|
||||
static void filter_add_errno(int syscall, int arg) {
|
||||
assert(sfilter);
|
||||
assert(sfilter_alloc_size);
|
||||
assert(sfilter_index);
|
||||
// if (arg_debug)
|
||||
// printf("Errno syscall %d %d %s\n", syscall, arg, syscall_find_nr(syscall));
|
||||
|
||||
if ((sfilter_index + 2) > sfilter_alloc_size)
|
||||
filter_realloc();
|
||||
|
||||
struct sock_filter filter[] = {
|
||||
ERRNO(syscall, arg)
|
||||
};
|
||||
#if 0
|
||||
{
|
||||
int i;
|
||||
unsigned char *ptr = (unsigned char *) &filter[0];
|
||||
for (i = 0; i < sizeof(filter); i++, ptr++)
|
||||
printf("%x, ", (*ptr) & 0xff);
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
memcpy(&sfilter[sfilter_index], filter, sizeof(filter));
|
||||
sfilter_index += sizeof(filter) / sizeof(struct sock_filter);
|
||||
}
|
||||
|
||||
static void filter_end_blacklist(void) {
|
||||
assert(sfilter);
|
||||
assert(sfilter_alloc_size);
|
||||
|
|
@ -405,96 +440,96 @@ int seccomp_filter_drop(void) {
|
|||
// default seccomp
|
||||
if (arg_seccomp_list_drop == NULL) {
|
||||
#ifdef SYS_mount
|
||||
filter_add_blacklist(SYS_mount);
|
||||
filter_add_blacklist(SYS_mount, 0);
|
||||
#endif
|
||||
#ifdef SYS_umount2
|
||||
filter_add_blacklist(SYS_umount2);
|
||||
filter_add_blacklist(SYS_umount2, 0);
|
||||
#endif
|
||||
#ifdef SYS_ptrace
|
||||
filter_add_blacklist(SYS_ptrace);
|
||||
filter_add_blacklist(SYS_ptrace, 0);
|
||||
#endif
|
||||
#ifdef SYS_kexec_load
|
||||
filter_add_blacklist(SYS_kexec_load);
|
||||
filter_add_blacklist(SYS_kexec_load, 0);
|
||||
#endif
|
||||
#ifdef SYS_open_by_handle_at
|
||||
filter_add_blacklist(SYS_open_by_handle_at);
|
||||
filter_add_blacklist(SYS_open_by_handle_at, 0);
|
||||
#endif
|
||||
#ifdef SYS_init_module
|
||||
filter_add_blacklist(SYS_init_module);
|
||||
filter_add_blacklist(SYS_init_module, 0);
|
||||
#endif
|
||||
#ifdef SYS_finit_module // introduced in 2013
|
||||
filter_add_blacklist(SYS_finit_module);
|
||||
filter_add_blacklist(SYS_finit_module, 0);
|
||||
#endif
|
||||
#ifdef SYS_delete_module
|
||||
filter_add_blacklist(SYS_delete_module);
|
||||
filter_add_blacklist(SYS_delete_module, 0);
|
||||
#endif
|
||||
#ifdef SYS_iopl
|
||||
filter_add_blacklist(SYS_iopl);
|
||||
filter_add_blacklist(SYS_iopl, 0);
|
||||
#endif
|
||||
#ifdef SYS_ioperm
|
||||
filter_add_blacklist(SYS_ioperm);
|
||||
filter_add_blacklist(SYS_ioperm, 0);
|
||||
#endif
|
||||
#ifdef SYS_ni_syscall // new io permisions call on arm devices
|
||||
filter_add_blacklist(SYS_ni_syscall);
|
||||
filter_add_blacklist(SYS_ni_syscall, 0);
|
||||
#endif
|
||||
#ifdef SYS_swapon
|
||||
filter_add_blacklist(SYS_swapon);
|
||||
filter_add_blacklist(SYS_swapon, 0);
|
||||
#endif
|
||||
#ifdef SYS_swapoff
|
||||
filter_add_blacklist(SYS_swapoff);
|
||||
filter_add_blacklist(SYS_swapoff, 0);
|
||||
#endif
|
||||
#ifdef SYS_syslog
|
||||
filter_add_blacklist(SYS_syslog);
|
||||
filter_add_blacklist(SYS_syslog, 0);
|
||||
#endif
|
||||
#ifdef SYS_process_vm_readv
|
||||
filter_add_blacklist(SYS_process_vm_readv);
|
||||
filter_add_blacklist(SYS_process_vm_readv, 0);
|
||||
#endif
|
||||
#ifdef SYS_process_vm_writev
|
||||
filter_add_blacklist(SYS_process_vm_writev);
|
||||
filter_add_blacklist(SYS_process_vm_writev, 0);
|
||||
#endif
|
||||
|
||||
// mknod removed in 0.9.29
|
||||
//#ifdef SYS_mknod
|
||||
// filter_add_blacklist(SYS_mknod);
|
||||
// filter_add_blacklist(SYS_mknod, 0);
|
||||
//#endif
|
||||
|
||||
// new syscalls in 0.9,23
|
||||
#ifdef SYS_sysfs
|
||||
filter_add_blacklist(SYS_sysfs);
|
||||
filter_add_blacklist(SYS_sysfs, 0);
|
||||
#endif
|
||||
#ifdef SYS__sysctl
|
||||
filter_add_blacklist(SYS__sysctl);
|
||||
filter_add_blacklist(SYS__sysctl, 0);
|
||||
#endif
|
||||
#ifdef SYS_adjtimex
|
||||
filter_add_blacklist(SYS_adjtimex);
|
||||
filter_add_blacklist(SYS_adjtimex, 0);
|
||||
#endif
|
||||
#ifdef SYS_clock_adjtime
|
||||
filter_add_blacklist(SYS_clock_adjtime);
|
||||
filter_add_blacklist(SYS_clock_adjtime, 0);
|
||||
#endif
|
||||
#ifdef SYS_lookup_dcookie
|
||||
filter_add_blacklist(SYS_lookup_dcookie);
|
||||
filter_add_blacklist(SYS_lookup_dcookie, 0);
|
||||
#endif
|
||||
#ifdef SYS_perf_event_open
|
||||
filter_add_blacklist(SYS_perf_event_open);
|
||||
filter_add_blacklist(SYS_perf_event_open, 0);
|
||||
#endif
|
||||
#ifdef SYS_fanotify_init
|
||||
filter_add_blacklist(SYS_fanotify_init);
|
||||
filter_add_blacklist(SYS_fanotify_init, 0);
|
||||
#endif
|
||||
#ifdef SYS_kcmp
|
||||
filter_add_blacklist(SYS_kcmp);
|
||||
filter_add_blacklist(SYS_kcmp, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
// default seccomp filter with additional drop list
|
||||
if (arg_seccomp_list && arg_seccomp_list_drop == NULL) {
|
||||
if (syscall_check_list(arg_seccomp_list, filter_add_blacklist)) {
|
||||
if (syscall_check_list(arg_seccomp_list, filter_add_blacklist, 0)) {
|
||||
fprintf(stderr, "Error: cannot load seccomp filter\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
// drop list
|
||||
else if (arg_seccomp_list == NULL && arg_seccomp_list_drop) {
|
||||
if (syscall_check_list(arg_seccomp_list_drop, filter_add_blacklist)) {
|
||||
if (syscall_check_list(arg_seccomp_list_drop, filter_add_blacklist, 0)) {
|
||||
fprintf(stderr, "Error: cannot load seccomp filter\n");
|
||||
exit(1);
|
||||
}
|
||||
|
|
@ -531,14 +566,14 @@ int seccomp_filter_keep(void) {
|
|||
filter_init();
|
||||
|
||||
// these 4 syscalls are used by firejail after the seccomp filter is initialized
|
||||
filter_add_whitelist(SYS_setuid);
|
||||
filter_add_whitelist(SYS_setgid);
|
||||
filter_add_whitelist(SYS_setgroups);
|
||||
filter_add_whitelist(SYS_dup);
|
||||
filter_add_whitelist(SYS_setuid, 0);
|
||||
filter_add_whitelist(SYS_setgid, 0);
|
||||
filter_add_whitelist(SYS_setgroups, 0);
|
||||
filter_add_whitelist(SYS_dup, 0);
|
||||
|
||||
// apply keep list
|
||||
if (arg_seccomp_list_keep) {
|
||||
if (syscall_check_list(arg_seccomp_list_keep, filter_add_whitelist)) {
|
||||
if (syscall_check_list(arg_seccomp_list_keep, filter_add_whitelist, 0)) {
|
||||
fprintf(stderr, "Error: cannot load seccomp filter\n");
|
||||
exit(1);
|
||||
}
|
||||
|
|
@ -569,6 +604,47 @@ int seccomp_filter_keep(void) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// errno filter for seccomp option
|
||||
int seccomp_filter_errno(void) {
|
||||
int i;
|
||||
int higest_errno = errno_highest_nr();
|
||||
filter_init();
|
||||
|
||||
// apply errno list
|
||||
|
||||
for (i = 0; i < higest_errno; i++) {
|
||||
if (arg_seccomp_list_errno[i]) {
|
||||
if (syscall_check_list(arg_seccomp_list_errno[i], filter_add_errno, i)) {
|
||||
fprintf(stderr, "Error: cannot load seccomp filter\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filter_end_blacklist();
|
||||
if (arg_debug)
|
||||
filter_debug();
|
||||
|
||||
// save seccomp filter in /tmp/firejail/mnt/seccomp
|
||||
// in order to use it in --join operations
|
||||
write_seccomp_file();
|
||||
|
||||
struct sock_fprog prog = {
|
||||
.len = sfilter_index,
|
||||
.filter = sfilter,
|
||||
};
|
||||
|
||||
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
|
||||
fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n");
|
||||
return 1;
|
||||
}
|
||||
else if (arg_debug) {
|
||||
printf("seccomp enabled\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void seccomp_set(void) {
|
||||
|
|
|
|||
|
|
@ -4889,7 +4889,7 @@ static int syscall_find_name(const char *name) {
|
|||
}
|
||||
|
||||
// return 1 if error, 0 if OK
|
||||
int syscall_check_list(const char *slist, void (*callback)(int)) {
|
||||
int syscall_check_list(const char *slist, void (*callback)(int syscall, int arg), int arg) {
|
||||
// don't allow empty lists
|
||||
if (slist == NULL || *slist == '\0') {
|
||||
fprintf(stderr, "Error: empty syscall lists are not allowed\n");
|
||||
|
|
@ -4912,7 +4912,7 @@ int syscall_check_list(const char *slist, void (*callback)(int)) {
|
|||
if (nr == -1)
|
||||
fprintf(stderr, "Warning: syscall %s not found\n", start);
|
||||
else if (callback != NULL)
|
||||
callback(nr);
|
||||
callback(nr, arg);
|
||||
|
||||
start = ptr + 1;
|
||||
}
|
||||
|
|
@ -4923,7 +4923,7 @@ int syscall_check_list(const char *slist, void (*callback)(int)) {
|
|||
if (nr == -1)
|
||||
fprintf(stderr, "Warning: syscall %s not found\n", start);
|
||||
else if (callback != NULL)
|
||||
callback(nr);
|
||||
callback(nr, arg);
|
||||
}
|
||||
|
||||
free(str);
|
||||
|
|
|
|||
|
|
@ -845,6 +845,15 @@ Example:
|
|||
.br
|
||||
$ firejail \-\-shell=none \-\-seccomp.keep=poll,select,[...] transmission-gtk
|
||||
.TP
|
||||
\fB\-\-seccomp.<errno>=syscall,syscall,syscall
|
||||
Enable seccomp filter, and return errno for the syscalls specified by the command.
|
||||
.br
|
||||
|
||||
.br
|
||||
Example:
|
||||
.br
|
||||
$ firejail \-\-shell=none \-\-seccomp.einval=kill kill 1
|
||||
.TP
|
||||
\fB\-\-seccomp.print=name
|
||||
Print the seccomp filter for the sandbox started using \-\-name option.
|
||||
.br
|
||||
|
|
|
|||
4
src/tools/extract_errnos.sh
Normal file
4
src/tools/extract_errnos.sh
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
echo -e "#include <errno.h>\n#include <attr/xattr.h>" | \
|
||||
cpp -dD | \
|
||||
grep "^#define E" | \
|
||||
sed -e '{s/#define \(.*\) .*/\t"\1", \1,/g}'
|
||||
Loading…
Add table
Add a link
Reference in a new issue