Fix decreasing loop.

As pointed out by rickyz@, we were comparing past the beginning of the
array.

Also add a bunch of unit tests for the label functionality.

Bug: 31955943
Test: syscall_filter_unittest

Change-Id: Iece922372c6548aff36cf2f2650e37d2f25eaae7
diff --git a/bpf.c b/bpf.c
index f56bc11..ce754a7 100644
--- a/bpf.c
+++ b/bpf.c
@@ -9,6 +9,7 @@
 #include <string.h>
 
 #include "bpf.h"
+#include "util.h"
 
 /* Architecture validation. */
 size_t bpf_validate_arch(struct sock_filter *filter)
@@ -187,47 +188,47 @@
 int bpf_resolve_jumps(struct bpf_labels *labels, struct sock_filter *filter,
 		      size_t len)
 {
-	size_t insn;
-	struct sock_filter *begin = filter;
-
-	/* This needs at least two instructions: one jump and one label. */
-	if (len < 2)
-		return -1;
+	struct sock_filter *instr;
+	size_t i, offset;
 
 	if (len > BPF_MAXINSNS)
 		return -1;
 
-	insn = len - 1;
-
 	/*
 	 * Walk it once, backwards, to build the label table and do fixups.
 	 * Since backward jumps are disallowed by BPF, this is easy.
 	 */
-	for (filter += insn; filter >= begin; --insn, --filter) {
-		if (filter->code != (BPF_JMP + BPF_JA))
+	for (i = 0; i < len; i++) {
+		offset = len - i - 1;
+		instr = &filter[offset];
+		if (instr->code != (BPF_JMP + BPF_JA))
 			continue;
-		switch ((filter->jt << 8) | filter->jf) {
+		switch ((instr->jt << 8) | instr->jf) {
 		case (JUMP_JT << 8) | JUMP_JF:
-			if (labels->labels[filter->k].location == 0xffffffff) {
-				fprintf(stderr, "Unresolved label: '%s'\n",
-					labels->labels[filter->k].label);
-				return 1;
+			if (instr->k >= labels->count) {
+				warn("nonexistent label id: %u", instr->k);
+				return -1;
 			}
-			filter->k =
-			    labels->labels[filter->k].location - (insn + 1);
-			filter->jt = 0;
-			filter->jf = 0;
+			if (labels->labels[instr->k].location == 0xffffffff) {
+				warn("unresolved label: '%s'",
+				     labels->labels[instr->k].label);
+				return -1;
+			}
+			instr->k =
+			    labels->labels[instr->k].location - (offset + 1);
+			instr->jt = 0;
+			instr->jf = 0;
 			continue;
 		case (LABEL_JT << 8) | LABEL_JF:
-			if (labels->labels[filter->k].location != 0xffffffff) {
-				fprintf(stderr, "Duplicate label use: '%s'\n",
-					labels->labels[filter->k].label);
-				return 1;
+			if (labels->labels[instr->k].location != 0xffffffff) {
+				warn("duplicate label: '%s'",
+				     labels->labels[instr->k].label);
+				return -1;
 			}
-			labels->labels[filter->k].location = insn;
-			filter->k = 0; /* Fall through. */
-			filter->jt = 0;
-			filter->jf = 0;
+			labels->labels[instr->k].location = offset;
+			instr->k = 0; /* Fall through. */
+			instr->jt = 0;
+			instr->jf = 0;
 			continue;
 		}
 	}