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