(root)/
strace-6.5/
src/
bpf_filter.c
       1  /*
       2   * Decoder of classic BPF programs.
       3   *
       4   * Copyright (c) 2015-2017 Dmitry V. Levin <ldv@strace.io>
       5   * Copyright (c) 2017-2022 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  	tprint_flags_begin();
      40  	printxval(extended ? ebpf_class : bpf_class, BPF_CLASS(code),
      41  		  "BPF_???");
      42  	switch (BPF_CLASS(code)) {
      43  	case BPF_ST:
      44  	case BPF_STX:
      45  		if (!extended) {
      46  			if (i) {
      47  				tprint_flags_or();
      48  				PRINT_VAL_X(i);
      49  				tprints_comment("BPF_???");
      50  			}
      51  			break;
      52  		}
      53  		ATTRIBUTE_FALLTHROUGH; /* extended == true */
      54  
      55  	case BPF_LD:
      56  	case BPF_LDX:
      57  		tprint_flags_or();
      58  		printxvals(BPF_SIZE(code), "BPF_???",
      59  			   bpf_size, extended ? ebpf_size : NULL, NULL);
      60  		tprint_flags_or();
      61  		printxval(mode, BPF_MODE(code), "BPF_???");
      62  		break;
      63  
      64  	case BPF_MISC: /* BPF_ALU64 in eBPF */
      65  		if (!extended) {
      66  			tprint_flags_or();
      67  			printxval(bpf_miscop, BPF_MISCOP(code), "BPF_???");
      68  			i &= ~BPF_MISCOP(code);
      69  			if (i) {
      70  				tprint_flags_or();
      71  				PRINT_VAL_X(i);
      72  				tprints_comment("BPF_???");
      73  			}
      74  			break;
      75  		}
      76  		ATTRIBUTE_FALLTHROUGH; /* extended == true */
      77  
      78  	case BPF_ALU:
      79  		tprint_flags_or();
      80  		printxval(bpf_src, BPF_SRC(code), "BPF_???");
      81  		tprint_flags_or();
      82  		printxvals(BPF_OP(code), "BPF_???",
      83  			   bpf_op_alu,
      84  			   extended ? ebpf_op_alu : NULL, NULL);
      85  		break;
      86  
      87  	case BPF_JMP:
      88  		tprint_flags_or();
      89  		printxval(bpf_src, BPF_SRC(code), "BPF_???");
      90  		tprint_flags_or();
      91  		printxvals(BPF_OP(code), "BPF_???",
      92  			   bpf_op_jmp, extended ? ebpf_op_jmp : NULL, NULL);
      93  		break;
      94  
      95  	case BPF_RET: /* Reserved in eBPF */
      96  		if (!extended) {
      97  			tprint_flags_or();
      98  			printxval(bpf_rval, BPF_RVAL(code), "BPF_???");
      99  			i &= ~BPF_RVAL(code);
     100  		}
     101  
     102  		if (i) {
     103  			tprint_flags_or();
     104  			PRINT_VAL_X(i);
     105  			tprints_comment("BPF_???");
     106  		}
     107  
     108  		break;
     109  	}
     110  	tprint_flags_end();
     111  }
     112  
     113  static void
     114  print_bpf_filter_stmt(const struct bpf_filter_block *const filter,
     115  		      const print_bpf_filter_fn print_k)
     116  {
     117  	tprints_arg_begin("BPF_STMT");
     118  
     119  	print_bpf_filter_code(filter->code, false);
     120  	tprint_arg_next();
     121  
     122  	if (!print_k || !print_k(filter))
     123  		PRINT_VAL_X(filter->k);
     124  
     125  	tprint_arg_end();
     126  }
     127  
     128  static void
     129  print_bpf_filter_jump(const struct bpf_filter_block *const filter)
     130  {
     131  	tprints_arg_begin("BPF_JUMP");
     132  
     133  	print_bpf_filter_code(filter->code, false);
     134  	tprint_arg_next();
     135  
     136  	PRINT_VAL_X(filter->k);
     137  	tprint_arg_next();
     138  
     139  	PRINT_VAL_X(filter->jt);
     140  	tprint_arg_next();
     141  
     142  	PRINT_VAL_X(filter->jf);
     143  
     144  	tprint_arg_end();
     145  }
     146  
     147  struct bpf_filter_block_data {
     148  	const print_bpf_filter_fn fn;
     149  	unsigned int count;
     150  };
     151  
     152  static bool
     153  print_bpf_filter_block(struct tcb *const tcp, void *const elem_buf,
     154  		       const size_t elem_size, void *const data)
     155  {
     156  	const struct bpf_filter_block *const filter = elem_buf;
     157  	struct bpf_filter_block_data *const fbd = data;
     158  
     159  	if (fbd->count++ >= BPF_MAXINSNS) {
     160  		tprint_more_data_follows();
     161  		return false;
     162  	}
     163  
     164  	if (filter->jt || filter->jf)
     165  		print_bpf_filter_jump(filter);
     166  	else
     167  		print_bpf_filter_stmt(filter, fbd->fn);
     168  
     169  	return true;
     170  }
     171  
     172  void
     173  print_bpf_fprog(struct tcb *const tcp, const kernel_ulong_t addr,
     174  		const unsigned short len, const print_bpf_filter_fn print_k)
     175  {
     176  	if (abbrev(tcp)) {
     177  		printaddr(addr);
     178  	} else {
     179  		struct bpf_filter_block_data fbd = { .fn = print_k };
     180  		struct bpf_filter_block filter;
     181  
     182  		print_array(tcp, addr, len, &filter, sizeof(filter),
     183  			    tfetch_mem, print_bpf_filter_block, &fbd);
     184  	}
     185  }
     186  
     187  void
     188  decode_bpf_fprog(struct tcb *const tcp, const kernel_ulong_t addr,
     189  		 const print_bpf_filter_fn print_k)
     190  {
     191  	struct bpf_fprog fprog;
     192  
     193  	if (fetch_bpf_fprog(tcp, addr, &fprog)) {
     194  		tprint_struct_begin();
     195  		PRINT_FIELD_U(fprog, len);
     196  		tprint_struct_next();
     197  		PRINT_FIELD_OBJ_TCB_VAL(fprog, filter, tcp,
     198  					print_bpf_fprog, fprog.len, print_k);
     199  		tprint_struct_end();
     200  	}
     201  }