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