• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
AluOpToken(uint32_t code)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 
JmpOpToken(uint32_t code)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 
DataOffsetName(size_t off)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 
AppendInstruction(std::string * dst,size_t pc,const sock_filter & insn)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 
PrintProgram(const CodeGen::Program & program)146 void DumpBPF::PrintProgram(const CodeGen::Program& program) {
147   fputs(StringPrintProgram(program).c_str(), stderr);
148 }
149 
StringPrintProgram(const CodeGen::Program & program)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