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:
Michael Santos
2014-06-06 14:35:43 -04:00
parent 433ea39bcb
commit fa07b11b85

118
include/alcove_seccomp.hrl Normal file
View 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()]
}).