Browse Source

tpws,nfqws: seccomp hardening

pull/127/head
bol-van 2 years ago
parent
commit
7af2d43d5f
  1. BIN
      binaries/aarch64/nfqws
  2. BIN
      binaries/aarch64/tpws
  3. BIN
      binaries/arm/nfqws
  4. BIN
      binaries/arm/tpws
  5. BIN
      binaries/mips32r1-lsb/nfqws
  6. BIN
      binaries/mips32r1-lsb/tpws
  7. BIN
      binaries/mips32r1-msb/nfqws
  8. BIN
      binaries/mips32r1-msb/tpws
  9. BIN
      binaries/mips64r2-msb/nfqws
  10. BIN
      binaries/mips64r2-msb/tpws
  11. BIN
      binaries/ppc/nfqws
  12. BIN
      binaries/ppc/tpws
  13. BIN
      binaries/x86/nfqws
  14. BIN
      binaries/x86/tpws
  15. BIN
      binaries/x86_64/nfqws
  16. BIN
      binaries/x86_64/tpws
  17. BIN
      binaries/x86_64/tpws_wsl.tgz
  18. 2
      nfq/nfqws.c
  19. 164
      nfq/sec.c
  20. 40
      nfq/sec.h
  21. 163
      tpws/sec.c
  22. 40
      tpws/sec.h
  23. 2
      tpws/tpws.c

BIN
binaries/aarch64/nfqws

Binary file not shown.

BIN
binaries/aarch64/tpws

Binary file not shown.

BIN
binaries/arm/nfqws

Binary file not shown.

BIN
binaries/arm/tpws

Binary file not shown.

BIN
binaries/mips32r1-lsb/nfqws

Binary file not shown.

BIN
binaries/mips32r1-lsb/tpws

Binary file not shown.

BIN
binaries/mips32r1-msb/nfqws

Binary file not shown.

BIN
binaries/mips32r1-msb/tpws

Binary file not shown.

BIN
binaries/mips64r2-msb/nfqws

Binary file not shown.

BIN
binaries/mips64r2-msb/tpws

Binary file not shown.

BIN
binaries/ppc/nfqws

Binary file not shown.

BIN
binaries/ppc/tpws

Binary file not shown.

BIN
binaries/x86/nfqws

Binary file not shown.

BIN
binaries/x86/tpws

Binary file not shown.

BIN
binaries/x86_64/nfqws

Binary file not shown.

BIN
binaries/x86_64/tpws

Binary file not shown.

BIN
binaries/x86_64/tpws_wsl.tgz

Binary file not shown.

2
nfq/nfqws.c

@ -276,6 +276,8 @@ static int nfq_main()
if (!rawsend_preinit(params.bind_fix4,params.bind_fix6))
goto exiterr;
sec_harden();
if (params.droproot && !droproot(params.uid, params.gid))
goto exiterr;
print_id();

164
nfq/sec.c

@ -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()
{

40
nfq/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();

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

@ -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();

2
tpws/tpws.c

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

Loading…
Cancel
Save