From fa07b11b8557191c679a95349558defbbdcd3b7f Mon Sep 17 00:00:00 2001 From: Michael Santos Date: Fri, 6 Jun 2014 14:35:43 -0400 Subject: [PATCH] Add macros for Linux seccomp mode Macros to create bpf instructions, taken from procket. A minimal example (set up for little endian ARM): -module(filt). -export([enforce/2,enforce/3]). -include_lib("alcove/include/alcove.hrl"). -include_lib("alcove/include/alcove_seccomp.hrl"). -define(EM_ARM, 40). -define(__AUDIT_ARCH_LE, 16#40000000). -define(AUDIT_ARCH_ARM, ?EM_ARM bxor ?__AUDIT_ARCH_LE). -define(OFFSET_SYSCALL_NR, 0). -define(OFFSET_ARCH_NR, 4). -define(VALIDATE_ARCHITECTURE(Offset_arch_nr, Arch_nr), [ ?BPF_STMT(?BPF_LD+?BPF_W+?BPF_ABS, Offset_arch_nr), ?BPF_JUMP(?BPF_JMP+?BPF_JEQ+?BPF_K, Arch_nr, 1, 0), ?BPF_STMT(?BPF_RET+?BPF_K, ?SECCOMP_RET_KILL) ]). -define(EXAMINE_SYSCALL(Offset_syscall_nr), ?BPF_STMT(?BPF_LD+?BPF_W+?BPF_ABS, Offset_syscall_nr)). -define(ALLOW_SYSCALL(Syscall_nr), [ ?BPF_JUMP(?BPF_JMP+?BPF_JEQ+?BPF_K, Syscall_nr, 0, 1), ?BPF_STMT(?BPF_RET+?BPF_K, ?SECCOMP_RET_ALLOW) ]). -define(NR_exit, 1). -define(NR_read, 3). -define(NR_write, 4). -define(NR_setrlimit, 75). -define(NR_getrlimit, 76). -define(NR_sigreturn, 119). -define(NR_poll, 168). -define(NR_rt_sigreturn, 173). -define(NR_ugetrlimit, 191). -define(NR_exit_group, 248). filter() -> [ ?VALIDATE_ARCHITECTURE(?OFFSET_ARCH_NR, ?AUDIT_ARCH_ARM), ?EXAMINE_SYSCALL(?OFFSET_SYSCALL_NR), ?ALLOW_SYSCALL(?NR_rt_sigreturn), ?ALLOW_SYSCALL(?NR_sigreturn), ?ALLOW_SYSCALL(?NR_exit_group), ?ALLOW_SYSCALL(?NR_exit), ?ALLOW_SYSCALL(?NR_read), ?ALLOW_SYSCALL(?NR_write), ?ALLOW_SYSCALL(?NR_setrlimit), ?ALLOW_SYSCALL(?NR_getrlimit), ?ALLOW_SYSCALL(?NR_ugetrlimit), ?ALLOW_SYSCALL(?NR_poll), ?BPF_STMT(?BPF_RET+?BPF_K, ?SECCOMP_RET_KILL) ]. enforce(Drv, Pids) -> enforce(Drv, Pids, filter()). enforce(Drv, Pids, Filter) -> PR_SET_NO_NEW_PRIVS = alcove:define(Drv, 'PR_SET_NO_NEW_PRIVS'), PR_SET_SECCOMP = alcove:define(Drv, 'PR_SET_SECCOMP'), SECCOMP_MODE_FILTER = alcove:define(Drv, 'SECCOMP_MODE_FILTER'), {ok,_,_,_,_,_} = alcove:prctl(Drv, Pids, PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0), Prog = [ <<(iolist_size(Filter) div 8):2/native-unsigned-integer-unit:8>>, <<0:16>>, {ptr, list_to_binary(Filter)} ], {ok,_,_,_,_,_} = alcove:prctl(Drv, Pids, PR_SET_SECCOMP, SECCOMP_MODE_FILTER, Prog, 0, 0), ok. ``` And running it: ``` 1> {ok,Drv} = alcove_drv:start([termsig]). {ok,<0.44.0>} 2> {ok,Fork} = alcove:fork(Drv). {ok,19125} 3> filt:enforce(Drv, [Fork]). ok 4> alcove:version(Drv, [Fork]). <<"0.5.0">> 5> alcove:getpid(Drv, [Fork]). 19125 6> alcove:fork(Drv, [Fork]). ok 7> alcove:event(Drv, [Fork]). {termsig,31} 8> alcove:signal_constant(Drv, 31). 'SIGSYS' ``` --- include/alcove_seccomp.hrl | 118 +++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 include/alcove_seccomp.hrl diff --git a/include/alcove_seccomp.hrl b/include/alcove_seccomp.hrl new file mode 100644 index 0000000..4dad669 --- /dev/null +++ b/include/alcove_seccomp.hrl @@ -0,0 +1,118 @@ +% Copyright (c) 2014, Michael Santos +% Permission to use, copy, modify, and/or distribute this software for any +% purpose with or without fee is hereby granted, provided that the above +% copyright notice and this permission notice appear in all copies. +% +% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +%%------------------------------------------------------------------------- +%%% BPF Filter +%%------------------------------------------------------------------------- + +%% instruction classes +-define(BPF_CLASS(Code), (Code band 16#07)). +-define(BPF_LD, 16#00). +-define(BPF_LDX, 16#01). +-define(BPF_ST, 16#02). +-define(BPF_STX, 16#03). +-define(BPF_ALU, 16#04). +-define(BPF_JMP, 16#05). +-define(BPF_RET, 16#06). +-define(BPF_MISC, 16#07). + +%% ld/ldx fields +-define(BPF_SIZE(Code), (Code band 16#18)). +-define(BPF_W, 16#00). +-define(BPF_H, 16#08). +-define(BPF_B, 16#10). +-define(BPF_MODE(Code), (Code band 16#e0)). +-define(BPF_IMM, 16#00). +-define(BPF_ABS, 16#20). +-define(BPF_IND, 16#40). +-define(BPF_MEM, 16#60). +-define(BPF_LEN, 16#80). +-define(BPF_MSH, 16#a0). + +%% alu/jmp fields +-define(BPF_OP(Code), (Code band 16#f0)). +-define(BPF_ADD, 16#00). +-define(BPF_SUB, 16#10). +-define(BPF_MUL, 16#20). +-define(BPF_DIV, 16#30). +-define(BPF_OR, 16#40). +-define(BPF_AND, 16#50). +-define(BPF_LSH, 16#60). +-define(BPF_RSH, 16#70). +-define(BPF_NEG, 16#80). +-define(BPF_JA, 16#00). +-define(BPF_JEQ, 16#10). +-define(BPF_JGT, 16#20). +-define(BPF_JGE, 16#30). +-define(BPF_JSET, 16#40). +-define(BPF_SRC(Code), (Code band 16#08)). +-define(BPF_K, 16#00). +-define(BPF_X, 16#08). + +%% ret - BPF_K and BPF_X also apply +-define(BPF_RVAL(Code), (Code band 16#18)). +-define(BPF_A, 16#10). + +%% misc +-define(BPF_MISCOP(Code), (Code band 16#f8)). +-define(BPF_TAX, 16#00). +-define(BPF_TXA, 16#80). + +%% struct bpf_insn { +%% u_short code; +%% u_char jt; +%% u_char jf; +%% bpf_u_int32 k; +%% }; +%% NOTE: the man page says k is a u_long, +%% the header says u_int32_t. +-record(alcove_filter, { + code = 0 :: 0..65535, + jt = 0 :: 0..255, + jf = 0 :: 0..255, + k = 0 :: non_neg_integer() + }). + +-define(BPF_STMT(Code, K), bpf:stmt(Code, K)). +-define(BPF_JUMP(Code, K, JT, JF), bpf:jump(Code, K, JT, JF)). + + +% Valid values for seccomp.mode and prctl(PR_SET_SECCOMP, ) +-define(SECCOMP_MODE_DISABLED, 0). % seccomp is not in use. +-define(SECCOMP_MODE_STRICT, 1). % uses hard-coded filter. +-define(SECCOMP_MODE_FILTER, 2). % uses user-supplied filter. + +-define(SECCOMP_RET_KILL, 16#00000000). % kill the task immediately +-define(SECCOMP_RET_TRAP, 16#00030000). % disallow and force a SIGSYS +-define(SECCOMP_RET_ERRNO, 16#00050000). % returns an errno +-define(SECCOMP_RET_TRACE, 16#7ff00000). % pass to a tracer or disallow +-define(SECCOMP_RET_ALLOW, 16#7fff0000). % allow + +% Masks for the return value sections. +-define(SECCOMP_RET_ACTION, 16#7fff0000). +-define(SECCOMP_RET_DATA, 16#0000ffff). + +% struct seccomp_data - the format the BPF program executes over. +% nr: the system call number +% arch: indicates system call convention as an AUDIT_ARCH_* value +% as defined in . +% instruction_pointer: at the time of the system call. +% args: up to 6 system call arguments always stored as 64-bit values +% regardless of the architecture. + +-record(alcove_seccomp_data, { + nr = 0 :: integer(), + arch = 0 :: non_neg_integer(), + instruction_pointer = 0 :: non_neg_integer(), + args = [0,0,0,0,0,0] :: [non_neg_integer()] + }).