Branch data Line data Source code
1 : : /*
2 : : * Decoder of classic BPF programs.
3 : : *
4 : : * Copyright (c) 2015-2017 Dmitry V. Levin <ldv@altlinux.org>
5 : : * All rights reserved.
6 : : *
7 : : * Redistribution and use in source and binary forms, with or without
8 : : * modification, are permitted provided that the following conditions
9 : : * are met:
10 : : * 1. Redistributions of source code must retain the above copyright
11 : : * notice, this list of conditions and the following disclaimer.
12 : : * 2. Redistributions in binary form must reproduce the above copyright
13 : : * notice, this list of conditions and the following disclaimer in the
14 : : * documentation and/or other materials provided with the distribution.
15 : : * 3. The name of the author may not be used to endorse or promote products
16 : : * derived from this software without specific prior written permission.
17 : : *
18 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 : : * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 : : */
29 : :
30 : : #include "defs.h"
31 : :
32 : : #include "bpf_filter.h"
33 : : #include "bpf_fprog.h"
34 : :
35 : : #include <linux/filter.h>
36 : : #include "xlat/bpf_class.h"
37 : : #include "xlat/bpf_miscop.h"
38 : : #include "xlat/bpf_mode.h"
39 : : #include "xlat/bpf_op_alu.h"
40 : : #include "xlat/bpf_op_jmp.h"
41 : : #include "xlat/bpf_rval.h"
42 : : #include "xlat/bpf_size.h"
43 : : #include "xlat/bpf_src.h"
44 : :
45 : : static void
46 : 72 : print_bpf_filter_code(const uint16_t code)
47 : : {
48 : 72 : uint16_t i = code & ~BPF_CLASS(code);
49 : :
50 : 72 : printxval(bpf_class, BPF_CLASS(code), "BPF_???");
51 [ + - - + : 72 : switch (BPF_CLASS(code)) {
+ - - ]
52 : : case BPF_LD:
53 : : case BPF_LDX:
54 : 28 : tprints("|");
55 : 28 : printxval(bpf_size, BPF_SIZE(code), "BPF_???");
56 : 28 : tprints("|");
57 : 28 : printxval(bpf_mode, BPF_MODE(code), "BPF_???");
58 : : break;
59 : : case BPF_ST:
60 : : case BPF_STX:
61 [ # # ]: 0 : if (i) {
62 : 0 : tprintf("|%#x", i);
63 : 0 : tprints_comment("BPF_???");
64 : : }
65 : : break;
66 : : case BPF_ALU:
67 : 0 : tprints("|");
68 : 0 : printxval(bpf_src, BPF_SRC(code), "BPF_???");
69 : 0 : tprints("|");
70 : 0 : printxval(bpf_op_alu, BPF_OP(code), "BPF_???");
71 : : break;
72 : : case BPF_JMP:
73 : 22 : tprints("|");
74 : 22 : printxval(bpf_src, BPF_SRC(code), "BPF_???");
75 : 22 : tprints("|");
76 : 22 : printxval(bpf_op_jmp, BPF_OP(code), "BPF_???");
77 : : break;
78 : : case BPF_RET:
79 : 22 : tprints("|");
80 : 22 : printxval(bpf_rval, BPF_RVAL(code), "BPF_???");
81 : 22 : i &= ~BPF_RVAL(code);
82 [ - + ]: 22 : if (i) {
83 : 0 : tprintf("|%#x", i);
84 : 0 : tprints_comment("BPF_???");
85 : : }
86 : : break;
87 : : case BPF_MISC:
88 : 0 : tprints("|");
89 : 0 : printxval(bpf_miscop, BPF_MISCOP(code), "BPF_???");
90 : 0 : i &= ~BPF_MISCOP(code);
91 [ # # ]: 0 : if (i) {
92 : 0 : tprintf("|%#x", i);
93 : 0 : tprints_comment("BPF_???");
94 : : }
95 : : break;
96 : : }
97 : 72 : }
98 : :
99 : : static void
100 : 50 : print_bpf_filter_stmt(const struct bpf_filter_block *const filter,
101 : : const print_bpf_filter_fn print_k)
102 : : {
103 : 50 : tprints("BPF_STMT(");
104 : 50 : print_bpf_filter_code(filter->code);
105 : 50 : tprints(", ");
106 [ + - ][ + + ]: 50 : if (!print_k || !print_k(filter))
107 : 20 : tprintf("%#x", filter->k);
108 : 50 : tprints(")");
109 : 50 : }
110 : :
111 : : static void
112 : 22 : print_bpf_filter_jump(const struct bpf_filter_block *const filter)
113 : : {
114 : 22 : tprints("BPF_JUMP(");
115 : 22 : print_bpf_filter_code(filter->code);
116 : 22 : tprintf(", %#x, %#x, %#x)", filter->k, filter->jt, filter->jf);
117 : 22 : }
118 : :
119 : : struct bpf_filter_block_data {
120 : : const print_bpf_filter_fn fn;
121 : : unsigned int count;
122 : : };
123 : :
124 : : static bool
125 : 72 : print_bpf_filter_block(struct tcb *const tcp, void *const elem_buf,
126 : : const size_t elem_size, void *const data)
127 : : {
128 : 72 : const struct bpf_filter_block *const filter = elem_buf;
129 : 72 : struct bpf_filter_block_data *const fbd = data;
130 : :
131 [ - + ]: 72 : if (fbd->count++ >= BPF_MAXINSNS) {
132 : 0 : tprints("...");
133 : 0 : return false;
134 : : }
135 : :
136 [ + + ]: 72 : if (filter->jt || filter->jf)
137 : 22 : print_bpf_filter_jump(filter);
138 : : else
139 : 50 : print_bpf_filter_stmt(filter, fbd->fn);
140 : :
141 : : return true;
142 : : }
143 : :
144 : : void
145 : 16 : print_bpf_fprog(struct tcb *const tcp, const kernel_ulong_t addr,
146 : : const unsigned short len, const print_bpf_filter_fn print_k)
147 : : {
148 [ + + ]: 16 : if (abbrev(tcp)) {
149 : 2 : printaddr(addr);
150 : : } else {
151 : 14 : struct bpf_filter_block_data fbd = { .fn = print_k };
152 : : struct bpf_filter_block filter;
153 : :
154 : 14 : print_array(tcp, addr, len, &filter, sizeof(filter),
155 : : umoven_or_printaddr, print_bpf_filter_block, &fbd);
156 : : }
157 : 16 : }
158 : :
159 : : void
160 : 4 : decode_bpf_fprog(struct tcb *const tcp, const kernel_ulong_t addr,
161 : : const print_bpf_filter_fn print_k)
162 : : {
163 : : struct bpf_fprog fprog;
164 : :
165 [ + - ]: 4 : if (fetch_bpf_fprog(tcp, addr, &fprog)) {
166 : 4 : tprintf("{len=%hu, filter=", fprog.len);
167 : 4 : print_bpf_fprog(tcp, fprog.filter, fprog.len, print_k);
168 : 4 : tprints("}");
169 : : }
170 : 4 : }
|