Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

34
tools/net/Makefile Normal file
View file

@ -0,0 +1,34 @@
prefix = /usr
CC = gcc
LEX = flex
YACC = bison
%.yacc.c: %.y
$(YACC) -o $@ -d $<
%.lex.c: %.l
$(LEX) -o $@ $<
all : bpf_jit_disasm bpf_dbg bpf_asm
bpf_jit_disasm : CFLAGS = -Wall -O2 -DPACKAGE='bpf_jit_disasm'
bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl
bpf_jit_disasm : bpf_jit_disasm.o
bpf_dbg : CFLAGS = -Wall -O2
bpf_dbg : LDLIBS = -lreadline
bpf_dbg : bpf_dbg.o
bpf_asm : CFLAGS = -Wall -O2 -I.
bpf_asm : LDLIBS =
bpf_asm : bpf_asm.o bpf_exp.yacc.o bpf_exp.lex.o
bpf_exp.lex.o : bpf_exp.yacc.c
clean :
rm -rf *.o bpf_jit_disasm bpf_dbg bpf_asm bpf_exp.yacc.* bpf_exp.lex.*
install :
install bpf_jit_disasm $(prefix)/bin/bpf_jit_disasm
install bpf_dbg $(prefix)/bin/bpf_dbg
install bpf_asm $(prefix)/bin/bpf_asm

52
tools/net/bpf_asm.c Normal file
View file

@ -0,0 +1,52 @@
/*
* Minimal BPF assembler
*
* Instead of libpcap high-level filter expressions, it can be quite
* useful to define filters in low-level BPF assembler (that is kept
* close to Steven McCanne and Van Jacobson's original BPF paper).
* In particular for BPF JIT implementors, JIT security auditors, or
* just for defining BPF expressions that contain extensions which are
* not supported by compilers.
*
* How to get into it:
*
* 1) read Documentation/networking/filter.txt
* 2) Run `bpf_asm [-c] <filter-prog file>` to translate into binary
* blob that is loadable with xt_bpf, cls_bpf et al. Note: -c will
* pretty print a C-like construct.
*
* Copyright 2013 Daniel Borkmann <borkmann@redhat.com>
* Licensed under the GNU General Public License, version 2.0 (GPLv2)
*/
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
extern void bpf_asm_compile(FILE *fp, bool cstyle);
int main(int argc, char **argv)
{
FILE *fp = stdin;
bool cstyle = false;
int i;
for (i = 1; i < argc; i++) {
if (!strncmp("-c", argv[i], 2)) {
cstyle = true;
continue;
}
fp = fopen(argv[i], "r");
if (!fp) {
fp = stdin;
continue;
}
break;
}
bpf_asm_compile(fp, cstyle);
return 0;
}

1395
tools/net/bpf_dbg.c Normal file

File diff suppressed because it is too large Load diff

144
tools/net/bpf_exp.l Normal file
View file

@ -0,0 +1,144 @@
/*
* BPF asm code lexer
*
* This program is free software; you can distribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License,
* or (at your option) any later version.
*
* Syntax kept close to:
*
* Steven McCanne and Van Jacobson. 1993. The BSD packet filter: a new
* architecture for user-level packet capture. In Proceedings of the
* USENIX Winter 1993 Conference Proceedings on USENIX Winter 1993
* Conference Proceedings (USENIX'93). USENIX Association, Berkeley,
* CA, USA, 2-2.
*
* Copyright 2013 Daniel Borkmann <borkmann@redhat.com>
* Licensed under the GNU General Public License, version 2.0 (GPLv2)
*/
%{
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include "bpf_exp.yacc.h"
extern void yyerror(const char *str);
%}
%option align
%option ecs
%option nounput
%option noreject
%option noinput
%option noyywrap
%option 8bit
%option caseless
%option yylineno
%%
"ldb" { return OP_LDB; }
"ldh" { return OP_LDH; }
"ld" { return OP_LD; }
"ldi" { return OP_LDI; }
"ldx" { return OP_LDX; }
"ldxi" { return OP_LDXI; }
"ldxb" { return OP_LDXB; }
"st" { return OP_ST; }
"stx" { return OP_STX; }
"jmp" { return OP_JMP; }
"ja" { return OP_JMP; }
"jeq" { return OP_JEQ; }
"jneq" { return OP_JNEQ; }
"jne" { return OP_JNEQ; }
"jlt" { return OP_JLT; }
"jle" { return OP_JLE; }
"jgt" { return OP_JGT; }
"jge" { return OP_JGE; }
"jset" { return OP_JSET; }
"add" { return OP_ADD; }
"sub" { return OP_SUB; }
"mul" { return OP_MUL; }
"div" { return OP_DIV; }
"mod" { return OP_MOD; }
"neg" { return OP_NEG; }
"and" { return OP_AND; }
"xor" { return OP_XOR; }
"or" { return OP_OR; }
"lsh" { return OP_LSH; }
"rsh" { return OP_RSH; }
"ret" { return OP_RET; }
"tax" { return OP_TAX; }
"txa" { return OP_TXA; }
"#"?("len") { return K_PKT_LEN; }
"#"?("proto") { return K_PROTO; }
"#"?("type") { return K_TYPE; }
"#"?("poff") { return K_POFF; }
"#"?("ifidx") { return K_IFIDX; }
"#"?("nla") { return K_NLATTR; }
"#"?("nlan") { return K_NLATTR_NEST; }
"#"?("mark") { return K_MARK; }
"#"?("queue") { return K_QUEUE; }
"#"?("hatype") { return K_HATYPE; }
"#"?("rxhash") { return K_RXHASH; }
"#"?("cpu") { return K_CPU; }
"#"?("vlan_tci") { return K_VLANT; }
"#"?("vlan_pr") { return K_VLANP; }
"#"?("rand") { return K_RAND; }
":" { return ':'; }
"," { return ','; }
"#" { return '#'; }
"%" { return '%'; }
"[" { return '['; }
"]" { return ']'; }
"(" { return '('; }
")" { return ')'; }
"x" { return 'x'; }
"a" { return 'a'; }
"+" { return '+'; }
"M" { return 'M'; }
"*" { return '*'; }
"&" { return '&'; }
([0][x][a-fA-F0-9]+) {
yylval.number = strtoul(yytext, NULL, 16);
return number;
}
([0][b][0-1]+) {
yylval.number = strtol(yytext + 2, NULL, 2);
return number;
}
(([0])|([-+]?[1-9][0-9]*)) {
yylval.number = strtol(yytext, NULL, 10);
return number;
}
([0][0-9]+) {
yylval.number = strtol(yytext + 1, NULL, 8);
return number;
}
[a-zA-Z_][a-zA-Z0-9_]+ {
yylval.label = strdup(yytext);
return label;
}
"/*"([^\*]|\*[^/])*"*/" { /* NOP */ }
";"[^\n]* { /* NOP */ }
^#.* { /* NOP */ }
[ \t]+ { /* NOP */ }
[ \n]+ { /* NOP */ }
. {
printf("unknown character \'%s\'", yytext);
yyerror("lex unknown character");
}
%%

771
tools/net/bpf_exp.y Normal file
View file

@ -0,0 +1,771 @@
/*
* BPF asm code parser
*
* This program is free software; you can distribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License,
* or (at your option) any later version.
*
* Syntax kept close to:
*
* Steven McCanne and Van Jacobson. 1993. The BSD packet filter: a new
* architecture for user-level packet capture. In Proceedings of the
* USENIX Winter 1993 Conference Proceedings on USENIX Winter 1993
* Conference Proceedings (USENIX'93). USENIX Association, Berkeley,
* CA, USA, 2-2.
*
* Copyright 2013 Daniel Borkmann <borkmann@redhat.com>
* Licensed under the GNU General Public License, version 2.0 (GPLv2)
*/
%{
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <linux/filter.h>
#include "bpf_exp.yacc.h"
enum jmp_type { JTL, JFL, JKL };
extern FILE *yyin;
extern int yylex(void);
extern void yyerror(const char *str);
extern void bpf_asm_compile(FILE *fp, bool cstyle);
static void bpf_set_curr_instr(uint16_t op, uint8_t jt, uint8_t jf, uint32_t k);
static void bpf_set_curr_label(char *label);
static void bpf_set_jmp_label(char *label, enum jmp_type type);
%}
%union {
char *label;
uint32_t number;
}
%token OP_LDB OP_LDH OP_LD OP_LDX OP_ST OP_STX OP_JMP OP_JEQ OP_JGT OP_JGE
%token OP_JSET OP_ADD OP_SUB OP_MUL OP_DIV OP_AND OP_OR OP_XOR OP_LSH OP_RSH
%token OP_RET OP_TAX OP_TXA OP_LDXB OP_MOD OP_NEG OP_JNEQ OP_JLT OP_JLE OP_LDI
%token OP_LDXI
%token K_PKT_LEN K_PROTO K_TYPE K_NLATTR K_NLATTR_NEST K_MARK K_QUEUE K_HATYPE
%token K_RXHASH K_CPU K_IFIDX K_VLANT K_VLANP K_POFF K_RAND
%token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%'
%token number label
%type <label> label
%type <number> number
%%
prog
: line
| prog line
;
line
: instr
| labelled_instr
;
labelled_instr
: labelled instr
;
instr
: ldb
| ldh
| ld
| ldi
| ldx
| ldxi
| st
| stx
| jmp
| jeq
| jneq
| jlt
| jle
| jgt
| jge
| jset
| add
| sub
| mul
| div
| mod
| neg
| and
| or
| xor
| lsh
| rsh
| ret
| tax
| txa
;
labelled
: label ':' { bpf_set_curr_label($1); }
;
ldb
: OP_LDB '[' 'x' '+' number ']' {
bpf_set_curr_instr(BPF_LD | BPF_B | BPF_IND, 0, 0, $5); }
| OP_LDB '[' '%' 'x' '+' number ']' {
bpf_set_curr_instr(BPF_LD | BPF_B | BPF_IND, 0, 0, $6); }
| OP_LDB '[' number ']' {
bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, $3); }
| OP_LDB K_PROTO {
bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_PROTOCOL); }
| OP_LDB K_TYPE {
bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_PKTTYPE); }
| OP_LDB K_IFIDX {
bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_IFINDEX); }
| OP_LDB K_NLATTR {
bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_NLATTR); }
| OP_LDB K_NLATTR_NEST {
bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_NLATTR_NEST); }
| OP_LDB K_MARK {
bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_MARK); }
| OP_LDB K_QUEUE {
bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_QUEUE); }
| OP_LDB K_HATYPE {
bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_HATYPE); }
| OP_LDB K_RXHASH {
bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_RXHASH); }
| OP_LDB K_CPU {
bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_CPU); }
| OP_LDB K_VLANT {
bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_VLAN_TAG); }
| OP_LDB K_VLANP {
bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); }
| OP_LDB K_POFF {
bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
| OP_LDB K_RAND {
bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_RANDOM); }
;
ldh
: OP_LDH '[' 'x' '+' number ']' {
bpf_set_curr_instr(BPF_LD | BPF_H | BPF_IND, 0, 0, $5); }
| OP_LDH '[' '%' 'x' '+' number ']' {
bpf_set_curr_instr(BPF_LD | BPF_H | BPF_IND, 0, 0, $6); }
| OP_LDH '[' number ']' {
bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, $3); }
| OP_LDH K_PROTO {
bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_PROTOCOL); }
| OP_LDH K_TYPE {
bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_PKTTYPE); }
| OP_LDH K_IFIDX {
bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_IFINDEX); }
| OP_LDH K_NLATTR {
bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_NLATTR); }
| OP_LDH K_NLATTR_NEST {
bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_NLATTR_NEST); }
| OP_LDH K_MARK {
bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_MARK); }
| OP_LDH K_QUEUE {
bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_QUEUE); }
| OP_LDH K_HATYPE {
bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_HATYPE); }
| OP_LDH K_RXHASH {
bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_RXHASH); }
| OP_LDH K_CPU {
bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_CPU); }
| OP_LDH K_VLANT {
bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_VLAN_TAG); }
| OP_LDH K_VLANP {
bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); }
| OP_LDH K_POFF {
bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
| OP_LDH K_RAND {
bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_RANDOM); }
;
ldi
: OP_LDI '#' number {
bpf_set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $3); }
| OP_LDI number {
bpf_set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $2); }
;
ld
: OP_LD '#' number {
bpf_set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $3); }
| OP_LD K_PKT_LEN {
bpf_set_curr_instr(BPF_LD | BPF_W | BPF_LEN, 0, 0, 0); }
| OP_LD K_PROTO {
bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_PROTOCOL); }
| OP_LD K_TYPE {
bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_PKTTYPE); }
| OP_LD K_IFIDX {
bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_IFINDEX); }
| OP_LD K_NLATTR {
bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_NLATTR); }
| OP_LD K_NLATTR_NEST {
bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_NLATTR_NEST); }
| OP_LD K_MARK {
bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_MARK); }
| OP_LD K_QUEUE {
bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_QUEUE); }
| OP_LD K_HATYPE {
bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_HATYPE); }
| OP_LD K_RXHASH {
bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_RXHASH); }
| OP_LD K_CPU {
bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_CPU); }
| OP_LD K_VLANT {
bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_VLAN_TAG); }
| OP_LD K_VLANP {
bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); }
| OP_LD K_POFF {
bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
| OP_LD K_RAND {
bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
SKF_AD_OFF + SKF_AD_RANDOM); }
| OP_LD 'M' '[' number ']' {
bpf_set_curr_instr(BPF_LD | BPF_MEM, 0, 0, $4); }
| OP_LD '[' 'x' '+' number ']' {
bpf_set_curr_instr(BPF_LD | BPF_W | BPF_IND, 0, 0, $5); }
| OP_LD '[' '%' 'x' '+' number ']' {
bpf_set_curr_instr(BPF_LD | BPF_W | BPF_IND, 0, 0, $6); }
| OP_LD '[' number ']' {
bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, $3); }
;
ldxi
: OP_LDXI '#' number {
bpf_set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $3); }
| OP_LDXI number {
bpf_set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $2); }
;
ldx
: OP_LDX '#' number {
bpf_set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $3); }
| OP_LDX K_PKT_LEN {
bpf_set_curr_instr(BPF_LDX | BPF_W | BPF_LEN, 0, 0, 0); }
| OP_LDX 'M' '[' number ']' {
bpf_set_curr_instr(BPF_LDX | BPF_MEM, 0, 0, $4); }
| OP_LDXB number '*' '(' '[' number ']' '&' number ')' {
if ($2 != 4 || $9 != 0xf) {
fprintf(stderr, "ldxb offset not supported!\n");
exit(0);
} else {
bpf_set_curr_instr(BPF_LDX | BPF_MSH | BPF_B, 0, 0, $6); } }
| OP_LDX number '*' '(' '[' number ']' '&' number ')' {
if ($2 != 4 || $9 != 0xf) {
fprintf(stderr, "ldxb offset not supported!\n");
exit(0);
} else {
bpf_set_curr_instr(BPF_LDX | BPF_MSH | BPF_B, 0, 0, $6); } }
;
st
: OP_ST 'M' '[' number ']' {
bpf_set_curr_instr(BPF_ST, 0, 0, $4); }
;
stx
: OP_STX 'M' '[' number ']' {
bpf_set_curr_instr(BPF_STX, 0, 0, $4); }
;
jmp
: OP_JMP label {
bpf_set_jmp_label($2, JKL);
bpf_set_curr_instr(BPF_JMP | BPF_JA, 0, 0, 0); }
;
jeq
: OP_JEQ '#' number ',' label ',' label {
bpf_set_jmp_label($5, JTL);
bpf_set_jmp_label($7, JFL);
bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); }
| OP_JEQ 'x' ',' label ',' label {
bpf_set_jmp_label($4, JTL);
bpf_set_jmp_label($6, JFL);
bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
| OP_JEQ '%' 'x' ',' label ',' label {
bpf_set_jmp_label($5, JTL);
bpf_set_jmp_label($7, JFL);
bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
| OP_JEQ '#' number ',' label {
bpf_set_jmp_label($5, JTL);
bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); }
| OP_JEQ 'x' ',' label {
bpf_set_jmp_label($4, JTL);
bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
| OP_JEQ '%' 'x' ',' label {
bpf_set_jmp_label($5, JTL);
bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
;
jneq
: OP_JNEQ '#' number ',' label {
bpf_set_jmp_label($5, JFL);
bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); }
| OP_JNEQ 'x' ',' label {
bpf_set_jmp_label($4, JFL);
bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
| OP_JNEQ '%' 'x' ',' label {
bpf_set_jmp_label($5, JFL);
bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
;
jlt
: OP_JLT '#' number ',' label {
bpf_set_jmp_label($5, JFL);
bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); }
| OP_JLT 'x' ',' label {
bpf_set_jmp_label($4, JFL);
bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
| OP_JLT '%' 'x' ',' label {
bpf_set_jmp_label($5, JFL);
bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
;
jle
: OP_JLE '#' number ',' label {
bpf_set_jmp_label($5, JFL);
bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); }
| OP_JLE 'x' ',' label {
bpf_set_jmp_label($4, JFL);
bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
| OP_JLE '%' 'x' ',' label {
bpf_set_jmp_label($5, JFL);
bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
;
jgt
: OP_JGT '#' number ',' label ',' label {
bpf_set_jmp_label($5, JTL);
bpf_set_jmp_label($7, JFL);
bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); }
| OP_JGT 'x' ',' label ',' label {
bpf_set_jmp_label($4, JTL);
bpf_set_jmp_label($6, JFL);
bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
| OP_JGT '%' 'x' ',' label ',' label {
bpf_set_jmp_label($5, JTL);
bpf_set_jmp_label($7, JFL);
bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
| OP_JGT '#' number ',' label {
bpf_set_jmp_label($5, JTL);
bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); }
| OP_JGT 'x' ',' label {
bpf_set_jmp_label($4, JTL);
bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
| OP_JGT '%' 'x' ',' label {
bpf_set_jmp_label($5, JTL);
bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
;
jge
: OP_JGE '#' number ',' label ',' label {
bpf_set_jmp_label($5, JTL);
bpf_set_jmp_label($7, JFL);
bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); }
| OP_JGE 'x' ',' label ',' label {
bpf_set_jmp_label($4, JTL);
bpf_set_jmp_label($6, JFL);
bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
| OP_JGE '%' 'x' ',' label ',' label {
bpf_set_jmp_label($5, JTL);
bpf_set_jmp_label($7, JFL);
bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
| OP_JGE '#' number ',' label {
bpf_set_jmp_label($5, JTL);
bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); }
| OP_JGE 'x' ',' label {
bpf_set_jmp_label($4, JTL);
bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
| OP_JGE '%' 'x' ',' label {
bpf_set_jmp_label($5, JTL);
bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
;
jset
: OP_JSET '#' number ',' label ',' label {
bpf_set_jmp_label($5, JTL);
bpf_set_jmp_label($7, JFL);
bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_K, 0, 0, $3); }
| OP_JSET 'x' ',' label ',' label {
bpf_set_jmp_label($4, JTL);
bpf_set_jmp_label($6, JFL);
bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); }
| OP_JSET '%' 'x' ',' label ',' label {
bpf_set_jmp_label($5, JTL);
bpf_set_jmp_label($7, JFL);
bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); }
| OP_JSET '#' number ',' label {
bpf_set_jmp_label($5, JTL);
bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_K, 0, 0, $3); }
| OP_JSET 'x' ',' label {
bpf_set_jmp_label($4, JTL);
bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); }
| OP_JSET '%' 'x' ',' label {
bpf_set_jmp_label($5, JTL);
bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); }
;
add
: OP_ADD '#' number {
bpf_set_curr_instr(BPF_ALU | BPF_ADD | BPF_K, 0, 0, $3); }
| OP_ADD 'x' {
bpf_set_curr_instr(BPF_ALU | BPF_ADD | BPF_X, 0, 0, 0); }
| OP_ADD '%' 'x' {
bpf_set_curr_instr(BPF_ALU | BPF_ADD | BPF_X, 0, 0, 0); }
;
sub
: OP_SUB '#' number {
bpf_set_curr_instr(BPF_ALU | BPF_SUB | BPF_K, 0, 0, $3); }
| OP_SUB 'x' {
bpf_set_curr_instr(BPF_ALU | BPF_SUB | BPF_X, 0, 0, 0); }
| OP_SUB '%' 'x' {
bpf_set_curr_instr(BPF_ALU | BPF_SUB | BPF_X, 0, 0, 0); }
;
mul
: OP_MUL '#' number {
bpf_set_curr_instr(BPF_ALU | BPF_MUL | BPF_K, 0, 0, $3); }
| OP_MUL 'x' {
bpf_set_curr_instr(BPF_ALU | BPF_MUL | BPF_X, 0, 0, 0); }
| OP_MUL '%' 'x' {
bpf_set_curr_instr(BPF_ALU | BPF_MUL | BPF_X, 0, 0, 0); }
;
div
: OP_DIV '#' number {
bpf_set_curr_instr(BPF_ALU | BPF_DIV | BPF_K, 0, 0, $3); }
| OP_DIV 'x' {
bpf_set_curr_instr(BPF_ALU | BPF_DIV | BPF_X, 0, 0, 0); }
| OP_DIV '%' 'x' {
bpf_set_curr_instr(BPF_ALU | BPF_DIV | BPF_X, 0, 0, 0); }
;
mod
: OP_MOD '#' number {
bpf_set_curr_instr(BPF_ALU | BPF_MOD | BPF_K, 0, 0, $3); }
| OP_MOD 'x' {
bpf_set_curr_instr(BPF_ALU | BPF_MOD | BPF_X, 0, 0, 0); }
| OP_MOD '%' 'x' {
bpf_set_curr_instr(BPF_ALU | BPF_MOD | BPF_X, 0, 0, 0); }
;
neg
: OP_NEG {
bpf_set_curr_instr(BPF_ALU | BPF_NEG, 0, 0, 0); }
;
and
: OP_AND '#' number {
bpf_set_curr_instr(BPF_ALU | BPF_AND | BPF_K, 0, 0, $3); }
| OP_AND 'x' {
bpf_set_curr_instr(BPF_ALU | BPF_AND | BPF_X, 0, 0, 0); }
| OP_AND '%' 'x' {
bpf_set_curr_instr(BPF_ALU | BPF_AND | BPF_X, 0, 0, 0); }
;
or
: OP_OR '#' number {
bpf_set_curr_instr(BPF_ALU | BPF_OR | BPF_K, 0, 0, $3); }
| OP_OR 'x' {
bpf_set_curr_instr(BPF_ALU | BPF_OR | BPF_X, 0, 0, 0); }
| OP_OR '%' 'x' {
bpf_set_curr_instr(BPF_ALU | BPF_OR | BPF_X, 0, 0, 0); }
;
xor
: OP_XOR '#' number {
bpf_set_curr_instr(BPF_ALU | BPF_XOR | BPF_K, 0, 0, $3); }
| OP_XOR 'x' {
bpf_set_curr_instr(BPF_ALU | BPF_XOR | BPF_X, 0, 0, 0); }
| OP_XOR '%' 'x' {
bpf_set_curr_instr(BPF_ALU | BPF_XOR | BPF_X, 0, 0, 0); }
;
lsh
: OP_LSH '#' number {
bpf_set_curr_instr(BPF_ALU | BPF_LSH | BPF_K, 0, 0, $3); }
| OP_LSH 'x' {
bpf_set_curr_instr(BPF_ALU | BPF_LSH | BPF_X, 0, 0, 0); }
| OP_LSH '%' 'x' {
bpf_set_curr_instr(BPF_ALU | BPF_LSH | BPF_X, 0, 0, 0); }
;
rsh
: OP_RSH '#' number {
bpf_set_curr_instr(BPF_ALU | BPF_RSH | BPF_K, 0, 0, $3); }
| OP_RSH 'x' {
bpf_set_curr_instr(BPF_ALU | BPF_RSH | BPF_X, 0, 0, 0); }
| OP_RSH '%' 'x' {
bpf_set_curr_instr(BPF_ALU | BPF_RSH | BPF_X, 0, 0, 0); }
;
ret
: OP_RET 'a' {
bpf_set_curr_instr(BPF_RET | BPF_A, 0, 0, 0); }
| OP_RET '%' 'a' {
bpf_set_curr_instr(BPF_RET | BPF_A, 0, 0, 0); }
| OP_RET 'x' {
bpf_set_curr_instr(BPF_RET | BPF_X, 0, 0, 0); }
| OP_RET '%' 'x' {
bpf_set_curr_instr(BPF_RET | BPF_X, 0, 0, 0); }
| OP_RET '#' number {
bpf_set_curr_instr(BPF_RET | BPF_K, 0, 0, $3); }
;
tax
: OP_TAX {
bpf_set_curr_instr(BPF_MISC | BPF_TAX, 0, 0, 0); }
;
txa
: OP_TXA {
bpf_set_curr_instr(BPF_MISC | BPF_TXA, 0, 0, 0); }
;
%%
static int curr_instr = 0;
static struct sock_filter out[BPF_MAXINSNS];
static char **labels, **labels_jt, **labels_jf, **labels_k;
static void bpf_assert_max(void)
{
if (curr_instr >= BPF_MAXINSNS) {
fprintf(stderr, "only max %u insns allowed!\n", BPF_MAXINSNS);
exit(0);
}
}
static void bpf_set_curr_instr(uint16_t code, uint8_t jt, uint8_t jf,
uint32_t k)
{
bpf_assert_max();
out[curr_instr].code = code;
out[curr_instr].jt = jt;
out[curr_instr].jf = jf;
out[curr_instr].k = k;
curr_instr++;
}
static void bpf_set_curr_label(char *label)
{
bpf_assert_max();
labels[curr_instr] = label;
}
static void bpf_set_jmp_label(char *label, enum jmp_type type)
{
bpf_assert_max();
switch (type) {
case JTL:
labels_jt[curr_instr] = label;
break;
case JFL:
labels_jf[curr_instr] = label;
break;
case JKL:
labels_k[curr_instr] = label;
break;
}
}
static int bpf_find_insns_offset(const char *label)
{
int i, max = curr_instr, ret = -ENOENT;
for (i = 0; i < max; i++) {
if (labels[i] && !strcmp(label, labels[i])) {
ret = i;
break;
}
}
if (ret == -ENOENT) {
fprintf(stderr, "no such label \'%s\'!\n", label);
exit(0);
}
return ret;
}
static void bpf_stage_1_insert_insns(void)
{
yyparse();
}
static void bpf_reduce_k_jumps(void)
{
int i;
for (i = 0; i < curr_instr; i++) {
if (labels_k[i]) {
int off = bpf_find_insns_offset(labels_k[i]);
out[i].k = (uint32_t) (off - i - 1);
}
}
}
static void bpf_reduce_jt_jumps(void)
{
int i;
for (i = 0; i < curr_instr; i++) {
if (labels_jt[i]) {
int off = bpf_find_insns_offset(labels_jt[i]);
out[i].jt = (uint8_t) (off - i -1);
}
}
}
static void bpf_reduce_jf_jumps(void)
{
int i;
for (i = 0; i < curr_instr; i++) {
if (labels_jf[i]) {
int off = bpf_find_insns_offset(labels_jf[i]);
out[i].jf = (uint8_t) (off - i - 1);
}
}
}
static void bpf_stage_2_reduce_labels(void)
{
bpf_reduce_k_jumps();
bpf_reduce_jt_jumps();
bpf_reduce_jf_jumps();
}
static void bpf_pretty_print_c(void)
{
int i;
for (i = 0; i < curr_instr; i++)
printf("{ %#04x, %2u, %2u, %#010x },\n", out[i].code,
out[i].jt, out[i].jf, out[i].k);
}
static void bpf_pretty_print(void)
{
int i;
printf("%u,", curr_instr);
for (i = 0; i < curr_instr; i++)
printf("%u %u %u %u,", out[i].code,
out[i].jt, out[i].jf, out[i].k);
printf("\n");
}
static void bpf_init(void)
{
memset(out, 0, sizeof(out));
labels = calloc(BPF_MAXINSNS, sizeof(*labels));
assert(labels);
labels_jt = calloc(BPF_MAXINSNS, sizeof(*labels_jt));
assert(labels_jt);
labels_jf = calloc(BPF_MAXINSNS, sizeof(*labels_jf));
assert(labels_jf);
labels_k = calloc(BPF_MAXINSNS, sizeof(*labels_k));
assert(labels_k);
}
static void bpf_destroy_labels(void)
{
int i;
for (i = 0; i < curr_instr; i++) {
free(labels_jf[i]);
free(labels_jt[i]);
free(labels_k[i]);
free(labels[i]);
}
}
static void bpf_destroy(void)
{
bpf_destroy_labels();
free(labels_jt);
free(labels_jf);
free(labels_k);
free(labels);
}
void bpf_asm_compile(FILE *fp, bool cstyle)
{
yyin = fp;
bpf_init();
bpf_stage_1_insert_insns();
bpf_stage_2_reduce_labels();
bpf_destroy();
if (cstyle)
bpf_pretty_print_c();
else
bpf_pretty_print();
if (fp != stdin)
fclose(yyin);
}
void yyerror(const char *str)
{
exit(1);
}

197
tools/net/bpf_jit_disasm.c Normal file
View file

@ -0,0 +1,197 @@
/*
* Minimal BPF JIT image disassembler
*
* Disassembles BPF JIT compiler emitted opcodes back to asm insn's for
* debugging or verification purposes.
*
* To get the disassembly of the JIT code, do the following:
*
* 1) `echo 2 > /proc/sys/net/core/bpf_jit_enable`
* 2) Load a BPF filter (e.g. `tcpdump -p -n -s 0 -i eth1 host 192.168.20.0/24`)
* 3) Run e.g. `bpf_jit_disasm -o` to read out the last JIT code
*
* Copyright 2013 Daniel Borkmann <borkmann@redhat.com>
* Licensed under the GNU General Public License, version 2.0 (GPLv2)
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <bfd.h>
#include <dis-asm.h>
#include <sys/klog.h>
#include <sys/types.h>
#include <regex.h>
static void get_exec_path(char *tpath, size_t size)
{
char *path;
ssize_t len;
snprintf(tpath, size, "/proc/%d/exe", (int) getpid());
tpath[size - 1] = 0;
path = strdup(tpath);
assert(path);
len = readlink(path, tpath, size);
tpath[len] = 0;
free(path);
}
static void get_asm_insns(uint8_t *image, size_t len, int opcodes)
{
int count, i, pc = 0;
char tpath[256];
struct disassemble_info info;
disassembler_ftype disassemble;
bfd *bfdf;
memset(tpath, 0, sizeof(tpath));
get_exec_path(tpath, sizeof(tpath));
bfdf = bfd_openr(tpath, NULL);
assert(bfdf);
assert(bfd_check_format(bfdf, bfd_object));
init_disassemble_info(&info, stdout, (fprintf_ftype) fprintf);
info.arch = bfd_get_arch(bfdf);
info.mach = bfd_get_mach(bfdf);
info.buffer = image;
info.buffer_length = len;
disassemble_init_for_target(&info);
disassemble = disassembler(bfdf);
assert(disassemble);
do {
printf("%4x:\t", pc);
count = disassemble(pc, &info);
if (opcodes) {
printf("\n\t");
for (i = 0; i < count; ++i)
printf("%02x ", (uint8_t) image[pc + i]);
}
printf("\n");
pc += count;
} while(count > 0 && pc < len);
bfd_close(bfdf);
}
static char *get_klog_buff(int *klen)
{
int ret, len = klogctl(10, NULL, 0);
char *buff = malloc(len);
assert(buff && klen);
ret = klogctl(3, buff, len);
assert(ret >= 0);
*klen = ret;
return buff;
}
static void put_klog_buff(char *buff)
{
free(buff);
}
static int get_last_jit_image(char *haystack, size_t hlen,
uint8_t *image, size_t ilen)
{
char *ptr, *pptr, *tmp;
off_t off = 0;
int ret, flen, proglen, pass, ulen = 0;
regmatch_t pmatch[1];
unsigned long base;
regex_t regex;
if (hlen == 0)
return 0;
ret = regcomp(&regex, "flen=[[:alnum:]]+ proglen=[[:digit:]]+ "
"pass=[[:digit:]]+ image=[[:xdigit:]]+", REG_EXTENDED);
assert(ret == 0);
ptr = haystack;
while (1) {
ret = regexec(&regex, ptr, 1, pmatch, 0);
if (ret == 0) {
ptr += pmatch[0].rm_eo;
off += pmatch[0].rm_eo;
assert(off < hlen);
} else
break;
}
ptr = haystack + off - (pmatch[0].rm_eo - pmatch[0].rm_so);
ret = sscanf(ptr, "flen=%d proglen=%d pass=%d image=%lx",
&flen, &proglen, &pass, &base);
if (ret != 4)
return 0;
tmp = ptr = haystack + off;
while ((ptr = strtok(tmp, "\n")) != NULL && ulen < ilen) {
tmp = NULL;
if (!strstr(ptr, "JIT code"))
continue;
pptr = ptr;
while ((ptr = strstr(pptr, ":")))
pptr = ptr + 1;
ptr = pptr;
do {
image[ulen++] = (uint8_t) strtoul(pptr, &pptr, 16);
if (ptr == pptr || ulen >= ilen) {
ulen--;
break;
}
ptr = pptr;
} while (1);
}
assert(ulen == proglen);
printf("%d bytes emitted from JIT compiler (pass:%d, flen:%d)\n",
proglen, pass, flen);
printf("%lx + <x>:\n", base);
regfree(&regex);
return ulen;
}
int main(int argc, char **argv)
{
int len, klen, opcodes = 0;
char *kbuff;
static uint8_t image[32768];
if (argc > 1) {
if (!strncmp("-o", argv[argc - 1], 2)) {
opcodes = 1;
} else {
printf("usage: bpf_jit_disasm [-o: show opcodes]\n");
exit(0);
}
}
bfd_init();
memset(image, 0, sizeof(image));
kbuff = get_klog_buff(&klen);
len = get_last_jit_image(kbuff, klen, image, sizeof(image));
if (len > 0)
get_asm_insns(image, len, opcodes);
put_klog_buff(kbuff);
return 0;
}