Add syscall filter BPF program generator.

BUG=chromium-os:25429
BUG=chromium-os:27878
TEST=syscall_filter_unittest

Change-Id: I3a4334a3c568178e19b18e7f3ed97517b03afd1b
Reviewed-on: https://gerrit.chromium.org/gerrit/18914
Reviewed-by: Kees Cook <keescook@chromium.org>
Commit-Ready: Jorge Lucangeli Obes <jorgelo@chromium.org>
Tested-by: Jorge Lucangeli Obes <jorgelo@chromium.org>
diff --git a/bpf.h b/bpf.h
new file mode 100644
index 0000000..3759813
--- /dev/null
+++ b/bpf.h
@@ -0,0 +1,155 @@
+/* bpf.h
+ * Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Berkeley Packet Filter functions.
+ */
+
+#ifndef BPF_H
+#define BPF_H
+
+#include <asm/bitsperlong.h>   /* for __BITS_PER_LONG */
+#include <linux/filter.h>
+#include <stddef.h>
+#include <sys/user.h>
+
+#if __BITS_PER_LONG == 32
+#define BITS32
+#elif __BITS_PER_LONG == 64
+#define BITS64
+#endif
+
+/* Constants for comparison operators. */
+#define MIN_OPERATOR 128
+enum operator {
+	EQ = MIN_OPERATOR,
+	NE,
+	LT,
+	LE,
+	GT,
+	GE
+};
+
+/*
+ * BPF return values and data structures,
+ * since they're not yet in the kernel.
+ */
+#define SECCOMP_RET_KILL	0x00000000U /* kill the task immediately */
+#define SECCOMP_RET_TRAP	0x00030000U /* return SIGSYS */
+#define SECCOMP_RET_ERRNO	0x00050000U /* return -1 and set errno */
+#define SECCOMP_RET_ALLOW	0x7fff0000U /* allow */
+
+#define SECCOMP_RET_DATA	0x0000ffffU /* mask for return value */
+
+struct seccomp_data {
+	int nr;
+	__u32 arch;
+	__u64 instruction_pointer;
+	__u64 args[6];
+};
+
+/* Size-dependent defines. */
+#if defined(BITS32)
+/* On 32 bits, comparisons take 2 instructions: 1 load arg, and 1 cmp. */
+#define BPF_LOAD_ARG_LEN 1U
+#define BPF_COMP_LEN 1U
+#define BPF_ARG_COMP_LEN (BPF_LOAD_ARG_LEN + BPF_COMP_LEN)
+
+#define bpf_comp_jeq bpf_comp_jeq32
+
+#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)])
+
+#elif __BITS_PER_LONG == 64
+#define BITS64
+/* On 64 bits, comparisons take 7 instructions: 4 load arg, and 3 cmp. */
+#define BPF_LOAD_ARG_LEN 4U
+#define BPF_COMP_LEN 3U
+#define BPF_ARG_COMP_LEN (BPF_LOAD_ARG_LEN + BPF_COMP_LEN)
+
+#define bpf_comp_jeq bpf_comp_jeq64
+
+/* Ensure that we load the logically correct offset. */
+#if defined(__LITTLE_ENDIAN)
+#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)])
+#define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32)
+#elif defined(__BIG_ENDIAN)
+#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32)
+#define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)])
+#else
+#error "Unknown endianness"
+#endif
+
+#endif
+
+/* Common jump targets. */
+#define NEXT 0
+#define SKIP 1
+#define SKIPN(_n) (_n)
+
+/* Support for labels in BPF programs. */
+#define JUMP_JT 0xff
+#define JUMP_JF 0xff
+#define LABEL_JT 0xfe
+#define LABEL_JF 0xfe
+
+#define MAX_BPF_LABEL_LEN 32
+
+#define BPF_LABELS_MAX 256
+struct bpf_labels {
+	int count;
+	struct __bpf_label {
+		const char *label;
+		unsigned int location;
+	} labels[BPF_LABELS_MAX];
+};
+
+/* BPF instruction manipulation functions and macros. */
+inline size_t set_bpf_instr(struct sock_filter *instr,
+		unsigned short code, unsigned int k,
+		unsigned char jt, unsigned char jf);
+
+#define set_bpf_stmt(_block, _code, _k) \
+	set_bpf_instr((_block), (_code), (_k), 0, 0)
+
+#define set_bpf_jump(_block, _code, _k, _jt, _jf) \
+	set_bpf_instr((_block), (_code), (_k), (_jt), (_jf))
+
+#define set_bpf_lbl(_block, _lbl_id) \
+	set_bpf_jump((_block), BPF_JMP+BPF_JA, (_lbl_id), \
+			LABEL_JT, LABEL_JF)
+
+#define set_bpf_jump_lbl(_block, _lbl_id) \
+	set_bpf_jump((_block), BPF_JMP+BPF_JA, (_lbl_id), \
+			JUMP_JT, JUMP_JF)
+
+#define set_bpf_ret_kill(_block) \
+	set_bpf_stmt((_block), BPF_RET+BPF_K, SECCOMP_RET_KILL)
+
+#define set_bpf_ret_errno(_block, _errno) \
+	set_bpf_stmt((_block), BPF_RET+BPF_K, \
+		SECCOMP_RET_ERRNO | ((_errno) & SECCOMP_RET_DATA))
+
+#define set_bpf_ret_allow(_block) \
+	set_bpf_stmt((_block), BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
+
+/* BPF label functions. */
+int bpf_resolve_jumps(struct bpf_labels *labels,
+		struct sock_filter *filter, size_t count);
+int bpf_label_id(struct bpf_labels *labels, const char *label);
+void free_label_strings(struct bpf_labels *labels);
+
+/* BPF helper functions. */
+size_t bpf_load_arg(struct sock_filter *filter, int argidx);
+size_t bpf_comp_jeq(struct sock_filter *filter, unsigned long c,
+		unsigned char jt, unsigned char jf);
+
+/* Functions called by syscall_filter.c */
+size_t bpf_arg_comp(struct sock_filter **pfilter,
+		int op, int argidx, unsigned long c, unsigned int label_id);
+
+/* Debug */
+void dump_bpf_prog(struct sock_fprog *fprog);
+void dump_bpf_filter(struct sock_filter *filter, unsigned short len);
+
+#endif /* _MINIJAIL_BPF_H_ */