parse_seccomp_policy: Add a --dump flag
This change adds a --dump flag to parse_seccomp_policy, to allow people
to inspect the policy with libseccomp's scmp_bpf_disasm. It also moves
the dump_bpf_prog / dump_bpf_filter functions to parse_seccomp_policy.cc
since they were only used in that one file, and formats the file in C++.
Bug: None
Test: make tests
Test: make parse_seccomp_policy
Test: ./parse_seccomp_policy --dump test/seccomp.policy | \
./libseccomp/tools/scmp_bpf_disasm
Change-Id: I96d54cae68b5b102f8962e39ff00b35407f45758
diff --git a/parse_seccomp_policy.cc b/parse_seccomp_policy.cc
index 76e8ab8..18cff96 100644
--- a/parse_seccomp_policy.cc
+++ b/parse_seccomp_policy.cc
@@ -3,34 +3,98 @@
* found in the LICENSE file.
*/
+#include <getopt.h>
#include <stdio.h>
+#include <string>
+
#include "bpf.h"
#include "syscall_filter.h"
#include "util.h"
-/* TODO(jorgelo): Use libseccomp disassembler here. */
-int main(int argc, char **argv) {
- init_logging(LOG_TO_FD, STDERR_FILENO, LOG_INFO);
+namespace {
- if (argc < 2) {
- fprintf(stderr, "Usage: %s <policy file>\n", argv[0]);
- return 1;
- }
+void DumpBpfProg(struct sock_fprog* fprog) {
+ struct sock_filter* filter = fprog->filter;
+ unsigned short len = fprog->len;
- FILE *f = fopen(argv[1], "re");
- if (!f) {
- pdie("fopen(%s) failed", argv[1]);
- }
+ printf("len == %d\n", len);
+ printf("filter:\n");
+ for (size_t i = 0; i < len; i++) {
+ printf("%zu: \t{ code=%#x, jt=%u, jf=%u, k=%#x \t}\n", i, filter[i].code,
+ filter[i].jt, filter[i].jf, filter[i].k);
+ }
+}
- struct sock_fprog fp;
- int res = compile_filter(argv[1], f, &fp, 0, 0);
- if (res != 0) {
- die("compile_filter failed");
- }
- dump_bpf_prog(&fp);
+void Usage(const char* progn, int status) {
+ // clang-format off
+ fprintf(status ? stderr : stdout,
+ "Usage: %s [--dump[=<output.bpf>]] <policy file>\n"
+ " --dump[=<output>]: Dump the BPF program into stdout (or <output>,\n"
+ " -d[<output>]: if provided). Useful if you want to inspect it\n"
+ " with libseccomp's scmp_bpf_disasm.\n",
+ progn);
+ // clang-format on
+ exit(status);
+}
- free(fp.filter);
- fclose(f);
- return 0;
+} // namespace
+
+int main(int argc, char** argv) {
+ init_logging(LOG_TO_FD, STDERR_FILENO, LOG_INFO);
+
+ const char* optstring = "d:h";
+ const struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"dump", optional_argument, 0, 'd'},
+ {0, 0, 0, 0},
+ };
+
+ bool dump = false;
+ std::string dump_path;
+ int opt;
+ while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) {
+ switch (opt) {
+ case 'h':
+ Usage(argv[0], 0);
+ return 0;
+ case 'd':
+ dump = true;
+ if (optarg)
+ dump_path = optarg;
+ break;
+ }
+ }
+
+ // There should be at least one additional unparsed argument: the
+ // policy script.
+ if (argc == optind)
+ Usage(argv[0], 1);
+
+ FILE* f = fopen(argv[optind], "re");
+ if (!f)
+ pdie("fopen(%s) failed", argv[1]);
+
+ struct sock_fprog fp;
+ int res = compile_filter(argv[1], f, &fp, 0, 0);
+ fclose(f);
+ if (res != 0)
+ die("compile_filter failed");
+
+ if (dump) {
+ FILE* out = stdout;
+ if (!dump_path.empty()) {
+ out = fopen(dump_path.c_str(), "we");
+ if (!out)
+ pdie("fopen(%s) failed", dump_path.c_str());
+ }
+ if (fwrite(fp.filter, sizeof(struct sock_filter), fp.len, out) != fp.len)
+ pdie("fwrite(%s) failed", dump_path.c_str());
+ fclose(out);
+ } else {
+ DumpBpfProg(&fp);
+ }
+
+ free(fp.filter);
+ return 0;
}