Home | History | Annotate | Download | only in strace
      1 /*
      2  * Decoder of classic BPF programs.
      3  *
      4  * Copyright (c) 2015-2017 Dmitry V. Levin <ldv (at) 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 print_bpf_filter_code(const uint16_t code)
     47 {
     48 	uint16_t i = code & ~BPF_CLASS(code);
     49 
     50 	printxval(bpf_class, BPF_CLASS(code), "BPF_???");
     51 	switch (BPF_CLASS(code)) {
     52 		case BPF_LD:
     53 		case BPF_LDX:
     54 			tprints("|");
     55 			printxval(bpf_size, BPF_SIZE(code), "BPF_???");
     56 			tprints("|");
     57 			printxval(bpf_mode, BPF_MODE(code), "BPF_???");
     58 			break;
     59 		case BPF_ST:
     60 		case BPF_STX:
     61 			if (i) {
     62 				tprintf("|%#x", i);
     63 				tprints_comment("BPF_???");
     64 			}
     65 			break;
     66 		case BPF_ALU:
     67 			tprints("|");
     68 			printxval(bpf_src, BPF_SRC(code), "BPF_???");
     69 			tprints("|");
     70 			printxval(bpf_op_alu, BPF_OP(code), "BPF_???");
     71 			break;
     72 		case BPF_JMP:
     73 			tprints("|");
     74 			printxval(bpf_src, BPF_SRC(code), "BPF_???");
     75 			tprints("|");
     76 			printxval(bpf_op_jmp, BPF_OP(code), "BPF_???");
     77 			break;
     78 		case BPF_RET:
     79 			tprints("|");
     80 			printxval(bpf_rval, BPF_RVAL(code), "BPF_???");
     81 			i &= ~BPF_RVAL(code);
     82 			if (i) {
     83 				tprintf("|%#x", i);
     84 				tprints_comment("BPF_???");
     85 			}
     86 			break;
     87 		case BPF_MISC:
     88 			tprints("|");
     89 			printxval(bpf_miscop, BPF_MISCOP(code), "BPF_???");
     90 			i &= ~BPF_MISCOP(code);
     91 			if (i) {
     92 				tprintf("|%#x", i);
     93 				tprints_comment("BPF_???");
     94 			}
     95 			break;
     96 	}
     97 }
     98 
     99 static void
    100 print_bpf_filter_stmt(const struct bpf_filter_block *const filter,
    101 		      const print_bpf_filter_fn print_k)
    102 {
    103 	tprints("BPF_STMT(");
    104 	print_bpf_filter_code(filter->code);
    105 	tprints(", ");
    106 	if (!print_k || !print_k(filter))
    107 		tprintf("%#x", filter->k);
    108 	tprints(")");
    109 }
    110 
    111 static void
    112 print_bpf_filter_jump(const struct bpf_filter_block *const filter)
    113 {
    114 	tprints("BPF_JUMP(");
    115 	print_bpf_filter_code(filter->code);
    116 	tprintf(", %#x, %#x, %#x)", filter->k, filter->jt, filter->jf);
    117 }
    118 
    119 struct bpf_filter_block_data {
    120 	const print_bpf_filter_fn fn;
    121 	unsigned int count;
    122 };
    123 
    124 static bool
    125 print_bpf_filter_block(struct tcb *const tcp, void *const elem_buf,
    126 		       const size_t elem_size, void *const data)
    127 {
    128 	const struct bpf_filter_block *const filter = elem_buf;
    129 	struct bpf_filter_block_data *const fbd = data;
    130 
    131 	if (fbd->count++ >= BPF_MAXINSNS) {
    132 		tprints("...");
    133 		return false;
    134 	}
    135 
    136 	if (filter->jt || filter->jf)
    137 		print_bpf_filter_jump(filter);
    138 	else
    139 		print_bpf_filter_stmt(filter, fbd->fn);
    140 
    141 	return true;
    142 }
    143 
    144 void
    145 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 	if (abbrev(tcp)) {
    149 		printaddr(addr);
    150 	} else {
    151 		struct bpf_filter_block_data fbd = { .fn = print_k };
    152 		struct bpf_filter_block filter;
    153 
    154 		print_array(tcp, addr, len, &filter, sizeof(filter),
    155 			    umoven_or_printaddr, print_bpf_filter_block, &fbd);
    156 	}
    157 }
    158 
    159 void
    160 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 	if (fetch_bpf_fprog(tcp, addr, &fprog)) {
    166 		tprintf("{len=%hu, filter=", fprog.len);
    167 		print_bpf_fprog(tcp, fprog.filter, fprog.len, print_k);
    168 		tprints("}");
    169 	}
    170 }
    171