3 * Politecnico di Torino. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the Politecnico
13 * di Torino, and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
28 #include <ddk/ntddk.h>
38 // emit routine to update the jump table
40 void emit_lenght(binary_stream
*stream
, ULONG value
, UINT len
)
42 (stream
->refs
)[stream
->bpf_pc
]+=len
;
47 // emit routine to output the actual binary code
49 void emit_code(binary_stream
*stream
, ULONG value
, UINT len
)
55 stream
->ibuf
[stream
->cur_ip
]=(UCHAR
)value
;
60 *((USHORT
*)(stream
->ibuf
+stream
->cur_ip
))=(USHORT
)value
;
65 *((ULONG
*)(stream
->ibuf
+stream
->cur_ip
))=value
;
78 // Function that does the real stuff
80 BPF_filter_function
BPFtoX86(struct bpf_insn
*prog
, UINT nins
, INT
*mem
)
87 // Allocate the reference table for the jumps
89 #define NPF_TAG_REFTABLE TAG('0', 'J', 'W', 'A')
90 stream
.refs
=(UINT
*)ExAllocatePoolWithTag(NonPagedPool
, (nins
+ 1)*sizeof(UINT
), NPF_TAG_REFTABLE
);
92 stream
.refs
=(UINT
*)malloc((nins
+ 1)*sizeof(UINT
));
99 // Reset the reference table
100 for(i
=0; i
< nins
+ 1; i
++)
106 // the first pass will emit the lengths of the instructions
107 // to create the reference table
114 /* create the procedure header */
161 case BPF_LD
|BPF_W
|BPF_ABS
:
165 ADDib(ECX
,sizeof(INT
))
166 CMPodd(ECX
, EBP
, 0x10)
174 MOVid(EAX
,0) //this can be optimized with xor eax,eax
176 MOVobd(EAX
, EBX
, ESI
)
181 case BPF_LD
|BPF_H
|BPF_ABS
:
185 ADDib(ECX
,sizeof(SHORT
))
186 CMPodd(ECX
, EBP
, 0x10)
202 case BPF_LD
|BPF_B
|BPF_ABS
:
205 CMPodd(ECX
, EBP
, 0x10)
220 case BPF_LD
|BPF_W
|BPF_LEN
:
222 MOVodd(EAX
, EBP
, 0xc)
226 case BPF_LDX
|BPF_W
|BPF_LEN
:
228 MOVodd(EDX
, EBP
, 0xc)
232 case BPF_LD
|BPF_W
|BPF_IND
:
237 ADDib(ECX
,sizeof(INT
))
238 CMPodd(ECX
, EBP
, 0x10)
248 MOVobd(EAX
, EBX
, ESI
)
253 case BPF_LD
|BPF_H
|BPF_IND
:
258 ADDib(ECX
,sizeof(SHORT
))
259 CMPodd(ECX
, EBP
, 0x10)
275 case BPF_LD
|BPF_B
|BPF_IND
:
279 CMPodd(ECX
, EBP
, 0x10)
294 case BPF_LDX
|BPF_MSH
|BPF_B
:
297 CMPodd(ECX
, EBP
, 0x10)
320 case BPF_LDX
|BPF_IMM
:
330 MOVobd(EAX
, ECX
, ESI
)
334 case BPF_LDX
|BPF_MEM
:
338 MOVobd(EDX
, ECX
, ESI
)
344 // XXX: this command and the following could be optimized if the previous
345 // instruction was already of this type
348 MOVomd(ECX
, ESI
, EAX
)
356 MOVomd(ECX
, ESI
, EDX
)
361 JMP(stream
.refs
[stream
.bpf_pc
+ins
->k
]-stream
.refs
[stream
.bpf_pc
])
365 case BPF_JMP
|BPF_JGT
|BPF_K
:
368 JG(stream
.refs
[stream
.bpf_pc
+ins
->jt
]-stream
.refs
[stream
.bpf_pc
]+5) // 5 is the size of the following JMP
369 JMP(stream
.refs
[stream
.bpf_pc
+ins
->jf
]-stream
.refs
[stream
.bpf_pc
])
372 case BPF_JMP
|BPF_JGE
|BPF_K
:
375 JGE(stream
.refs
[stream
.bpf_pc
+ins
->jt
]-stream
.refs
[stream
.bpf_pc
]+5)
376 JMP(stream
.refs
[stream
.bpf_pc
+ins
->jf
]-stream
.refs
[stream
.bpf_pc
])
380 case BPF_JMP
|BPF_JEQ
|BPF_K
:
383 JE(stream
.refs
[stream
.bpf_pc
+ins
->jt
]-stream
.refs
[stream
.bpf_pc
]+5)
384 JMP(stream
.refs
[stream
.bpf_pc
+ins
->jf
]-stream
.refs
[stream
.bpf_pc
])
388 case BPF_JMP
|BPF_JSET
|BPF_K
:
392 JE(stream
.refs
[stream
.bpf_pc
+ins
->jf
]-stream
.refs
[stream
.bpf_pc
]+5)
393 JMP(stream
.refs
[stream
.bpf_pc
+ins
->jt
]-stream
.refs
[stream
.bpf_pc
])
397 case BPF_JMP
|BPF_JGT
|BPF_X
:
400 JA(stream
.refs
[stream
.bpf_pc
+ins
->jt
]-stream
.refs
[stream
.bpf_pc
]+5)
401 JMP(stream
.refs
[stream
.bpf_pc
+ins
->jf
]-stream
.refs
[stream
.bpf_pc
])
404 case BPF_JMP
|BPF_JGE
|BPF_X
:
407 JAE(stream
.refs
[stream
.bpf_pc
+ins
->jt
]-stream
.refs
[stream
.bpf_pc
]+5)
408 JMP(stream
.refs
[stream
.bpf_pc
+ins
->jf
]-stream
.refs
[stream
.bpf_pc
])
412 case BPF_JMP
|BPF_JEQ
|BPF_X
:
415 JE(stream
.refs
[stream
.bpf_pc
+ins
->jt
]-stream
.refs
[stream
.bpf_pc
]+5)
416 JMP(stream
.refs
[stream
.bpf_pc
+ins
->jf
]-stream
.refs
[stream
.bpf_pc
])
420 case BPF_JMP
|BPF_JSET
|BPF_X
:
424 JE(stream
.refs
[stream
.bpf_pc
+ins
->jf
]-stream
.refs
[stream
.bpf_pc
]+5)
425 JMP(stream
.refs
[stream
.bpf_pc
+ins
->jt
]-stream
.refs
[stream
.bpf_pc
])
429 case BPF_ALU
|BPF_ADD
|BPF_X
:
435 case BPF_ALU
|BPF_SUB
|BPF_X
:
441 case BPF_ALU
|BPF_MUL
|BPF_X
:
448 case BPF_ALU
|BPF_DIV
|BPF_X
:
467 case BPF_ALU
|BPF_AND
|BPF_X
:
473 case BPF_ALU
|BPF_OR
|BPF_X
:
479 case BPF_ALU
|BPF_LSH
|BPF_X
:
486 case BPF_ALU
|BPF_RSH
|BPF_X
:
493 case BPF_ALU
|BPF_ADD
|BPF_K
:
499 case BPF_ALU
|BPF_SUB
|BPF_K
:
505 case BPF_ALU
|BPF_MUL
|BPF_K
:
514 case BPF_ALU
|BPF_DIV
|BPF_K
:
524 case BPF_ALU
|BPF_AND
|BPF_K
:
530 case BPF_ALU
|BPF_OR
|BPF_K
:
536 case BPF_ALU
|BPF_LSH
|BPF_K
:
538 SHLib(EAX
, (ins
->k
) & 255)
542 case BPF_ALU
|BPF_RSH
|BPF_K
:
544 SHRib(EAX
, (ins
->k
) & 255)
548 case BPF_ALU
|BPF_NEG
:
554 case BPF_MISC
|BPF_TAX
:
560 case BPF_MISC
|BPF_TXA
:
577 #define NPF_TAG_STREAMBUF TAG('1', 'J', 'W', 'A')
578 stream
.ibuf
=(CHAR
*)ExAllocatePoolWithTag(NonPagedPool
, stream
.cur_ip
, NPF_TAG_STREAMBUF
);
580 stream
.ibuf
=(CHAR
*)malloc(stream
.cur_ip
);
582 if(stream
.ibuf
==NULL
)
585 ExFreePool(stream
.refs
);
592 // modify the reference table to contain the offsets and not the lengths of the instructions
593 for(i
=1; i
< nins
+ 1; i
++)
594 stream
.refs
[i
]+=stream
.refs
[i
-1];
596 // Reset the counters
599 // the second pass creates the actual code
604 // the reference table is needed only during compilation, now we can free it
606 ExFreePool(stream
.refs
);
610 return (BPF_filter_function
)stream
.ibuf
;
615 JIT_BPF_Filter
* BPF_jitter(struct bpf_insn
*fp
, INT nins
)
617 JIT_BPF_Filter
*Filter
;
620 // Allocate the filter structure
622 #define NPF_TAG_FILTSTRUCT TAG('2', 'J', 'W', 'A')
623 Filter
=(struct JIT_BPF_Filter
*)ExAllocatePoolWithTag(NonPagedPool
, sizeof(struct JIT_BPF_Filter
), NPF_TAG_FILTSTRUCT
);
625 Filter
=(struct JIT_BPF_Filter
*)malloc(sizeof(struct JIT_BPF_Filter
));
632 // Allocate the filter's memory
634 #define NPF_TAG_FILTMEM TAG('3', 'J', 'W', 'A')
635 Filter
->mem
=(INT
*)ExAllocatePoolWithTag(NonPagedPool
, BPF_MEMWORDS
*sizeof(INT
), NPF_TAG_FILTMEM
);
637 Filter
->mem
=(INT
*)malloc(BPF_MEMWORDS
*sizeof(INT
));
639 if(Filter
->mem
==NULL
)
650 if((Filter
->Function
= BPFtoX86(fp
, nins
, Filter
->mem
))==NULL
)
653 ExFreePool(Filter
->mem
);
667 //////////////////////////////////////////////////////////////
669 void BPF_Destroy_JIT_Filter(JIT_BPF_Filter
*Filter
){
672 ExFreePool(Filter
->mem
);
673 ExFreePool(Filter
->Function
);
677 free(Filter
->Function
);