Home | History | Annotate | Download | only in bpf_dsl
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "sandbox/linux/bpf_dsl/dump_bpf.h"
      6 
      7 #include <inttypes.h>
      8 #include <stddef.h>
      9 #include <stdint.h>
     10 #include <stdio.h>
     11 
     12 #include <string>
     13 
     14 #include "base/strings/stringprintf.h"
     15 #include "sandbox/linux/bpf_dsl/codegen.h"
     16 #include "sandbox/linux/bpf_dsl/seccomp_macros.h"
     17 #include "sandbox/linux/bpf_dsl/trap_registry.h"
     18 #include "sandbox/linux/system_headers/linux_filter.h"
     19 #include "sandbox/linux/system_headers/linux_seccomp.h"
     20 
     21 namespace sandbox {
     22 namespace bpf_dsl {
     23 
     24 namespace {
     25 
     26 const char* AluOpToken(uint32_t code) {
     27   switch (BPF_OP(code)) {
     28     case BPF_ADD:
     29       return "+";
     30     case BPF_SUB:
     31       return "-";
     32     case BPF_MUL:
     33       return "*";
     34     case BPF_DIV:
     35       return "/";
     36     case BPF_MOD:
     37       return "%";
     38     case BPF_OR:
     39       return "|";
     40     case BPF_XOR:
     41       return "^";
     42     case BPF_AND:
     43       return "&";
     44     case BPF_LSH:
     45       return "<<";
     46     case BPF_RSH:
     47       return ">>";
     48     default:
     49       return "???";
     50   }
     51 }
     52 
     53 const char* JmpOpToken(uint32_t code) {
     54   switch (BPF_OP(code)) {
     55     case BPF_JSET:
     56       return "&";
     57     case BPF_JEQ:
     58       return "==";
     59     case BPF_JGE:
     60       return ">=";
     61     default:
     62       return "???";
     63   }
     64 }
     65 
     66 const char* DataOffsetName(size_t off) {
     67   switch (off) {
     68     case SECCOMP_NR_IDX:
     69       return "System call number";
     70     case SECCOMP_ARCH_IDX:
     71       return "Architecture";
     72     case SECCOMP_IP_LSB_IDX:
     73       return "Instruction pointer (LSB)";
     74     case SECCOMP_IP_MSB_IDX:
     75       return "Instruction pointer (MSB)";
     76     default:
     77       return "???";
     78   }
     79 }
     80 
     81 void AppendInstruction(std::string* dst, size_t pc, const sock_filter& insn) {
     82   base::StringAppendF(dst, "%3zu) ", pc);
     83   switch (BPF_CLASS(insn.code)) {
     84     case BPF_LD:
     85       if (insn.code == BPF_LD + BPF_W + BPF_ABS) {
     86         base::StringAppendF(dst, "LOAD %" PRIu32 "  // ", insn.k);
     87         size_t maybe_argno =
     88             (insn.k - offsetof(struct arch_seccomp_data, args)) /
     89             sizeof(uint64_t);
     90         if (maybe_argno < 6 && insn.k == SECCOMP_ARG_LSB_IDX(maybe_argno)) {
     91           base::StringAppendF(dst, "Argument %zu (LSB)\n", maybe_argno);
     92         } else if (maybe_argno < 6 &&
     93                    insn.k == SECCOMP_ARG_MSB_IDX(maybe_argno)) {
     94           base::StringAppendF(dst, "Argument %zu (MSB)\n", maybe_argno);
     95         } else {
     96           base::StringAppendF(dst, "%s\n", DataOffsetName(insn.k));
     97         }
     98       } else {
     99         base::StringAppendF(dst, "Load ???\n");
    100       }
    101       break;
    102     case BPF_JMP:
    103       if (BPF_OP(insn.code) == BPF_JA) {
    104         base::StringAppendF(dst, "JMP %zu\n", pc + insn.k + 1);
    105       } else {
    106         base::StringAppendF(
    107             dst, "if A %s 0x%" PRIx32 "; then JMP %zu else JMP %zu\n",
    108             JmpOpToken(insn.code), insn.k, pc + insn.jt + 1, pc + insn.jf + 1);
    109       }
    110       break;
    111     case BPF_RET:
    112       base::StringAppendF(dst, "RET 0x%" PRIx32 "  // ", insn.k);
    113       if ((insn.k & SECCOMP_RET_ACTION) == SECCOMP_RET_TRAP) {
    114         base::StringAppendF(dst, "Trap #%" PRIu32 "\n",
    115                             insn.k & SECCOMP_RET_DATA);
    116       } else if ((insn.k & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) {
    117         base::StringAppendF(dst, "errno = %" PRIu32 "\n",
    118                             insn.k & SECCOMP_RET_DATA);
    119       } else if ((insn.k & SECCOMP_RET_ACTION) == SECCOMP_RET_TRACE) {
    120         base::StringAppendF(dst, "Trace #%" PRIu32 "\n",
    121                             insn.k & SECCOMP_RET_DATA);
    122       } else if (insn.k == SECCOMP_RET_ALLOW) {
    123         base::StringAppendF(dst, "Allowed\n");
    124       } else if (insn.k == SECCOMP_RET_KILL) {
    125         base::StringAppendF(dst, "Kill\n");
    126       } else {
    127         base::StringAppendF(dst, "???\n");
    128       }
    129       break;
    130     case BPF_ALU:
    131       if (BPF_OP(insn.code) == BPF_NEG) {
    132         base::StringAppendF(dst, "A := -A\n");
    133       } else {
    134         base::StringAppendF(dst, "A := A %s 0x%" PRIx32 "\n",
    135                             AluOpToken(insn.code), insn.k);
    136       }
    137       break;
    138     default:
    139       base::StringAppendF(dst, "???\n");
    140       break;
    141   }
    142 }
    143 
    144 }  // namespace
    145 
    146 void DumpBPF::PrintProgram(const CodeGen::Program& program) {
    147   fputs(StringPrintProgram(program).c_str(), stderr);
    148 }
    149 
    150 std::string DumpBPF::StringPrintProgram(const CodeGen::Program& program) {
    151   std::string res;
    152   for (size_t i = 0; i < program.size(); i++) {
    153     AppendInstruction(&res, i + 1, program[i]);
    154   }
    155   return res;
    156 }
    157 
    158 }  // namespace bpf_dsl
    159 }  // namespace sandbox
    160