mirror of
https://github.com/uselessd/alcove.git
synced 2026-04-15 09:15:19 +00:00
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'
```
This commit is contained in:
118
include/alcove_seccomp.hrl
Normal file
118
include/alcove_seccomp.hrl
Normal file
@@ -0,0 +1,118 @@
|
||||
% Copyright (c) 2014, Michael Santos <michael.santos@gmail.com>
|
||||
% 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, <mode>)
|
||||
-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 <linux/audit.h>.
|
||||
% 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()]
|
||||
}).
|
||||
Reference in New Issue
Block a user