Add full seccomp BPF filter generation.

This CL uses the mechanism to generate filter sections from
policy strings and builds a complete filter by first
validating the arch and loading the syscall number, then
checking against all syscalls listed in the policy file, and
executing the argument filters if necessary.

BUG=chromium-os:25429
BUG=chromium-os:27878
TEST=syscall_filter_unittest
CQ-DEPEND=I3a4334a3c568178e19b18e7f3ed97517b03afd1b

Change-Id: I13a9b22ac8d55f02d5a77b5beedb955386b63723
Reviewed-on: https://gerrit.chromium.org/gerrit/19007
Tested-by: Jorge Lucangeli Obes <jorgelo@chromium.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Commit-Ready: Jorge Lucangeli Obes <jorgelo@chromium.org>
Reviewed-by: Will Drewry <wad@chromium.org>
diff --git a/bpf.c b/bpf.c
index 780f4e0..a0b6d3f 100644
--- a/bpf.c
+++ b/bpf.c
@@ -10,11 +10,7 @@
 
 #include "bpf.h"
 
-/* Common jump targets. */
-#define NEXT 0
-#define SKIP 1
-#define SKIPN(_n) (_n)
-
+/* Basic BPF instruction setter. */
 inline size_t set_bpf_instr(struct sock_filter *instr,
 		unsigned short code, unsigned int k,
 		unsigned char jt, unsigned char jf)
@@ -26,6 +22,35 @@
 	return 1U;
 }
 
+/* Architecture validation. */
+size_t bpf_validate_arch(struct sock_filter *filter)
+{
+	struct sock_filter *curr_block = filter;
+	set_bpf_stmt(curr_block++, BPF_LD+BPF_W+BPF_ABS, arch_nr);
+	set_bpf_jump(curr_block++,
+			BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, SKIP, NEXT);
+	set_bpf_ret_kill(curr_block++);
+	return curr_block - filter;
+}
+
+/* Syscall number eval functions. */
+size_t bpf_allow_syscall(struct sock_filter *filter, int nr)
+{
+	struct sock_filter *curr_block = filter;
+	set_bpf_jump(curr_block++, BPF_JMP+BPF_JEQ+BPF_K, nr, NEXT, SKIP);
+	set_bpf_stmt(curr_block++, BPF_RET+BPF_K, SECCOMP_RET_ALLOW);
+	return curr_block - filter;
+}
+
+size_t bpf_allow_syscall_args(struct sock_filter *filter,
+		int nr, unsigned int id)
+{
+	struct sock_filter *curr_block = filter;
+	set_bpf_jump(curr_block++, BPF_JMP+BPF_JEQ+BPF_K, nr, NEXT, SKIP);
+	set_bpf_jump_lbl(curr_block++, id);
+	return curr_block - filter;
+}
+
 /* Size-aware arg loaders. */
 #if defined(BITS32)
 size_t bpf_load_arg(struct sock_filter *filter, int argidx)
@@ -72,7 +97,6 @@
 
 #if defined(BITS32)
 #define bpf_comp_jeq bpf_comp_jeq32
-
 #elif defined(BITS64)
 #define bpf_comp_jeq bpf_comp_jeq64
 #endif
@@ -207,6 +231,9 @@
 /* Free label strings. */
 void free_label_strings(struct bpf_labels *labels)
 {
+	if (labels->count == 0)
+		return;
+
 	struct __bpf_label *begin = labels->labels, *end;
 
 	end = begin + labels->count;