mirror of
https://github.com/irssi/irssi.git
synced 2026-08-23 10:32:31 +02:00
Merge de0a6e5452 into dc03baa0d3
This commit is contained in:
commit
2cc3e05351
9 changed files with 933 additions and 0 deletions
|
|
@ -1,4 +1,5 @@
|
|||
/* misc.. */
|
||||
#undef HAVE_SECCOMP
|
||||
#undef HAVE_IPV6
|
||||
#undef HAVE_SOCKS_H
|
||||
#undef HAVE_STATIC_PERL
|
||||
|
|
|
|||
34
configure.ac
34
configure.ac
|
|
@ -140,6 +140,15 @@ AC_ARG_WITH(perl,
|
|||
fi,
|
||||
want_perl=static)
|
||||
|
||||
AC_ARG_ENABLE(seccomp,
|
||||
[ --disable-seccomp, Disable seccomp support],
|
||||
if test x$enableval = xno; then
|
||||
want_seccomp=yes
|
||||
else
|
||||
want_seccomp=no
|
||||
fi,
|
||||
want_seccomp=yes)
|
||||
|
||||
AC_ARG_ENABLE(ipv6,
|
||||
[ --disable-ipv6 Disable IPv6 support],
|
||||
if test x$enableval = xno; then
|
||||
|
|
@ -577,6 +586,30 @@ COMMON_LIBS="$FE_COMMON_LIBS $COMMON_NOUI_LIBS"
|
|||
AC_SUBST(COMMON_NOUI_LIBS)
|
||||
AC_SUBST(COMMON_LIBS)
|
||||
|
||||
dnl **
|
||||
dnl ** Seccomp support
|
||||
dnl **
|
||||
|
||||
have_seccomp=no
|
||||
if test "x$want_seccomp" = "xyes"; then
|
||||
have_caps=no
|
||||
AC_CHECK_LIB(cap, cap_init,
|
||||
[
|
||||
have_caps=yes
|
||||
], [], [])
|
||||
|
||||
AC_CHECK_LIB(seccomp, seccomp_init,
|
||||
[
|
||||
have_seccomp=yes
|
||||
AC_DEFINE(HAVE_SECCOMP)
|
||||
LIBS="$LIBS -lseccomp -lcap"
|
||||
], [], [-lcap])
|
||||
|
||||
if test x$have_cap = xno; then
|
||||
AC_ERROR([Capability support is required to build Irssi with Seccomp support enabled.])
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl **
|
||||
dnl ** IPv6 support
|
||||
dnl **
|
||||
|
|
@ -742,6 +775,7 @@ echo "Install prefix ................... : $prefix"
|
|||
|
||||
echo
|
||||
|
||||
echo "Building with seccomp support .... : $have_seccomp"
|
||||
echo "Building with IPv6 support ....... : $have_ipv6"
|
||||
echo "Building with SSL support ........ : $have_openssl"
|
||||
if test "x$have_openssl" = "xno" -a "x$enable_ssl" = "xyes"; then
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ libcore_a_SOURCES = \
|
|||
queries.c \
|
||||
rawlog.c \
|
||||
recode.c \
|
||||
sandbox.c \
|
||||
servers.c \
|
||||
servers-reconnect.c \
|
||||
servers-setup.c \
|
||||
|
|
@ -86,6 +87,7 @@ pkginc_core_HEADERS = \
|
|||
queries.h \
|
||||
rawlog.h \
|
||||
recode.h \
|
||||
sandbox.h \
|
||||
servers.h \
|
||||
servers-reconnect.h \
|
||||
servers-setup.h \
|
||||
|
|
|
|||
|
|
@ -170,4 +170,6 @@ void commands_remove_module(const char *module);
|
|||
void commands_init(void);
|
||||
void commands_deinit(void);
|
||||
|
||||
extern int sandbox;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
859
src/core/sandbox.c
Normal file
859
src/core/sandbox.c
Normal file
|
|
@ -0,0 +1,859 @@
|
|||
/*
|
||||
sandbox.c : irssi
|
||||
|
||||
Copyright (C) 2015 Namsun Ch'o
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <linux/futex.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/prctl.h>
|
||||
#include <linux/sched.h>
|
||||
#include <seccomp.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/capability.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/termios.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sandbox.h"
|
||||
|
||||
#define IRSSI_NEEDS_RDTSC
|
||||
#undef IRSSI_NEEDS_CAPS
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* - implement user, pid, network, and mount namespaces
|
||||
* - ensure that hardcoded file descriptors work
|
||||
* - create automated test suite for seccomp (and/or static analysis?)
|
||||
* - keep private keys in a separate process, (e.g https://github.com/AGWA/titus)?
|
||||
* - add support tame() on OpenBSD, and Capsicum on FreeBSD
|
||||
*/
|
||||
|
||||
struct _cap_struct {
|
||||
struct __user_cap_header_struct head;
|
||||
union {
|
||||
struct __user_cap_data_struct set;
|
||||
uint32_t flag[3];
|
||||
} u[2];
|
||||
};
|
||||
|
||||
void create_namespaces(void)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
void drop_privileges(void)
|
||||
{
|
||||
int tsc_state;
|
||||
size_t i;
|
||||
uint32_t *raw_data;
|
||||
cap_t cap;
|
||||
cap_flag_value_t value;
|
||||
|
||||
/* running as root largely defeats the purpose of using a sandbox */
|
||||
if (geteuid() == 0 || getegid() == 0) {
|
||||
fprintf(stderr, "Cannot run irssi as root when the sandbox is enabled\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* disable the rdtsc so it cannot be used for side-channel attacks */
|
||||
#ifndef IRSSI_NEEDS_RDTSC
|
||||
if (prctl(PR_GET_TSC, &tsc_state, 0, 0, 0) < 0) {
|
||||
fprintf(stderr, "Could not get the TSC state\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (tsc_state == PR_TSC_ENABLE) {
|
||||
prctl(PR_SET_TSC, PR_TSC_SIGSEGV, 0, 0, 0);
|
||||
prctl(PR_GET_TSC, &tsc_state, 0, 0, 0);
|
||||
|
||||
if (tsc_state != PR_TSC_SIGSEGV) {
|
||||
fprintf(stderr, "Could not disable the TSC\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* drop any dangerous capabilities the process is running with
|
||||
* https://forums.grsecurity.net/viewtopic.php?f=7&t=2522 */
|
||||
#ifndef IRSSI_NEEDS_CAPS
|
||||
cap = cap_get_proc();
|
||||
if (cap == NULL) {
|
||||
raw_data = malloc(sizeof(uint32_t) + sizeof(*cap));
|
||||
*raw_data = 0xCA90D0; /* CAP_T_MAGIC */
|
||||
cap = (cap_t)(raw_data + 1);
|
||||
memset(cap, 0, sizeof(*cap));
|
||||
cap->header.version = 0x20080522; /* capability version 3 */
|
||||
|
||||
if (capget(&cap->head, &cap->u[0].set) < 0) {
|
||||
cap_free(cap);
|
||||
fprintf(stderr, "Could not initialize capabilities (capget failed)\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (cap_clear(cap) < 0) {
|
||||
fprintf(stderr, "Could not clear capabilities (cap_clear failed)\n");
|
||||
cap_free(cap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
cap_get_flag(cap, i, CAP_EFFECTIVE, &value);
|
||||
if (value == CAP_SET) {
|
||||
fprintf(stderr, "Cannot run irssi with caps set (cap %u)\n", (unsigned)i);
|
||||
cap_free(cap);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
cap_free(cap);
|
||||
#endif
|
||||
}
|
||||
|
||||
void enforce_resource_limits(void)
|
||||
{
|
||||
size_t i;
|
||||
struct rlimit rlim;
|
||||
|
||||
struct rlimit_struct_t {
|
||||
int resource;
|
||||
int limit;
|
||||
};
|
||||
const struct rlimit_struct_t rlimit_struct[9] = {
|
||||
{ RLIMIT_AS, 268435456 }, /* 256 MiB */
|
||||
{ RLIMIT_FSIZE, 1073741824 }, /* 1 GiB */
|
||||
{ RLIMIT_LOCKS, 0 },
|
||||
{ RLIMIT_MEMLOCK, 0 },
|
||||
{ RLIMIT_MSGQUEUE, 0 },
|
||||
{ RLIMIT_NOFILE, 4096 },
|
||||
{ RLIMIT_NPROC, 70 }, /* why is this so large? */
|
||||
{ RLIMIT_SIGPENDING, 0 },
|
||||
{ RLIMIT_STACK, 32768 } /* 32 KiB */
|
||||
};
|
||||
for (i = 0; i < 9; i++) {
|
||||
rlim.rlim_cur = rlimit_struct[i].limit;
|
||||
rlim.rlim_max = rlimit_struct[i].limit;
|
||||
|
||||
if (setrlimit(rlimit_struct[i].resource, &rlim) < 0 && errno != EPERM) {
|
||||
fprintf(stderr, "Could not set resource limits. Errno %d\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void enable_seccomp_sandbox(void)
|
||||
{
|
||||
scmp_filter_ctx ctx;
|
||||
size_t i;
|
||||
int rc;
|
||||
|
||||
/* initialize the libseccomp context */
|
||||
ctx = seccomp_init(SCMP_ACT_KILL);
|
||||
if (ctx == NULL) {
|
||||
fprintf(stderr, "Could not initialize the sandbox (seccomp_init failed)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* syscalls without argument filtering */
|
||||
const int noarg_whitelist[19] = {
|
||||
SCMP_SYS(brk),
|
||||
SCMP_SYS(chdir),
|
||||
SCMP_SYS(close),
|
||||
SCMP_SYS(exit_group),
|
||||
SCMP_SYS(fstat),
|
||||
SCMP_SYS(getegid),
|
||||
SCMP_SYS(geteuid),
|
||||
SCMP_SYS(getgid),
|
||||
SCMP_SYS(getpid),
|
||||
SCMP_SYS(getuid),
|
||||
SCMP_SYS(lseek),
|
||||
SCMP_SYS(munmap),
|
||||
SCMP_SYS(pipe),
|
||||
SCMP_SYS(rt_sigreturn),
|
||||
SCMP_SYS(set_tid_address),
|
||||
SCMP_SYS(stat),
|
||||
SCMP_SYS(umask),
|
||||
SCMP_SYS(uname)
|
||||
};
|
||||
for (i = 0; i < 19; i++) {
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, noarg_whitelist[i], 0);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, noarg_whitelist[i], 100);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef __i386__
|
||||
/* if we are on a 32 bit architecture, we need to use socketcall */
|
||||
const int socketcall_calls[7] = {
|
||||
SYS_SOCKET,
|
||||
SYS_CONNECT,
|
||||
SYS_GETPEERNAME,
|
||||
SYS_GETSOCKOPT,
|
||||
SYS_SETSOCKOPT,
|
||||
SYS_SENDTO,
|
||||
SYS_RECVFROM
|
||||
};
|
||||
for (i = 0; i < 7; i++) {
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socketcall), 1,
|
||||
SCMP_A0(SCMP_CMP_EQ, socketcall_calls[i]));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(socketcall), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
/* clone */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(clone), 3,
|
||||
SCMP_A0(SCMP_CMP_EQ, CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD),
|
||||
SCMP_A1(SCMP_CMP_EQ, 0),
|
||||
SCMP_A2(SCMP_CMP_EQ, 0));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(clone), 1,
|
||||
SCMP_A0(SCMP_CMP_EQ, CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|
|
||||
CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|
|
||||
CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(clone), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* mkdir */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mkdir), 1,
|
||||
SCMP_A1(SCMP_CMP_EQ, 0700)); /* src/core/settings.c:828 */
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(mkdir), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
#ifndef __i386__
|
||||
/* setsockopt */
|
||||
struct setsockopt_struct_t {
|
||||
int minsockfd;
|
||||
int level;
|
||||
int optname;
|
||||
socklen_t optlen;
|
||||
};
|
||||
const struct setsockopt_struct_t setsockopt_struct[2] = {
|
||||
{ 4, SOL_SOCKET, SO_KEEPALIVE, 4 },
|
||||
{ 4, SOL_SOCKET, SO_REUSEADDR, 4 }
|
||||
};
|
||||
for (i = 0; i < 2; i++) {
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setsockopt), 4,
|
||||
SCMP_A0(SCMP_CMP_GE, setsockopt_struct[i].minsockfd),
|
||||
SCMP_A1(SCMP_CMP_EQ, setsockopt_struct[i].level),
|
||||
SCMP_A2(SCMP_CMP_EQ, setsockopt_struct[i].optname),
|
||||
SCMP_A4(SCMP_CMP_EQ, setsockopt_struct[i].optlen));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(setsockopt), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* getsockopt */
|
||||
struct getsockopt_struct_t {
|
||||
int minsockfd;
|
||||
int level;
|
||||
int optname;
|
||||
};
|
||||
const struct getsockopt_struct_t getsockopt_struct[2] = {
|
||||
{ 4, SOL_SOCKET, SO_TYPE },
|
||||
{ 4, SOL_SOCKET, SO_ERROR }
|
||||
};
|
||||
for (i = 0; i < 2; i++) {
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getsockopt), 3,
|
||||
SCMP_A0(SCMP_CMP_GE, getsockopt_struct[i].minsockfd),
|
||||
SCMP_A1(SCMP_CMP_EQ, getsockopt_struct[i].level),
|
||||
SCMP_A2(SCMP_CMP_EQ, getsockopt_struct[i].optname));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(getsockopt), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
/* ioctl */
|
||||
const int ioctl_array[3] = {
|
||||
TCSETSW,
|
||||
TCGETS,
|
||||
TIOCGWINSZ
|
||||
};
|
||||
for (i = 0; i < 3; i++) {
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
|
||||
SCMP_A1(SCMP_CMP_EQ, ioctl_array[i]));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(ioctl), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* kill */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(kill), 1,
|
||||
SCMP_A1(SCMP_CMP_EQ, SIGTSTP));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(kill), 1,
|
||||
SCMP_A1(SCMP_CMP_EQ, SIGKILL));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(kill), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* prctl */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl), 4,
|
||||
SCMP_A0(SCMP_CMP_EQ, PR_SET_NAME),
|
||||
SCMP_A2(SCMP_CMP_EQ, 0),
|
||||
SCMP_A3(SCMP_CMP_EQ, 0),
|
||||
SCMP_A4(SCMP_CMP_EQ, 0));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(prctl), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* fcntl */
|
||||
const int fcntl_1arg_array[3] = {
|
||||
F_GETFL,
|
||||
F_GETFD,
|
||||
F_SETLK
|
||||
};
|
||||
for (i = 0; i < 3; i++) {
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 1,
|
||||
SCMP_A1(SCMP_CMP_EQ, fcntl_1arg_array[i]));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
struct fcntl_2args_struct_t {
|
||||
int cmd;
|
||||
int arg;
|
||||
};
|
||||
const struct fcntl_2args_struct_t fcntl_2args_struct[3] = {
|
||||
{ F_SETFD, FD_CLOEXEC },
|
||||
{ F_SETFL, O_RDONLY },
|
||||
{ F_SETFL, O_RDONLY|O_NONBLOCK }
|
||||
};
|
||||
for (i = 0; i < 3; i++) {
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fcntl), 2,
|
||||
SCMP_A1(SCMP_CMP_EQ, fcntl_2args_struct[i].cmd),
|
||||
SCMP_A2(SCMP_CMP_EQ, fcntl_2args_struct[i].arg));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(fcntl), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* mprotect
|
||||
*
|
||||
* Although this filter prevents making non-executable pages executable
|
||||
* again, there is nothing stopping an attacker from using mmap to load
|
||||
* an arbitrary executable file with PROT_READ|PROT_EXEC in the first
|
||||
* place
|
||||
*/
|
||||
const int mprotect_prot_array[3] = {
|
||||
PROT_NONE,
|
||||
PROT_READ,
|
||||
PROT_READ|PROT_WRITE
|
||||
};
|
||||
for (i = 0; i < 3; i++) {
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect), 1,
|
||||
SCMP_A2(SCMP_CMP_EQ, mprotect_prot_array[i]));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(mprotect), 60);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* mmap */
|
||||
struct mmap_struct_t {
|
||||
int prot;
|
||||
int flags;
|
||||
};
|
||||
const struct mmap_struct_t mmap_anon_struct[4] = {
|
||||
{ PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE },
|
||||
{ PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS },
|
||||
{ PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK },
|
||||
{ PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS }
|
||||
};
|
||||
for (i = 0; i < 4; i++) {
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 4,
|
||||
SCMP_A2(SCMP_CMP_EQ, mmap_anon_struct[i].prot),
|
||||
SCMP_A3(SCMP_CMP_EQ, mmap_anon_struct[i].flags),
|
||||
SCMP_A4(SCMP_CMP_EQ, (unsigned)-1),
|
||||
SCMP_A5(SCMP_CMP_EQ, 0));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
const struct mmap_struct_t mmap_noanon_struct[3] = {
|
||||
{ PROT_READ, MAP_PRIVATE },
|
||||
{ PROT_READ, MAP_SHARED },
|
||||
{ PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE }
|
||||
};
|
||||
for (i = 0; i < 3; i++) {
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 4,
|
||||
SCMP_A2(SCMP_CMP_EQ, mmap_noanon_struct[i].prot),
|
||||
SCMP_A3(SCMP_CMP_EQ, mmap_noanon_struct[i].flags),
|
||||
SCMP_A4(SCMP_CMP_NE, (unsigned)-1),
|
||||
SCMP_A5(SCMP_CMP_EQ, 0));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 4,
|
||||
SCMP_A2(SCMP_CMP_EQ, PROT_READ|PROT_WRITE),
|
||||
SCMP_A3(SCMP_CMP_EQ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE),
|
||||
SCMP_A4(SCMP_CMP_NE, (unsigned)-1),
|
||||
SCMP_A5(SCMP_CMP_NE, 0)); /* NE 0, so can't be in the struct */
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(mmap), 60);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* madvise */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(madvise), 1,
|
||||
SCMP_A2(SCMP_CMP_EQ, MADV_DONTNEED));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(madvise), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
#ifndef __i386__
|
||||
/* socket */
|
||||
struct socket_struct_t {
|
||||
int domain;
|
||||
int type;
|
||||
int proto;
|
||||
};
|
||||
const struct socket_struct_t socket_struct[2] = {
|
||||
{ PF_INET, SOCK_STREAM, IPPROTO_TCP },
|
||||
{ PF_INET, SOCK_STREAM, IPPROTO_IP }
|
||||
};
|
||||
for (i = 0; i < 2; i++) {
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 3,
|
||||
SCMP_A0(SCMP_CMP_EQ, socket_struct[i].domain),
|
||||
SCMP_A1(SCMP_CMP_EQ, socket_struct[i].type),
|
||||
SCMP_A2(SCMP_CMP_EQ, socket_struct[i].proto));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(socket), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* connect */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(connect), 2,
|
||||
SCMP_A0(SCMP_CMP_GE, 4),
|
||||
SCMP_A2(SCMP_CMP_EQ, 16));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(connect), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* getpeername */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getpeername), 1,
|
||||
SCMP_A0(SCMP_CMP_GE, 4));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(getpeername), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
/* futex */
|
||||
struct futex_struct_t {
|
||||
int op;
|
||||
int val;
|
||||
};
|
||||
const struct futex_struct_t futex_struct[5] = {
|
||||
{ FUTEX_WAIT_PRIVATE, 1 },
|
||||
{ FUTEX_WAIT_PRIVATE, 2 },
|
||||
{ FUTEX_WAKE, 2147483647 },
|
||||
{ FUTEX_WAKE_PRIVATE, 1 },
|
||||
{ FUTEX_WAKE_PRIVATE, 2147483647 }
|
||||
};
|
||||
for (i = 0; i < 5; i++) {
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex), 2,
|
||||
SCMP_A1(SCMP_CMP_EQ, futex_struct[i].op),
|
||||
SCMP_A2(SCMP_CMP_EQ, futex_struct[i].val));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(futex), 3,
|
||||
SCMP_A1(SCMP_CMP_EQ, FUTEX_WAKE_PRIVATE),
|
||||
SCMP_A2(SCMP_CMP_EQ, 2),
|
||||
SCMP_A3(SCMP_CMP_EQ, NULL));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(futex), 100);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* set_robust_list */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(set_robust_list), 1,
|
||||
SCMP_A1(SCMP_CMP_EQ, 24));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(set_robust_list), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* setrlimit */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(setrlimit), 1,
|
||||
SCMP_A0(SCMP_CMP_EQ, RLIMIT_CORE));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(setrlimit), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* getrlimit */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getrlimit), 1,
|
||||
SCMP_A0(SCMP_CMP_EQ, RLIMIT_STACK));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getrlimit), 1,
|
||||
SCMP_A0(SCMP_CMP_EQ, RLIMIT_CORE));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(getrlimit), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* eventfd2 */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(eventfd2), 2,
|
||||
SCMP_A0(SCMP_CMP_EQ, 0),
|
||||
SCMP_A1(SCMP_CMP_EQ, O_NONBLOCK|O_CLOEXEC));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(eventfd2), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* rt_sigprocmask */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask), 3,
|
||||
SCMP_A0(SCMP_CMP_EQ, SIG_UNBLOCK),
|
||||
SCMP_A2(SCMP_CMP_EQ, NULL),
|
||||
SCMP_A3(SCMP_CMP_EQ, 8));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask), 1,
|
||||
SCMP_A0(SCMP_CMP_EQ, SIG_SETMASK));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(rt_sigprocmask), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* rt_sigaction */
|
||||
const int sigaction_signal_array[13] = {
|
||||
SIGALRM,
|
||||
SIGCHLD,
|
||||
SIGCONT,
|
||||
SIGFPE,
|
||||
SIGHUP,
|
||||
SIGINT,
|
||||
SIGPIPE,
|
||||
SIGQUIT,
|
||||
SIGTERM,
|
||||
SIGTRAP,
|
||||
SIGUSR1,
|
||||
SIGUSR2,
|
||||
SIGWINCH
|
||||
};
|
||||
for (i = 0; i < 13; i++) {
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigaction), 2,
|
||||
SCMP_A0(SCMP_CMP_EQ, sigaction_signal_array[i]),
|
||||
SCMP_A3(SCMP_CMP_EQ, 8));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(rt_sigaction), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
#ifndef __i386__
|
||||
/* sendto */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sendto), 4,
|
||||
SCMP_A0(SCMP_CMP_GE, 4),
|
||||
SCMP_A3(SCMP_CMP_EQ, 0),
|
||||
SCMP_A4(SCMP_CMP_EQ, NULL),
|
||||
SCMP_A5(SCMP_CMP_EQ, 0));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(sendto), 70);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* recvfrom */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(recvfrom), 5,
|
||||
SCMP_A0(SCMP_CMP_GE, 4),
|
||||
SCMP_A2(SCMP_CMP_EQ, 8),
|
||||
SCMP_A3(SCMP_CMP_EQ, 0),
|
||||
SCMP_A4(SCMP_CMP_EQ, NULL),
|
||||
SCMP_A5(SCMP_CMP_EQ, NULL));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(recvfrom), 70);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
/* access */
|
||||
const int access_mode_array[3] = {
|
||||
R_OK,
|
||||
F_OK,
|
||||
X_OK
|
||||
};
|
||||
for (i = 0; i < 3; i++) {
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(access), 1,
|
||||
SCMP_A1(SCMP_CMP_EQ, access_mode_array[i]));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(access), 60);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* write */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 2,
|
||||
SCMP_A0(SCMP_CMP_LT, 3),
|
||||
SCMP_A2(SCMP_CMP_LE, 4096));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 2,
|
||||
SCMP_A0(SCMP_CMP_GT, 3),
|
||||
SCMP_A2(SCMP_CMP_LE, 4096));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 2,
|
||||
SCMP_A0(SCMP_CMP_EQ, 3),
|
||||
/* SCMP_A1(SCMP_CMP_EQ, "\1\0\0\0\0\0\0\0"), */
|
||||
SCMP_A2(SCMP_CMP_EQ, 8));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(write), 200);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* read */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 2,
|
||||
SCMP_A0(SCMP_CMP_EQ, 0),
|
||||
SCMP_A2(SCMP_CMP_EQ, 256));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 2,
|
||||
SCMP_A0(SCMP_CMP_GE, 3),
|
||||
SCMP_A2(SCMP_CMP_LE, 16384));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(read), 200);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* open */
|
||||
const int open_flag_array[6] = {
|
||||
O_RDONLY,
|
||||
O_RDONLY|O_CLOEXEC,
|
||||
O_RDONLY|O_NOCTTY|O_NONBLOCK,
|
||||
O_WRONLY|O_CREAT|O_APPEND,
|
||||
O_WRONLY|O_CREAT|O_TRUNC,
|
||||
O_RDWR|O_CREAT|O_TRUNC
|
||||
};
|
||||
for (i = 0; i < 6; i++) {
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 1,
|
||||
SCMP_A1(SCMP_CMP_EQ, open_flag_array[i]));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(open), 60);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* openat */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), 2,
|
||||
SCMP_A0(SCMP_CMP_EQ, AT_FDCWD),
|
||||
SCMP_A2(SCMP_CMP_EQ, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(openat), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* readlink */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(readlink), 1,
|
||||
SCMP_A2(SCMP_CMP_EQ, 4095));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(readlink), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* getdents */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EBADF), SCMP_SYS(getdents), 1,
|
||||
SCMP_A2(SCMP_CMP_EQ, 32768));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(getdents), 70);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* clock_gettime */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(clock_gettime), 1,
|
||||
SCMP_A0(SCMP_CMP_EQ, CLOCK_PROCESS_CPUTIME_ID));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(clock_gettime), 60);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* getrusage */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(getrusage), 1,
|
||||
SCMP_A0(SCMP_CMP_EQ, 0)); /* RUSAGE_SELF */
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(getrusage), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* select */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(select), 2,
|
||||
SCMP_A2(SCMP_CMP_EQ, NULL),
|
||||
SCMP_A3(SCMP_CMP_EQ, NULL));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(select), 200);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* poll */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(poll), 2,
|
||||
SCMP_A1(SCMP_CMP_LE, 3),
|
||||
SCMP_A2(SCMP_CMP_GE, 0),
|
||||
SCMP_A2(SCMP_CMP_LE, 1000));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(poll), 200);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* wait4 */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(wait4), 2,
|
||||
SCMP_A2(SCMP_CMP_EQ, WNOHANG),
|
||||
SCMP_A3(SCMP_CMP_EQ, NULL));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(wait4), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* tgkill */
|
||||
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(tgkill), 2,
|
||||
SCMP_A0(SCMP_CMP_EQ, getpid()),
|
||||
SCMP_A2(SCMP_CMP_EQ, SIGABRT));
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = seccomp_syscall_priority(ctx, SCMP_SYS(tgkill), 50);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* apply filters */
|
||||
rc = seccomp_load(ctx);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
|
||||
/* seccomp has been seccessfully loaded and is now enforced */
|
||||
return;
|
||||
|
||||
fail:
|
||||
seccomp_release(ctx);
|
||||
fprintf(stderr, "Could not load the sandbox (libseccomp error %d)\n", -rc);
|
||||
exit(1);
|
||||
}
|
||||
6
src/core/sandbox.h
Normal file
6
src/core/sandbox.h
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
extern void create_namespaces(void);
|
||||
extern void drop_privileges(void);
|
||||
extern void enable_seccomp_sandbox(void);
|
||||
extern void enforce_resource_limits(void);
|
||||
|
||||
extern int sandbox;
|
||||
|
|
@ -62,6 +62,9 @@ static void cmd_upgrade(const char *data)
|
|||
char *session_file, *str;
|
||||
char *binary;
|
||||
|
||||
if (sandbox)
|
||||
return;
|
||||
|
||||
if (*data == '\0')
|
||||
data = irssi_binary;
|
||||
|
||||
|
|
|
|||
|
|
@ -553,6 +553,9 @@ static void cmd_exec(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
|
|||
char *args;
|
||||
void *free_arg;
|
||||
|
||||
if (sandbox)
|
||||
return;
|
||||
|
||||
g_return_if_fail(data != NULL);
|
||||
|
||||
if (cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "settings.h"
|
||||
#include "session.h"
|
||||
#include "servers.h"
|
||||
#include "sandbox.h"
|
||||
|
||||
#include "printtext.h"
|
||||
#include "fe-common-core.h"
|
||||
|
|
@ -74,11 +75,20 @@ void mainwindow_activity_deinit(void);
|
|||
void mainwindows_layout_init(void);
|
||||
void mainwindows_layout_deinit(void);
|
||||
|
||||
#ifdef HAVE_SECCOMP
|
||||
void create_namespaces(void);
|
||||
void drop_privileges(void);
|
||||
void enforce_resource_limits(void);
|
||||
void enable_seccomp_sandbox(void);
|
||||
#endif
|
||||
|
||||
void term_dummy_init(void);
|
||||
void term_dummy_deinit(void);
|
||||
|
||||
static int dirty, full_redraw, dummy;
|
||||
|
||||
int sandbox = 0;
|
||||
|
||||
static GMainLoop *main_loop;
|
||||
int quitting;
|
||||
|
||||
|
|
@ -278,6 +288,7 @@ int main(int argc, char **argv)
|
|||
static GOptionEntry options[] = {
|
||||
{ "dummy", 'd', 0, G_OPTION_ARG_NONE, &dummy, "Use the dummy terminal mode", NULL },
|
||||
{ "version", 'v', 0, G_OPTION_ARG_NONE, &version, "Display irssi version", NULL },
|
||||
{ "sandbox", 's', 0, G_OPTION_ARG_NONE, &sandbox, "Enable the sandbox", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
int loglev;
|
||||
|
|
@ -293,6 +304,18 @@ int main(int argc, char **argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (sandbox) {
|
||||
#ifdef HAVE_SECCOMP
|
||||
create_namespaces();
|
||||
drop_privileges();
|
||||
enforce_resource_limits();
|
||||
enable_seccomp_sandbox();
|
||||
#else
|
||||
fprintf(stderr, "This build does not support sandboxing\n");
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
dummy = FALSE;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue