|
|
@ -8,7 +8,159 @@ |
|
|
|
#include <grp.h> |
|
|
|
|
|
|
|
#ifdef __linux__ |
|
|
|
|
|
|
|
#include <sys/prctl.h> |
|
|
|
#include <sys/syscall.h> |
|
|
|
#include <linux/seccomp.h> |
|
|
|
#include <linux/filter.h> |
|
|
|
#include <syscall.h> |
|
|
|
|
|
|
|
/************ SECCOMP ************/ |
|
|
|
#ifdef __X32_SYSCALL_BIT |
|
|
|
#define X32_SYSCALL_BIT __X32_SYSCALL_BIT |
|
|
|
#else |
|
|
|
#define X32_SYSCALL_BIT 0x40000000 |
|
|
|
#endif |
|
|
|
// block most of the undesired syscalls to harden against code execution
|
|
|
|
static long blocked_syscalls[] = { |
|
|
|
#ifdef SYS_execv |
|
|
|
SYS_execv, |
|
|
|
#endif |
|
|
|
SYS_execve,SYS_execveat, |
|
|
|
#ifdef SYS_exec_with_loader |
|
|
|
SYS_exec_with_loader, |
|
|
|
#endif |
|
|
|
SYS_clone, |
|
|
|
#ifdef SYS_clone3 |
|
|
|
SYS_clone3, |
|
|
|
#endif |
|
|
|
#ifdef SYS_osf_execve |
|
|
|
SYS_osf_execve, |
|
|
|
#endif |
|
|
|
#ifdef SYS_fork |
|
|
|
SYS_fork, |
|
|
|
#endif |
|
|
|
#ifdef SYS_vfork |
|
|
|
SYS_vfork, |
|
|
|
#endif |
|
|
|
#ifdef SYS_unlink |
|
|
|
SYS_unlink, |
|
|
|
#endif |
|
|
|
SYS_unlinkat, |
|
|
|
#ifdef SYS_chmod |
|
|
|
SYS_chmod, |
|
|
|
#endif |
|
|
|
SYS_fchmod,SYS_fchmodat, |
|
|
|
#ifdef SYS_chown |
|
|
|
SYS_chown, |
|
|
|
#endif |
|
|
|
#ifdef SYS_chown32 |
|
|
|
SYS_chown32, |
|
|
|
#endif |
|
|
|
SYS_fchown, |
|
|
|
#ifdef SYS_fchown32 |
|
|
|
SYS_fchown32, |
|
|
|
#endif |
|
|
|
#ifdef SYS_lchown |
|
|
|
SYS_lchown, |
|
|
|
#endif |
|
|
|
#ifdef SYS_lchown32 |
|
|
|
SYS_lchown32, |
|
|
|
#endif |
|
|
|
SYS_fchownat, |
|
|
|
#ifdef SYS_symlink |
|
|
|
SYS_symlink, |
|
|
|
#endif |
|
|
|
SYS_symlinkat, |
|
|
|
#ifdef SYS_link |
|
|
|
SYS_link, |
|
|
|
#endif |
|
|
|
SYS_linkat, |
|
|
|
SYS_pkey_mprotect,SYS_mprotect, |
|
|
|
SYS_truncate, |
|
|
|
#ifdef SYS_truncate64 |
|
|
|
SYS_truncate64, |
|
|
|
#endif |
|
|
|
SYS_ftruncate, |
|
|
|
#ifdef SYS_ftruncate64 |
|
|
|
SYS_ftruncate64, |
|
|
|
#endif |
|
|
|
#ifdef SYS_mknod |
|
|
|
SYS_mknod, |
|
|
|
#endif |
|
|
|
SYS_mknodat, |
|
|
|
#ifdef SYS_mkdir |
|
|
|
SYS_mkdir, |
|
|
|
#endif |
|
|
|
SYS_mkdirat, |
|
|
|
#ifdef SYS_rmdir |
|
|
|
SYS_rmdir, |
|
|
|
#endif |
|
|
|
#ifdef SYS_rename |
|
|
|
SYS_rename, |
|
|
|
#endif |
|
|
|
SYS_renameat,SYS_renameat2 |
|
|
|
}; |
|
|
|
#define BLOCKED_SYSCALL_COUNT (sizeof(blocked_syscalls)/sizeof(*blocked_syscalls)) |
|
|
|
|
|
|
|
static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf, __u32 k) |
|
|
|
{ |
|
|
|
filter->code = code; |
|
|
|
filter->jt = jt; |
|
|
|
filter->jf = jf; |
|
|
|
filter->k = k; |
|
|
|
} |
|
|
|
// deny all blocked syscalls
|
|
|
|
bool set_seccomp() |
|
|
|
{ |
|
|
|
#define SECCOMP_PROG_SIZE (6 + BLOCKED_SYSCALL_COUNT) |
|
|
|
struct sock_fprog prog = { .len = SECCOMP_PROG_SIZE }; |
|
|
|
int res,i,idx=0; |
|
|
|
|
|
|
|
prog.filter = calloc(SECCOMP_PROG_SIZE, sizeof(*prog.filter)); |
|
|
|
if (!prog.filter) return false; |
|
|
|
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, arch_nr); |
|
|
|
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, 0, 3 + BLOCKED_SYSCALL_COUNT, ARCH_NR); // fail
|
|
|
|
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr); |
|
|
|
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JGT + BPF_K, 1 + BLOCKED_SYSCALL_COUNT, 0, X32_SYSCALL_BIT - 1); // fail
|
|
|
|
/*
|
|
|
|
// ! THIS IS NOT WORKING BECAUSE perror() in glibc dups() stderr
|
|
|
|
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, 0, 3, SYS_write); // special check for write call
|
|
|
|
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_arg(0)); // fd
|
|
|
|
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JGT + BPF_K, 2 + BLOCKED_SYSCALL_COUNT, 0, 2); // 1 - stdout, 2 - stderr. greater are bad
|
|
|
|
set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr); // reload syscall_nr
|
|
|
|
*/ |
|
|
|
for(i=0 ; i<BLOCKED_SYSCALL_COUNT ; i++) |
|
|
|
{ |
|
|
|
set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, BLOCKED_SYSCALL_COUNT-i, 0, blocked_syscalls[i]); |
|
|
|
} |
|
|
|
set_filter(&prog.filter[idx++], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_ALLOW); // success case
|
|
|
|
set_filter(&prog.filter[idx++], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_KILL); // fail case
|
|
|
|
res=prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); |
|
|
|
free(prog.filter); |
|
|
|
return res>=0; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool sec_harden() |
|
|
|
{ |
|
|
|
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) |
|
|
|
{ |
|
|
|
perror("PR_SET_NO_NEW_PRIVS(prctl)"); |
|
|
|
return false; |
|
|
|
} |
|
|
|
#if ARCH_NR!=0 |
|
|
|
if (!set_seccomp()) |
|
|
|
{ |
|
|
|
perror("seccomp"); |
|
|
|
return false; |
|
|
|
} |
|
|
|
#endif |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool checkpcap(uint64_t caps) |
|
|
|
{ |
|
|
@ -69,7 +221,17 @@ bool dropcaps() |
|
|
|
} |
|
|
|
return true; |
|
|
|
} |
|
|
|
#endif |
|
|
|
#else // __linux__
|
|
|
|
|
|
|
|
bool sec_harden() |
|
|
|
{ |
|
|
|
// noop
|
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
#endif // __linux__
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool can_drop_root() |
|
|
|
{ |
|
|
|