]> granicus.if.org Git - strace/blob - bpf_filter.c
Update debian/watch
[strace] / bpf_filter.c
1 /*
2  * Decoder of classic BPF programs.
3  *
4  * Copyright (c) 2015-2017 Dmitry V. Levin <ldv@altlinux.org>
5  * Copyright (c) 2017-2018 The strace developers.
6  * All rights reserved.
7  *
8  * SPDX-License-Identifier: LGPL-2.1-or-later
9  */
10
11 #include "defs.h"
12
13 #include "bpf_filter.h"
14 #include "bpf_fprog.h"
15
16 #include <linux/filter.h>
17
18 #include "xlat/bpf_class.h"
19 #include "xlat/bpf_miscop.h"
20 #include "xlat/bpf_mode.h"
21 #include "xlat/bpf_op_alu.h"
22 #include "xlat/bpf_op_jmp.h"
23 #include "xlat/bpf_rval.h"
24 #include "xlat/bpf_size.h"
25 #include "xlat/bpf_src.h"
26
27 #include "xlat/ebpf_class.h"
28 #include "xlat/ebpf_mode.h"
29 #include "xlat/ebpf_op_alu.h"
30 #include "xlat/ebpf_op_jmp.h"
31 #include "xlat/ebpf_size.h"
32
33 void
34 print_bpf_filter_code(const uint16_t code, bool extended)
35 {
36         const struct xlat *mode = extended ? ebpf_mode : bpf_mode;
37         uint16_t i = code & ~BPF_CLASS(code);
38
39         printxval(extended ? ebpf_class : bpf_class, BPF_CLASS(code),
40                   "BPF_???");
41         switch (BPF_CLASS(code)) {
42         case BPF_ST:
43         case BPF_STX:
44                 if (!extended) {
45                         if (i) {
46                                 tprintf("|%#x", i);
47                                 tprints_comment("BPF_???");
48                         }
49                         break;
50                 }
51                 ATTRIBUTE_FALLTHROUGH; /* extended == true */
52
53         case BPF_LD:
54         case BPF_LDX:
55                 tprints("|");
56                 printxvals(BPF_SIZE(code), "BPF_???",
57                            bpf_size, extended ? ebpf_size : NULL, NULL);
58                 tprints("|");
59                 printxval(mode, BPF_MODE(code), "BPF_???");
60                 break;
61
62         case BPF_MISC: /* BPF_ALU64 in eBPF */
63                 if (!extended) {
64                         tprints("|");
65                         printxval(bpf_miscop, BPF_MISCOP(code), "BPF_???");
66                         i &= ~BPF_MISCOP(code);
67                         if (i) {
68                                 tprintf("|%#x", i);
69                                 tprints_comment("BPF_???");
70                         }
71                         break;
72                 }
73                 ATTRIBUTE_FALLTHROUGH; /* extended == true */
74
75         case BPF_ALU:
76                 tprints("|");
77                 printxval(bpf_src, BPF_SRC(code), "BPF_???");
78                 tprints("|");
79                 printxvals(BPF_OP(code), "BPF_???",
80                            bpf_op_alu,
81                            extended ? ebpf_op_alu : NULL, NULL);
82                 break;
83
84         case BPF_JMP:
85                 tprints("|");
86                 printxval(bpf_src, BPF_SRC(code), "BPF_???");
87                 tprints("|");
88                 printxvals(BPF_OP(code), "BPF_???",
89                            bpf_op_jmp, extended ? ebpf_op_jmp : NULL, NULL);
90                 break;
91
92         case BPF_RET: /* Reserved in eBPF */
93                 if (!extended) {
94                         tprints("|");
95                         printxval(bpf_rval, BPF_RVAL(code), "BPF_???");
96                         i &= ~BPF_RVAL(code);
97                 }
98
99                 if (i) {
100                         tprintf("|%#x", i);
101                         tprints_comment("BPF_???");
102                 }
103
104                 break;
105         }
106 }
107
108 static void
109 print_bpf_filter_stmt(const struct bpf_filter_block *const filter,
110                       const print_bpf_filter_fn print_k)
111 {
112         tprints("BPF_STMT(");
113         print_bpf_filter_code(filter->code, false);
114         tprints(", ");
115         if (!print_k || !print_k(filter))
116                 tprintf("%#x", filter->k);
117         tprints(")");
118 }
119
120 static void
121 print_bpf_filter_jump(const struct bpf_filter_block *const filter)
122 {
123         tprints("BPF_JUMP(");
124         print_bpf_filter_code(filter->code, false);
125         tprintf(", %#x, %#x, %#x)", filter->k, filter->jt, filter->jf);
126 }
127
128 struct bpf_filter_block_data {
129         const print_bpf_filter_fn fn;
130         unsigned int count;
131 };
132
133 static bool
134 print_bpf_filter_block(struct tcb *const tcp, void *const elem_buf,
135                        const size_t elem_size, void *const data)
136 {
137         const struct bpf_filter_block *const filter = elem_buf;
138         struct bpf_filter_block_data *const fbd = data;
139
140         if (fbd->count++ >= BPF_MAXINSNS) {
141                 tprints("...");
142                 return false;
143         }
144
145         if (filter->jt || filter->jf)
146                 print_bpf_filter_jump(filter);
147         else
148                 print_bpf_filter_stmt(filter, fbd->fn);
149
150         return true;
151 }
152
153 void
154 print_bpf_fprog(struct tcb *const tcp, const kernel_ulong_t addr,
155                 const unsigned short len, const print_bpf_filter_fn print_k)
156 {
157         if (abbrev(tcp)) {
158                 printaddr(addr);
159         } else {
160                 struct bpf_filter_block_data fbd = { .fn = print_k };
161                 struct bpf_filter_block filter;
162
163                 print_array(tcp, addr, len, &filter, sizeof(filter),
164                             tfetch_mem, print_bpf_filter_block, &fbd);
165         }
166 }
167
168 void
169 decode_bpf_fprog(struct tcb *const tcp, const kernel_ulong_t addr,
170                  const print_bpf_filter_fn print_k)
171 {
172         struct bpf_fprog fprog;
173
174         if (fetch_bpf_fprog(tcp, addr, &fprog)) {
175                 tprintf("{len=%hu, filter=", fprog.len);
176                 print_bpf_fprog(tcp, fprog.filter, fprog.len, print_k);
177                 tprints("}");
178         }
179 }