mirror of
https://github.com/bol-van/zapret.git
synced 2024-11-11 17:29:16 +05:00
tpws,nfqws: seccomp hardening
This commit is contained in:
parent
3f8825e668
commit
7af2d43d5f
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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
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
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
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.
|
||||
|
Loading…
Reference in New Issue
Block a user