mirror of
https://github.com/bol-van/zapret.git
synced 2025-05-24 22:32:58 +03:00
tpws,nfqws: seccomp hardening
This commit is contained in:
163
tpws/sec.c
163
tpws/sec.c
@@ -10,6 +10,157 @@
|
||||
#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)
|
||||
{
|
||||
@@ -70,7 +221,17 @@ bool dropcaps()
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#else // __linux__
|
||||
|
||||
bool sec_harden()
|
||||
{
|
||||
// noop
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // __linux__
|
||||
|
||||
|
||||
|
||||
bool can_drop_root()
|
||||
{
|
||||
|
40
tpws/sec.h
40
tpws/sec.h
@@ -5,14 +5,54 @@
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <sys/capability.h>
|
||||
#include <linux/audit.h>
|
||||
|
||||
bool checkpcap(uint64_t caps);
|
||||
bool setpcap(uint64_t caps);
|
||||
int getmaxcap();
|
||||
bool dropcaps();
|
||||
|
||||
#define syscall_nr (offsetof(struct seccomp_data, nr))
|
||||
#define arch_nr (offsetof(struct seccomp_data, arch))
|
||||
#define syscall_arg(x) (offsetof(struct seccomp_data, args[x]))
|
||||
|
||||
#if defined(__aarch64__)
|
||||
# define REG_SYSCALL regs.regs[8]
|
||||
# define ARCH_NR AUDIT_ARCH_AARCH64
|
||||
#elif defined(__amd64__)
|
||||
# define REG_SYSCALL REG_RAX
|
||||
# define ARCH_NR AUDIT_ARCH_X86_64
|
||||
#elif defined(__arm__) && (defined(__ARM_EABI__) || defined(__thumb__))
|
||||
# define REG_SYSCALL regs.uregs[7]
|
||||
# if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
# define ARCH_NR AUDIT_ARCH_ARM
|
||||
# else
|
||||
# define ARCH_NR AUDIT_ARCH_ARMEB
|
||||
# endif
|
||||
#elif defined(__i386__)
|
||||
# define REG_SYSCALL REG_EAX
|
||||
# define ARCH_NR AUDIT_ARCH_I386
|
||||
#elif defined(__mips__)
|
||||
# define REG_SYSCALL regs[2]
|
||||
# if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
# define ARCH_NR AUDIT_ARCH_MIPSEL
|
||||
# else
|
||||
# define ARCH_NR AUDIT_ARCH_MIPS
|
||||
# endif
|
||||
#elif defined(__PPC__)
|
||||
# define REG_SYSCALL regs.gpr[0]
|
||||
# define ARCH_NR AUDIT_ARCH_PPC
|
||||
#else
|
||||
# warning "Platform does not support seccomp filter yet"
|
||||
# define REG_SYSCALL 0
|
||||
# define ARCH_NR 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
bool sec_harden();
|
||||
bool can_drop_root();
|
||||
bool droproot(uid_t uid, gid_t gid);
|
||||
void print_id();
|
||||
|
@@ -943,11 +943,11 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
set_ulimit();
|
||||
sec_harden();
|
||||
|
||||
if (params.droproot && !droproot(params.uid,params.gid))
|
||||
goto exiterr;
|
||||
print_id();
|
||||
|
||||
//splice() causes the process to receive the SIGPIPE-signal if one part (for
|
||||
//example a socket) is closed during splice(). I would rather have splice()
|
||||
//fail and return -1, so blocking SIGPIPE.
|
||||
|
Reference in New Issue
Block a user