From f16d6d177fdbf41f6d4389436dbbe5d2b84cd519 Mon Sep 17 00:00:00 2001 From: Jorge Lucangeli Obes Date: Thu, 29 Sep 2016 20:25:27 -0400 Subject: Fix BPF instruction count bug. We were accidentally capping the total number of BPF instructions at 256 when doing label fixup. Also add a simple binary to print a compiled policy. Bug: 31848734 Test: Policy attached to the bug works. Change-Id: I9df058e2f4888289db0219d65ca97851fac515d0 --- Makefile | 17 ++++++++++++----- bpf.c | 38 +++++++++++++++++++++++++------------- bpf.h | 2 +- parse_seccomp_policy.cc | 44 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 19 deletions(-) create mode 100644 parse_seccomp_policy.cc diff --git a/Makefile b/Makefile index 4cbf0b6..42d9a05 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,8 @@ endif all: CC_BINARY(minijail0) CC_LIBRARY(libminijail.so) \ CC_LIBRARY(libminijailpreload.so) +parse_seccomp_policy: CXX_BINARY(parse_seccomp_policy) + # TODO(jorgelo): convert to TEST(). tests: CC_BINARY(libminijail_unittest) CC_BINARY(syscall_filter_unittest) @@ -30,25 +32,30 @@ clean: CLEAN(minijail0) CC_LIBRARY(libminijail.so): LDLIBS += -lcap CC_LIBRARY(libminijail.so): libminijail.o syscall_filter.o signal_handler.o \ - bpf.o util.o syscall_wrapper.o libconstants.gen.o libsyscalls.gen.o + bpf.o util.o syscall_wrapper.o libconstants.gen.o \ + libsyscalls.gen.o clean: CLEAN(libminijail.so) CC_BINARY(libminijail_unittest): LDLIBS += -lcap CC_BINARY(libminijail_unittest): libminijail_unittest.o libminijail.o \ - syscall_filter.o signal_handler.o bpf.o util.o syscall_wrapper.o \ - libconstants.gen.o libsyscalls.gen.o + syscall_filter.o signal_handler.o bpf.o util.o \ + syscall_wrapper.o libconstants.gen.o libsyscalls.gen.o clean: CLEAN(libminijail_unittest) CC_LIBRARY(libminijailpreload.so): LDLIBS += -lcap -ldl CC_LIBRARY(libminijailpreload.so): libminijailpreload.o libminijail.o \ - libconstants.gen.o libsyscalls.gen.o syscall_filter.o signal_handler.o \ - bpf.o util.o syscall_wrapper.o + libconstants.gen.o libsyscalls.gen.o syscall_filter.o \ + signal_handler.o bpf.o util.o syscall_wrapper.o clean: CLEAN(libminijailpreload.so) CC_BINARY(syscall_filter_unittest): syscall_filter_unittest.o syscall_filter.o \ bpf.o util.o libconstants.gen.o libsyscalls.gen.o clean: CLEAN(syscall_filter_unittest) +CXX_BINARY(parse_seccomp_policy): parse_seccomp_policy.o syscall_filter.o \ + bpf.o util.o libconstants.gen.o libsyscalls.gen.o +clean: CLEAN(parse_policy) + libsyscalls.gen.o: CPPFLAGS += -I$(SRC) libsyscalls.gen.o.depends: libsyscalls.gen.c diff --git a/bpf.c b/bpf.c index 20f2ed0..f56bc11 100644 --- a/bpf.c +++ b/bpf.c @@ -172,8 +172,8 @@ void dump_bpf_filter(struct sock_filter *filter, unsigned short len) printf("len == %d\n", len); printf("filter:\n"); for (i = 0; i < len; i++) { - printf("%d: \t{ code=%#x, jt=%u, jf=%u, k=%#x \t}\n", - i, filter[i].code, filter[i].jt, filter[i].jf, filter[i].k); + printf("%d: \t{ code=%#x, jt=%u, jf=%u, k=%#x \t}\n", i, + filter[i].code, filter[i].jt, filter[i].jf, filter[i].k); } } @@ -184,41 +184,48 @@ void dump_bpf_prog(struct sock_fprog *fprog) dump_bpf_filter(filter, len); } -int bpf_resolve_jumps(struct bpf_labels *labels, - struct sock_filter *filter, size_t count) +int bpf_resolve_jumps(struct bpf_labels *labels, struct sock_filter *filter, + size_t len) { + size_t insn; struct sock_filter *begin = filter; - __u8 insn = count - 1; - if (count < 1) + /* This needs at least two instructions: one jump and one label. */ + if (len < 2) return -1; + + 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)) + if (filter->code != (BPF_JMP + BPF_JA)) continue; - switch ((filter->jt<<8)|filter->jf) { - case (JUMP_JT<<8)|JUMP_JF: + switch ((filter->jt << 8) | filter->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; } - filter->k = labels->labels[filter->k].location - - (insn + 1); + filter->k = + labels->labels[filter->k].location - (insn + 1); filter->jt = 0; filter->jf = 0; continue; - case (LABEL_JT<<8)|LABEL_JF: + 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; } labels->labels[filter->k].location = insn; - filter->k = 0; /* fall through */ + filter->k = 0; /* Fall through. */ filter->jt = 0; filter->jf = 0; continue; @@ -246,6 +253,11 @@ int bpf_label_id(struct bpf_labels *labels, const char *label) if (!strcmp(label, begin->label)) return id; } + + /* The label wasn't found. Insert it only if there's space. */ + if (labels->count == BPF_LABELS_MAX) { + return -1; + } begin->label = strndup(label, MAX_BPF_LABEL_LEN); if (!begin->label) { return -1; diff --git a/bpf.h b/bpf.h index e4897e2..60f4d7b 100644 --- a/bpf.h +++ b/bpf.h @@ -114,7 +114,7 @@ struct seccomp_data { #define MAX_BPF_LABEL_LEN 32 -#define BPF_LABELS_MAX 256 +#define BPF_LABELS_MAX 512 /* Each syscall could have an argument block. */ struct bpf_labels { int count; struct __bpf_label { diff --git a/parse_seccomp_policy.cc b/parse_seccomp_policy.cc new file mode 100644 index 0000000..c50b79e --- /dev/null +++ b/parse_seccomp_policy.cc @@ -0,0 +1,44 @@ +// parse_seccomp_policy.cc +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "bpf.h" +#include "syscall_filter.h" +#include "util.h" + +/* TODO(jorgelo): Use libseccomp disassembler here. */ +int main(int argc, char **argv) { + if (argc < 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + FILE *f = fopen(argv[1], "r"); + if (!f) { + pdie("fopen(%s) failed", argv[1]); + } + + struct sock_fprog fp; + int res = compile_filter(f, &fp, 0); + if (res != 0) { + die("compile_filter failed"); + } + dump_bpf_prog(&fp); + + free(fp.filter); + fclose(f); + return 0; +} -- cgit v1.2.3