| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "sandbox/linux/bpf_dsl/dump_bpf.h" |
| |
| #include <inttypes.h> |
| #include <stdio.h> |
| |
| #include <string> |
| |
| #include "base/strings/stringprintf.h" |
| #include "sandbox/linux/bpf_dsl/codegen.h" |
| #include "sandbox/linux/bpf_dsl/seccomp_macros.h" |
| #include "sandbox/linux/bpf_dsl/trap_registry.h" |
| #include "sandbox/linux/system_headers/linux_filter.h" |
| #include "sandbox/linux/system_headers/linux_seccomp.h" |
| |
| namespace sandbox { |
| namespace bpf_dsl { |
| |
| namespace { |
| |
| const char* AluOpToken(uint32_t code) { |
| switch (BPF_OP(code)) { |
| case BPF_ADD: |
| return "+"; |
| case BPF_SUB: |
| return "-"; |
| case BPF_MUL: |
| return "*"; |
| case BPF_DIV: |
| return "/"; |
| case BPF_MOD: |
| return "%"; |
| case BPF_OR: |
| return "|"; |
| case BPF_XOR: |
| return "^"; |
| case BPF_AND: |
| return "&"; |
| case BPF_LSH: |
| return "<<"; |
| case BPF_RSH: |
| return ">>"; |
| default: |
| return "???"; |
| } |
| } |
| |
| const char* JmpOpToken(uint32_t code) { |
| switch (BPF_OP(code)) { |
| case BPF_JSET: |
| return "&"; |
| case BPF_JEQ: |
| return "=="; |
| case BPF_JGE: |
| return ">="; |
| default: |
| return "???"; |
| } |
| } |
| |
| const char* DataOffsetName(size_t off) { |
| switch (off) { |
| case SECCOMP_NR_IDX: |
| return "System call number"; |
| case SECCOMP_ARCH_IDX: |
| return "Architecture"; |
| case SECCOMP_IP_LSB_IDX: |
| return "Instruction pointer (LSB)"; |
| case SECCOMP_IP_MSB_IDX: |
| return "Instruction pointer (MSB)"; |
| default: |
| return "???"; |
| } |
| } |
| |
| void AppendInstruction(std::string* dst, size_t pc, const sock_filter& insn) { |
| base::StringAppendF(dst, "%3zu) ", pc); |
| switch (BPF_CLASS(insn.code)) { |
| case BPF_LD: |
| if (insn.code == BPF_LD + BPF_W + BPF_ABS) { |
| base::StringAppendF(dst, "LOAD %" PRIu32 " // ", insn.k); |
| size_t maybe_argno = |
| (insn.k - offsetof(struct arch_seccomp_data, args)) / |
| sizeof(uint64_t); |
| if (maybe_argno < 6 && insn.k == SECCOMP_ARG_LSB_IDX(maybe_argno)) { |
| base::StringAppendF(dst, "Argument %zu (LSB)\n", maybe_argno); |
| } else if (maybe_argno < 6 && |
| insn.k == SECCOMP_ARG_MSB_IDX(maybe_argno)) { |
| base::StringAppendF(dst, "Argument %zu (MSB)\n", maybe_argno); |
| } else { |
| base::StringAppendF(dst, "%s\n", DataOffsetName(insn.k)); |
| } |
| } else { |
| base::StringAppendF(dst, "Load ???\n"); |
| } |
| break; |
| case BPF_JMP: |
| if (BPF_OP(insn.code) == BPF_JA) { |
| base::StringAppendF(dst, "JMP %zu\n", pc + insn.k + 1); |
| } else { |
| base::StringAppendF( |
| dst, "if A %s 0x%" PRIx32 "; then JMP %zu else JMP %zu\n", |
| JmpOpToken(insn.code), insn.k, pc + insn.jt + 1, pc + insn.jf + 1); |
| } |
| break; |
| case BPF_RET: |
| base::StringAppendF(dst, "RET 0x%" PRIx32 " // ", insn.k); |
| if ((insn.k & SECCOMP_RET_ACTION) == SECCOMP_RET_TRAP) { |
| base::StringAppendF(dst, "Trap #%" PRIu32 "\n", |
| insn.k & SECCOMP_RET_DATA); |
| } else if ((insn.k & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) { |
| base::StringAppendF(dst, "errno = %" PRIu32 "\n", |
| insn.k & SECCOMP_RET_DATA); |
| } else if ((insn.k & SECCOMP_RET_ACTION) == SECCOMP_RET_TRACE) { |
| base::StringAppendF(dst, "Trace #%" PRIu32 "\n", |
| insn.k & SECCOMP_RET_DATA); |
| } else if (insn.k == SECCOMP_RET_ALLOW) { |
| base::StringAppendF(dst, "Allowed\n"); |
| } else if (insn.k == SECCOMP_RET_KILL) { |
| base::StringAppendF(dst, "Kill\n"); |
| } else { |
| base::StringAppendF(dst, "???\n"); |
| } |
| break; |
| case BPF_ALU: |
| if (BPF_OP(insn.code) == BPF_NEG) { |
| base::StringAppendF(dst, "A := -A\n"); |
| } else { |
| base::StringAppendF(dst, "A := A %s 0x%" PRIx32 "\n", |
| AluOpToken(insn.code), insn.k); |
| } |
| break; |
| default: |
| base::StringAppendF(dst, "???\n"); |
| break; |
| } |
| } |
| |
| } // namespace |
| |
| void DumpBPF::PrintProgram(const CodeGen::Program& program) { |
| fputs(StringPrintProgram(program).c_str(), stderr); |
| } |
| |
| std::string DumpBPF::StringPrintProgram(const CodeGen::Program& program) { |
| std::string res; |
| for (size_t i = 0; i < program.size(); i++) { |
| AppendInstruction(&res, i + 1, program[i]); |
| } |
| return res; |
| } |
| |
| } // namespace bpf_dsl |
| } // namespace sandbox |