eBPF processor support

Signed-off-by: Nalen98 <nalenaskeyx@gmail.com>
This commit is contained in:
Nalen98
2023-01-25 18:15:00 +03:00
parent a59c42dd96
commit 79102c13c4
15 changed files with 2141 additions and 0 deletions

View File

View File

@@ -0,0 +1,26 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle"
apply from: "$rootProject.projectDir/gradle/javaProject.gradle"
apply from: "$rootProject.projectDir/gradle/processorProject.gradle"
apply from: "$rootProject.projectDir/gradle/jacocoProject.gradle"
apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle"
apply plugin: 'eclipse'
eclipse.project.name = 'Processors eBPF'
dependencies {
api project(':Base')
}

View File

@@ -0,0 +1,9 @@
##VERSION: 2.0
Module.manifest||GHIDRA||||END|
data/languages/eBPF.cspec||GHIDRA||||END|
data/languages/eBPF.dwarf||GHIDRA||||END|
data/languages/eBPF.ldefs||GHIDRA||||END|
data/languages/eBPF.opinion||GHIDRA||||END|
data/languages/eBPF.pspec||GHIDRA||||END|
data/languages/eBPF.sinc||GHIDRA||||END|
data/languages/eBPF_le.slaspec||GHIDRA||||END|

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<compiler_spec>
<data_organization>
<absolute_max_alignment value="0" />
<machine_alignment value="2" />
<default_alignment value="1" />
<default_pointer_alignment value="8" />
<pointer_size value="8" />
<wchar_size value="2" />
<short_size value="2" />
<integer_size value="4" />
<long_size value="4" />
<long_long_size value="8" />
<float_size value="4" />
<double_size value="8" />
<long_double_size value="8" />
<size_alignment_map>
<entry size="1" alignment="1" />
<entry size="2" alignment="2" />
<entry size="4" alignment="4" />
<entry size="8" alignment="8" />
</size_alignment_map>
</data_organization>
<global>
<range space="ram"/>
<range space="syscall"/>
</global>
<stackpointer register="R10" space="ram"/>
<default_proto>
<prototype name="__fastcall" extrapop="0" stackshift="0">
<input>
<pentry minsize="1" maxsize="8">
<register name="R1"/>
</pentry>
<pentry minsize="1" maxsize="8">
<register name="R2"/>
</pentry>
<pentry minsize="1" maxsize="8">
<register name="R3"/>
</pentry>
<pentry minsize="1" maxsize="8">
<register name="R4"/>
</pentry>
<pentry minsize="1" maxsize="8">
<register name="R5"/>
</pentry>
</input>
<output killedbycall="true">
<pentry minsize="1" maxsize="8">
<register name="R0"/>
</pentry>
</output>
<unaffected>
<varnode space="ram" offset="8" size="8"/>
<register name="R6"/>
<register name="R7"/>
<register name="R8"/>
<register name="R9"/>
<register name="R10"/>
</unaffected>
</prototype>
</default_proto>
</compiler_spec>

View File

@@ -0,0 +1,16 @@
<dwarf>
<register_mappings>
<register_mapping dwarf="0" ghidra="R0"/>
<register_mapping dwarf="1" ghidra="R1"/>
<register_mapping dwarf="2" ghidra="R2"/>
<register_mapping dwarf="3" ghidra="R3"/>
<register_mapping dwarf="4" ghidra="R4"/>
<register_mapping dwarf="5" ghidra="R5"/>
<register_mapping dwarf="6" ghidra="R6"/>
<register_mapping dwarf="7" ghidra="R7"/>
<register_mapping dwarf="8" ghidra="R8"/>
<register_mapping dwarf="9" ghidra="R9"/>
<register_mapping dwarf="10" ghidra="R10" stackpointer="true"/>
</register_mappings>
<call_frame_cfa value="8"/>
</dwarf>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<language_definitions>
<language processor="eBPF"
endian="little"
size="64"
variant="default"
version="1.0"
slafile="eBPF_le.sla"
processorspec="eBPF.pspec"
id="eBPF:LE:64:default">
<description>eBPF processor 64-bit little-endian</description>
<compiler name="default" spec="eBPF.cspec" id="default"/>
<external_name tool="DWARF.register.mapping.file" name="eBPF.dwarf"/>
</language>
</language_definitions>

View File

@@ -0,0 +1,5 @@
<opinions>
<constraint loader="Executable and Linking Format (ELF)" compilerSpecID="default">
<constraint primary="247" processor="eBPF" endian="little" size="64" />
</constraint>
</opinions>

View File

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<processor_spec>
<programcounter register="PC"/>
<default_symbols>
<symbol name="bpf_unspec" address="syscall:0x0"/>
<symbol name="bpf_map_lookup_elem" address="syscall:0x1"/>
<symbol name="bpf_map_update_elem" address="syscall:0x2"/>
<symbol name="bpf_map_delete_elem" address="syscall:0x3"/>
<symbol name="bpf_probe_read" address="syscall:0x4"/>
<symbol name="bpf_ktime_get_ns" address="syscall:0x5"/>
<symbol name="bpf_trace_printk" address="syscall:0x6"/>
<symbol name="bpf_get_prandom_u32" address="syscall:0x7"/>
<symbol name="bpf_get_smp_processor_id" address="syscall:0x8"/>
<symbol name="bpf_skb_store_bytes" address="syscall:0x9"/>
<symbol name="bpf_l3_csum_replace" address="syscall:0xa"/>
<symbol name="bpf_l4_csum_replace" address="syscall:0xb"/>
<symbol name="bpf_tail_call" address="syscall:0xc"/>
<symbol name="bpf_clone_redirect" address="syscall:0xd"/>
<symbol name="bpf_get_current_pid_tgid" address="syscall:0xe"/>
<symbol name="bpf_get_current_uid_gid" address="syscall:0xf"/>
<symbol name="bpf_get_current_comm" address="syscall:0x10"/>
<symbol name="bpf_get_cgroup_classid" address="syscall:0x11"/>
<symbol name="bpf_skb_vlan_push" address="syscall:0x12"/>
<symbol name="bpf_skb_vlan_pop" address="syscall:0x13"/>
<symbol name="bpf_skb_get_tunnel_key" address="syscall:0x14"/>
<symbol name="bpf_skb_set_tunnel_key" address="syscall:0x15"/>
<symbol name="bpf_perf_event_read" address="syscall:0x16"/>
<symbol name="bpf_redirect" address="syscall:0x17"/>
<symbol name="bpf_get_route_realm" address="syscall:0x18"/>
<symbol name="bpf_perf_event_output" address="syscall:0x19"/>
<symbol name="bpf_skb_load_bytes" address="syscall:0x1a"/>
<symbol name="bpf_get_stackid" address="syscall:0x1b"/>
<symbol name="bpf_csum_diff" address="syscall:0x1c"/>
<symbol name="bpf_skb_get_tunnel_opt" address="syscall:0x1d"/>
<symbol name="bpf_skb_set_tunnel_opt" address="syscall:0x1e"/>
<symbol name="bpf_skb_change_proto" address="syscall:0x1f"/>
<symbol name="bpf_skb_change_type" address="syscall:0x20"/>
<symbol name="bpf_skb_under_cgroup" address="syscall:0x21"/>
<symbol name="bpf_get_hash_recalc" address="syscall:0x22"/>
<symbol name="bpf_get_current_task" address="syscall:0x23"/>
<symbol name="bpf_probe_write_user" address="syscall:0x24"/>
<symbol name="bpf_current_task_under_cgroup" address="syscall:0x25"/>
<symbol name="bpf_skb_change_tail" address="syscall:0x26"/>
<symbol name="bpf_skb_pull_data" address="syscall:0x27"/>
<symbol name="bpf_csum_update" address="syscall:0x28"/>
<symbol name="bpf_set_hash_invalid" address="syscall:0x29"/>
<symbol name="bpf_get_numa_node_id" address="syscall:0x2a"/>
<symbol name="bpf_skb_change_head" address="syscall:0x2b"/>
<symbol name="bpf_xdp_adjust_head" address="syscall:0x2c"/>
<symbol name="bpf_probe_read_str" address="syscall:0x2d"/>
<symbol name="bpf_get_socket_cookie" address="syscall:0x2e"/>
<symbol name="bpf_get_socket_cookie" address="syscall:0x2f"/>
<symbol name="bpf_get_socket_cookie" address="syscall:0x30"/>
<symbol name="bpf_get_socket_uid" address="syscall:0x31"/>
<symbol name="bpf_set_hash" address="syscall:0x32"/>
<symbol name="bpf_setsockopt" address="syscall:0x33"/>
<symbol name="bpf_skb_adjust_room" address="syscall:0x34"/>
<symbol name="bpf_redirect_map" address="syscall:0x35"/>
<symbol name="bpf_sk_redirect_map" address="syscall:0x36"/>
<symbol name="bpf_sock_map_update" address="syscall:0x37"/>
<symbol name="bpf_xdp_adjust_meta" address="syscall:0x38"/>
<symbol name="bpf_perf_event_read_value" address="syscall:0x39"/>
<symbol name="bpf_perf_prog_read_value" address="syscall:0x3a"/>
<symbol name="bpf_getsockopt" address="syscall:0x3b"/>
<symbol name="bpf_override_return" address="syscall:0x3c"/>
<symbol name="bpf_sock_ops_cb_flags_set" address="syscall:0x3d"/>
<symbol name="bpf_msg_redirect_map" address="syscall:0x3e"/>
<symbol name="bpf_msg_apply_bytes" address="syscall:0x3f"/>
</default_symbols>
<default_memory_blocks>
<memory_block name="eBPFHelper_functions" start_address="syscall:0" length="0x400" initialized="true"/>
</default_memory_blocks>
</processor_spec>

View File

@@ -0,0 +1,519 @@
###############################################################################
# eBPF Processor Specification for Ghidra
###############################################################################
#eBPF is a RISC register machine with a total of 11 64-bit registers, a program counter and a 512 byte fixed-size stack.
#9 registers are general purpouse read-write, one is a read-only stack pointer and the program counter is implicit,
#i.e. we can only jump to a certain offset from it. The eBPF registers are always 64-bit wide.
define space ram type=ram_space size=8 default;
define space register type=register_space size=4;
define space syscall type=ram_space size=4;
define register offset=0 size=8 [ R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 PC ];
# Instruction encoding: Insop:8, dst_reg:4, src_reg:4, off:16, imm:32 - from lsb to msb
define token instr(64)
imm=(32, 63) signed
off=(16, 31) signed
src=(12, 15)
dst=(8, 11)
op_alu_jmp_opcode=(4, 7)
op_alu_jmp_source=(3, 3)
op_ld_st_mode=(5, 7)
op_ld_st_size=(3, 4)
op_insn_class=(0, 2)
;
#We'll need this token to operate with LDDW instruction, which has 64 bit imm value
define token immtoken(64)
imm2=(32, 63)
;
#To operate with registers
attach variables [ src dst ] [ R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 _ _ _ _ _ ];
#Arithmetic instructions
#BPF_ALU64
###############################################################################
:MOV dst, src is src & dst & op_alu_jmp_opcode=0xb & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = src; }
:MOV dst, imm is imm & dst & op_alu_jmp_opcode=0xb & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = imm; }
:ADD dst, src is src & dst & op_alu_jmp_opcode=0x0 & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst + src; }
:ADD dst, imm is imm & dst & op_alu_jmp_opcode=0x0 & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst + imm; }
:SUB dst, src is src & dst & op_alu_jmp_opcode=0x1 & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst - src; }
:SUB dst, imm is imm & dst & op_alu_jmp_opcode=0x1 & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst - imm; }
:MUL dst, src is src & dst & op_alu_jmp_opcode=0x2 & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst * src; }
:MUL dst, imm is imm & dst & op_alu_jmp_opcode=0x2 & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst * imm; }
:DIV dst, src is src & dst & op_alu_jmp_opcode=0x3 & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst / src; }
:DIV dst, imm is imm & dst & op_alu_jmp_opcode=0x3 & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst / imm; }
:OR dst, src is src & dst & op_alu_jmp_opcode=0x4 & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst | src; }
:OR dst, imm is imm & dst & op_alu_jmp_opcode=0x4 & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst | imm; }
:AND dst, src is src & dst & op_alu_jmp_opcode=0x5 & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst & src; }
:AND dst, imm is imm & dst & op_alu_jmp_opcode=0x5 & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst & imm; }
:LSH dst, src is src & dst & op_alu_jmp_opcode=0x6 & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst << src; }
:LSH dst, imm is imm & dst & op_alu_jmp_opcode=0x6 & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst << imm; }
:RSH dst, src is src & dst & op_alu_jmp_opcode=0x7 & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst >> src; }
:RSH dst, imm is imm & dst & op_alu_jmp_opcode=0x7 & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst >> imm; }
:NEG dst is dst & op_alu_jmp_opcode=0x8 & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = -dst; }
:MOD dst, src is src & dst & op_alu_jmp_opcode=0x9 & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst % src; }
:MOD dst, imm is imm & dst & op_alu_jmp_opcode=0x9 & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst % imm; }
:XOR dst, src is src & dst & op_alu_jmp_opcode=0xa & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst ^ src; }
:XOR dst, imm is imm & dst & op_alu_jmp_opcode=0xa & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst ^ imm; }
:ARSH dst, src is src & dst & op_alu_jmp_opcode=0xc & op_alu_jmp_source=1 & op_insn_class=0x7 { dst = dst s>> src; }
:ARSH dst, imm is imm & dst & op_alu_jmp_opcode=0xc & op_alu_jmp_source=0 & op_insn_class=0x7 { dst = dst s>> imm; }
#BPF_ALU
###############################################################################
:MOV dst, src is src & dst & op_alu_jmp_opcode=0xb & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(src:4); }
:MOV dst, imm is imm & dst & op_alu_jmp_opcode=0xb & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = imm; }
:ADD dst, src is src & dst & op_alu_jmp_opcode=0x0 & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 + src:4); }
:ADD dst, imm is imm & dst & op_alu_jmp_opcode=0x0 & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 + imm); }
:SUB dst, src is src & dst & op_alu_jmp_opcode=0x1 & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 - src:4); }
:SUB dst, imm is imm & dst & op_alu_jmp_opcode=0x1 & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 - imm); }
:MUL dst, src is src & dst & op_alu_jmp_opcode=0x2 & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 * src:4); }
:MUL dst, imm is imm & dst & op_alu_jmp_opcode=0x2 & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 * imm); }
:DIV dst, src is src & dst & op_alu_jmp_opcode=0x3 & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 / src:4); }
:DIV dst, imm is imm & dst & op_alu_jmp_opcode=0x3 & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 / imm); }
:OR dst, src is src & dst & op_alu_jmp_opcode=0x4 & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 | src:4); }
:OR dst, imm is imm & dst & op_alu_jmp_opcode=0x4 & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 | imm); }
:AND dst, src is src & dst & op_alu_jmp_opcode=0x5 & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 & src:4); }
:AND dst, imm is imm & dst & op_alu_jmp_opcode=0x5 & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 & imm); }
:LSH dst, src is src & dst & op_alu_jmp_opcode=0x6 & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 << src:4); }
:LSH dst, imm is imm & dst & op_alu_jmp_opcode=0x6 & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 << imm); }
:RSH dst, src is src & dst & op_alu_jmp_opcode=0x7 & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 >> src:4); }
:RSH dst, imm is imm & dst & op_alu_jmp_opcode=0x7 & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 >> imm); }
:NEG dst is dst & op_alu_jmp_opcode=0x8 & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(-dst:4); }
:MOD dst, src is src & dst & op_alu_jmp_opcode=0x9 & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 % src:4); }
:MOD dst, imm is imm & dst & op_alu_jmp_opcode=0x9 & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 % imm); }
:XOR dst, src is src & dst & op_alu_jmp_opcode=0xa & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 ^ src:4); }
:XOR dst, imm is imm & dst & op_alu_jmp_opcode=0xa & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 ^ imm); }
:ARSH dst, src is src & dst & op_alu_jmp_opcode=0xc & op_alu_jmp_source=1 & op_insn_class=0x4 { dst = zext(dst:4 s>> src:4); }
:ARSH dst, imm is imm & dst & op_alu_jmp_opcode=0xc & op_alu_jmp_source=0 & op_insn_class=0x4 { dst = zext(dst:4 s>> imm); }
#Bytewasp instructions
###############################################################################
# BPF_ALU | BPF_K | BPF_END
:LE16 dst is imm=0x10 & dst & op_alu_jmp_opcode=0xd & op_alu_jmp_source=0 & op_insn_class=0x4 { dst=((dst) >> 8) | ((dst) << 8); }
:LE32 dst is imm=0x20 & dst & op_alu_jmp_opcode=0xd & op_alu_jmp_source=0 & op_insn_class=0x4 { dst=((dst) >> 24) | (((dst) & 0x00FF0000) >> 8) | (((dst) & 0x0000FF00) << 8) | ((dst) << 24); }
:LE64 dst is imm=0x40 & dst & op_alu_jmp_opcode=0xd & op_alu_jmp_source=0 & op_insn_class=0x4 {
dst=( (dst << 56) & 0xff00000000000000 ) |
( (dst << 40) & 0x00ff000000000000 ) |
( (dst << 24) & 0x0000ff0000000000 ) |
( (dst << 8) & 0x000000ff00000000 ) |
( (dst >> 8) & 0x00000000ff000000 ) |
( (dst >> 24) & 0x0000000000ff0000 ) |
( (dst >> 40) & 0x000000000000ff00 ) |
( (dst >> 56) & 0x00000000000000ff );
}
# BPF_ALU | BPF_X | BPF_END
:BE16 dst is imm=0x10 & dst & op_alu_jmp_opcode=0xd & op_alu_jmp_source=1 & op_insn_class=0x4 { dst=((dst) >> 8) | ((dst) << 8); }
:BE32 dst is imm=0x20 & dst & op_alu_jmp_opcode=0xd & op_alu_jmp_source=1 & op_insn_class=0x4 { dst=((dst) >> 24) | (((dst) & 0x00FF0000) >> 8) | (((dst) & 0x0000FF00) << 8) | ((dst) << 24); }
:BE64 dst is imm=0x40 & dst & op_alu_jmp_opcode=0xd & op_alu_jmp_source=1 & op_insn_class=0x4 {
dst=( (dst << 56) & 0xff00000000000000 ) |
( (dst << 40) & 0x00ff000000000000 ) |
( (dst << 24) & 0x0000ff0000000000 ) |
( (dst << 8) & 0x000000ff00000000 ) |
( (dst >> 8) & 0x00000000ff000000 ) |
( (dst >> 24) & 0x0000000000ff0000 ) |
( (dst >> 40) & 0x000000000000ff00 ) |
( (dst >> 56) & 0x00000000000000ff );
}
#Memory instructions - Load and Store
###############################################################################
#LDDW is the only 16-byte eBPF instruction which consists of two consecutive 8-byte blocks ('struct bpf_insn')
#and interpreted as single instruction which loads 64-bit imm value into dst. Encoding of LDDW:
#LSR MSR
# opcode src dst offset Low 8-byte imm zero-block High 8-byte imm
#bits 8 4 4 16 32 32 32
# So, imm64 consists of concatination of high 8-byte imm and low 8-byte imm.
:LDDW dst, concat is imm & dst & op_ld_st_mode=0x0 & op_ld_st_size=0x3 & op_insn_class=0x0; imm2 [ concat= (imm2 << 32) | ((imm) & 0xFFFFFFFF); ] { dst = concat; }
#BPF_LD_MAP_FD(DST, MAP_FD) -> second LDDW = pseudo LDDW insn used to refer to process-local map_fd
#For each instruction which needs relocation, it inject corresponding file descriptor to imm field.
#As a part of protocol, src_reg is set to BPF_PSEUDO_MAP_FD (which defined as 1) to notify kernel this is a map loading instruction.
:LDDW dst, imm is imm & src=1 & dst & op_ld_st_mode=0x0 & op_ld_st_size=0x3 & op_insn_class=0x0; imm2 { dst = *:8 imm:8; }
:LDABSW dst, imm is imm & dst & op_ld_st_mode=0x1 & op_ld_st_size=0x0 & op_insn_class=0x0 { dst=*:4 imm:8; }
:LDABSH dst, imm is imm & dst & op_ld_st_mode=0x1 & op_ld_st_size=0x1 & op_insn_class=0x0 { dst=*:2 imm:8; }
:LDABSB dst, imm is imm & dst & op_ld_st_mode=0x1 & op_ld_st_size=0x2 & op_insn_class=0x0 { dst=*:1 imm:8; }
:LDABSDW dst, imm is imm & dst & op_ld_st_mode=0x1 & op_ld_st_size=0x3 & op_insn_class=0x0 { dst=*:8 imm:8; }
:LDINDW src, dst, imm is imm & src & dst & op_ld_st_mode=0x2 & op_ld_st_size=0x0 & op_insn_class=0x0 { dst=*:4 (src + imm); }
:LDINDH src, dst, imm is imm & src & dst & op_ld_st_mode=0x2 & op_ld_st_size=0x1 & op_insn_class=0x0 { dst=*:2 (src + imm); }
:LDINDB src, dst, imm is imm & src & dst & op_ld_st_mode=0x2 & op_ld_st_size=0x2 & op_insn_class=0x0 { dst=*:1 (src + imm); }
:LDINDDW src, dst, imm is imm & src & dst & op_ld_st_mode=0x2 & op_ld_st_size=0x3 & op_insn_class=0x0 { dst=*:8 (src + imm); }
:LDXW dst, [src + off] is off & src & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x0 & op_insn_class=0x1 { dst=*:4 (src + off); }
:LDXH dst, [src + off] is off & src & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x1 & op_insn_class=0x1 { dst=*:2 (src + off); }
:LDXB dst, [src + off] is off & src & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x2 & op_insn_class=0x1 { dst=*:1 (src + off); }
:LDXDW dst, [src + off] is off & src & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x3 & op_insn_class=0x1 { dst=*:8 (src + off); }
:STW [dst + off], imm is imm & off & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x0 & op_insn_class=0x2 { *:4 (dst + off)=imm:4; }
:STH [dst + off], imm is imm & off & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x1 & op_insn_class=0x2 { *:2 (dst + off)=imm:2; }
:STB [dst + off], imm is imm & off & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x2 & op_insn_class=0x2 { *:1 (dst + off)=imm:1; }
:STDW [dst + off], imm is imm & off & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x3 & op_insn_class=0x2 { *:8 (dst + off)=imm:8; }
:STXW [dst + off], src is off & src & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x0 & op_insn_class=0x3 { *:4 (dst + off)=src:4; }
:STXH [dst + off], src is off & src & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x1 & op_insn_class=0x3 { *:2 (dst + off)=src:2; }
:STXB [dst + off], src is off & src & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x2 & op_insn_class=0x3 { *:1 (dst + off)=src:1; }
:STXDW [dst + off], src is off & src & dst & op_ld_st_mode=0x3 & op_ld_st_size=0x3 & op_insn_class=0x3 { *:8 (dst + off)=src:8; }
# BPF_ATOMIC
# BPF_ADD:
# BPF_STX | BPF_ATOMIC | BPF_W
:STXXADDW [dst + off], src is imm=0x0 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 { *:4 (dst + off) = *:4 (dst + off) + src:4; }
# BPF_STX | BPF_ATOMIC | BPF_DW
:STXXADDDW [dst + off], src is imm=0x0 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 { *:8 (dst + off) = *:8 (dst + off) + src; }
# BPF_OR:
:STXXADDW [dst + off], src is imm=0x40 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 { *:4 (dst + off) = *:4 (dst + off) | src:4; }
:STXXADDDW [dst + off], src is imm=0x40 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 { *:8 (dst + off) = *:8 (dst + off) | src; }
# BPF_AND:
:STXXADDW [dst + off], src is imm=0x50 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 { *:4 (dst + off) = *:4 (dst + off) & src:4; }
:STXXADDDW [dst + off], src is imm=0x50 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 { *:8 (dst + off) = *:8 (dst + off) & src; }
# BPF_XOR:
:STXXADDW [dst + off], src is imm=0xa0 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 { *:4 (dst + off) = *:4 (dst + off) ^ src:4; }
:STXXADDDW [dst + off], src is imm=0xa0 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 { *:8 (dst + off) = *:8 (dst + off) ^ src; }
# BPF_ADD | BPF_FETCH -> src = atomic_fetch_add(dst + off, src):
:STXXADDW [dst + off], src is imm=0x1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
local tmp:4 = *:4 (dst + off);
*:4 (dst + off) = *:4 (dst + off) + src:4;
src = zext(tmp);
}
:STXXADDDW [dst + off], src is imm=0x1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
local tmp:8 = *:8 (dst + off);
*:8 (dst + off) = *:8 (dst + off) + src;
src = tmp;
}
# BPF_OR | BPF_FETCH -> src = atomic_fetch_or(dst + off, src):
:STXXADDW [dst + off], src is imm=0x41 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
local tmp:4 = *:4 (dst + off);
*:4 (dst + off) = *:4 (dst + off) | src:4;
src = zext(tmp);
}
:STXXADDDW [dst + off], src is imm=0x41 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
local tmp:8 = *:8 (dst + off);
*:8 (dst + off) = *:8 (dst + off) | src;
src = tmp;
}
# BPF_AND | BPF_FETCH -> src = atomic_fetch_and(dst + off, src):
:STXXADDW [dst + off], src is imm=0x51 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
local tmp:4 = *:4 (dst + off);
*:4 (dst + off) = *:4 (dst + off) & src:4;
src = zext(tmp);
}
:STXXADDDW [dst + off], src is imm=0x51 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
local tmp:8 = *:8 (dst + off);
*:8 (dst + off) = *:8 (dst + off) & src;
src = tmp;
}
# BPF_XOR | BPF_FETCH -> src = atomic_fetch_xor(dst + off, src):
:STXXADDW [dst + off], src is imm=0xa1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
local tmp:4 = *:4 (dst + off);
*:4 (dst + off) = *:4 (dst + off) ^ src:4;
src = zext(tmp);
}
:STXXADDDW [dst + off], src is imm=0xa1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
local tmp:8 = *:8 (dst + off);
*:8 (dst + off) = *:8 (dst + off) ^ src;
src = tmp;
}
# BPF_XCHG -> src_reg = atomic_xchg(dst + off, src):
:STXXADDW [dst + off], src is imm=0xe1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
local tmp:4 = *:4 (dst + off);
*:4 (dst + off) = src:4;
src = zext(tmp);
}
:STXXADDDW [dst + off], src is imm=0xe1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
local tmp:8 = *:8 (dst + off);
*:8 (dst + off) = src;
src = tmp;
}
# BPF_CMPXCHG -> R0 = atomic_cmpxchg(dst + off, R0, src):
:STXXADDW [dst + off], src is imm=0xf1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x0 & op_insn_class=0x3 {
local tmp:4 = *:4 (dst + off);
if (R0:4 == tmp) goto <equal>;
R0 = zext(tmp);
<equal>
*:4 (dst + off) = src:4;
}
:STXXADDDW [dst + off], src is imm=0xf1 & off & src & dst & op_ld_st_mode=0x6 & op_ld_st_size=0x3 & op_insn_class=0x3 {
local tmp:8 = *:8 (dst + off);
if (R0 == tmp) goto <equal>;
R0 = tmp;
<equal>
*:8 (dst + off) = src;
}
#Jump instructions (BPF_JMP, BPF_JMP32)
###############################################################################
joff: reloc is off [ reloc = inst_next + off * 8; ] { export *:8 reloc; }
:JA joff is joff & op_alu_jmp_opcode=0x0 & op_alu_jmp_source=0 & op_insn_class=0x5 {
goto joff;
}
:JEQ dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x1 & op_alu_jmp_source=0 & op_insn_class=0x5 {
if (dst == imm) goto joff;
}
:JEQ dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x1 & op_alu_jmp_source=1 & op_insn_class=0x5 {
if (dst == src) goto joff;
}
:JEQ dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x1 & op_alu_jmp_source=0 & op_insn_class=0x6 {
if (dst:4 == imm:4) goto joff;
}
:JEQ dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x1 & op_alu_jmp_source=1 & op_insn_class=0x6 {
if (dst:4 == src:4) goto joff;
}
:JGT dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x2 & op_alu_jmp_source=0 & op_insn_class=0x5 {
if (dst > imm) goto joff;
}
:JGT dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x2 & op_alu_jmp_source=1 & op_insn_class=0x5 {
if (dst > src) goto joff;
}
:JGT dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x2 & op_alu_jmp_source=0 & op_insn_class=0x6 {
if (dst:4 > imm:4) goto joff;
}
:JGT dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x2 & op_alu_jmp_source=1 & op_insn_class=0x6 {
if (dst:4 > src:4) goto joff;
}
:JGE dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x3 & op_alu_jmp_source=0 & op_insn_class=0x5 {
if (dst >= imm) goto joff;
}
:JGE dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x3 & op_alu_jmp_source=1 & op_insn_class=0x5 {
if (dst >= src) goto joff;
}
:JGE dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x3 & op_alu_jmp_source=0 & op_insn_class=0x6 {
if (dst:4 >= imm:4) goto joff;
}
:JGE dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x3 & op_alu_jmp_source=1 & op_insn_class=0x6 {
if (dst:4 >= src:4) goto joff;
}
:JLT dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0xa & op_alu_jmp_source=0 & op_insn_class=0x5 {
if (dst < imm) goto joff;
}
:JLT dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0xa & op_alu_jmp_source=1 & op_insn_class=0x5 {
if (dst < src) goto joff;
}
:JLT dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0xa & op_alu_jmp_source=0 & op_insn_class=0x6 {
if (dst:4 < imm:4) goto joff;
}
:JLT dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0xa & op_alu_jmp_source=1 & op_insn_class=0x6 {
if (dst:4 < src:4) goto joff;
}
:JLE dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0xb & op_alu_jmp_source=0 & op_insn_class=0x5 {
if (dst <= imm) goto joff;
}
:JLE dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0xb & op_alu_jmp_source=1 & op_insn_class=0x5 {
if (dst <= src) goto joff;
}
:JLE dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0xb & op_alu_jmp_source=0 & op_insn_class=0x6 {
if (dst:4 <= imm:4) goto joff;
}
:JLE dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0xb & op_alu_jmp_source=1 & op_insn_class=0x6 {
if (dst:4 <= src:4) goto joff;
}
:JNE dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x5 & op_alu_jmp_source=0 & op_insn_class=0x5 {
if (dst != imm) goto joff;
}
:JNE dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x5 & op_alu_jmp_source=1 & op_insn_class=0x5 {
if (dst != src) goto joff;
}
:JNE dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x5 & op_alu_jmp_source=0 & op_insn_class=0x6 {
if (dst:4 != imm:4) goto joff;
}
:JNE dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x5 & op_alu_jmp_source=1 & op_insn_class=0x6 {
if (dst:4 != src:4) goto joff;
}
:JSET dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x4 & op_alu_jmp_source=0 & op_insn_class=0x5 {
if ((dst & imm) != 0) goto joff;
}
:JSET dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x4 & op_alu_jmp_source=1 & op_insn_class=0x5 {
if ((dst & src) != 0) goto joff;
}
:JSET dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x4 & op_alu_jmp_source=0 & op_insn_class=0x6 {
if ((dst:4 & imm:4) != 0) goto joff;
}
:JSET dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x4 & op_alu_jmp_source=1 & op_insn_class=0x6 {
if ((dst:4 & src:4) != 0) goto joff;
}
:JSGT dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x6 & op_alu_jmp_source=0 & op_insn_class=0x5 {
if (dst s> imm) goto joff;
}
:JSGT dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x6 & op_alu_jmp_source=1 & op_insn_class=0x5 {
if (dst s> src) goto joff;
}
:JSGT dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x6 & op_alu_jmp_source=0 & op_insn_class=0x6 {
if (dst:4 s> imm:4) goto joff;
}
:JSGT dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x6 & op_alu_jmp_source=1 & op_insn_class=0x6 {
if (dst:4 s> src:4) goto joff;
}
:JSGE dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x7 & op_alu_jmp_source=0 & op_insn_class=0x5 {
if (dst s>= imm) goto joff;
}
:JSGE dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x7 & op_alu_jmp_source=1 & op_insn_class=0x5 {
if (dst s>= src) goto joff;
}
:JSGE dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0x7 & op_alu_jmp_source=0 & op_insn_class=0x6 {
if (dst:4 s>= imm:4) goto joff;
}
:JSGE dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0x7 & op_alu_jmp_source=1 & op_insn_class=0x6 {
if (dst:4 s>= src:4) goto joff;
}
:JSLT dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0xc & op_alu_jmp_source=0 & op_insn_class=0x5 {
if (dst s< imm) goto joff;
}
:JSLT dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0xc & op_alu_jmp_source=1 & op_insn_class=0x5 {
if (dst s< src) goto joff;
}
:JSLT dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0xc & op_alu_jmp_source=0 & op_insn_class=0x6 {
if (dst:4 s< imm:4) goto joff;
}
:JSLT dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0xc & op_alu_jmp_source=1 & op_insn_class=0x6 {
if (dst:4 s< src:4) goto joff;
}
:JSLE dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0xd & op_alu_jmp_source=0 & op_insn_class=0x5 {
if (dst s<= imm) goto joff;
}
:JSLE dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0xd & op_alu_jmp_source=1 & op_insn_class=0x5 {
if (dst s<= src) goto joff;
}
:JSLE dst, imm, joff is imm & joff & dst & op_alu_jmp_opcode=0xd & op_alu_jmp_source=0 & op_insn_class=0x6 {
if (dst:4 s<= imm:4) goto joff;
}
:JSLE dst, src, joff is joff & src & dst & op_alu_jmp_opcode=0xd & op_alu_jmp_source=1 & op_insn_class=0x6 {
if (dst:4 s<= src:4) goto joff;
}
SysCall: imm is imm { export *[syscall]:1 imm; }
:CALL SysCall is imm & src=0 & op_alu_jmp_opcode=0x8 & op_alu_jmp_source=0 & op_insn_class=0x5 & SysCall {
call SysCall;
}
disp32: reloc is imm [ reloc = inst_next + imm; ] { export *:4 reloc; }
:CALL disp32 is imm & src=1 & op_alu_jmp_opcode=0x8 & op_alu_jmp_source=0 & op_insn_class=0x5 & disp32 {
call disp32;
}
:EXIT is op_alu_jmp_opcode=0x9 & op_alu_jmp_source=0 & op_insn_class=0x5 { return [*:8 R10]; }

View File

@@ -0,0 +1,3 @@
define endian=little;
@include "eBPF.sinc"

View File

@@ -0,0 +1,49 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.bin.format.elf.extend;
import ghidra.app.util.bin.format.elf.*;
import ghidra.program.model.lang.*;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
public class eBPF_ElfExtension extends ElfExtension {
@Override
public boolean canHandle(ElfHeader elf) {
return elf.e_machine() == ElfConstants.EM_BPF && elf.is64Bit();
}
@Override
public boolean canHandle(ElfLoadHelper elfLoadHelper) {
Language language = elfLoadHelper.getProgram().getLanguage();
return canHandle(elfLoadHelper.getElfHeader()) && "eBPF".equals(language.getProcessor().toString()) &&
language.getLanguageDescription().getSize() == 64;
}
@Override
public String getDataTypeSuffix() {
return "eBPF";
}
@Override
public void processGotPlt(ElfLoadHelper elfLoadHelper, TaskMonitor monitor) throws CancelledException {
if (!canHandle(elfLoadHelper)) {
return;
}
super.processGotPlt(elfLoadHelper, monitor);
}
}

View File

@@ -0,0 +1,47 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.bin.format.elf.relocation;
import ghidra.app.plugin.core.reloc.RelocationFixupHandler;
import ghidra.app.util.opinion.ElfLoader;
import ghidra.program.model.address.Address;
import ghidra.program.model.lang.Language;
import ghidra.program.model.lang.Processor;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.reloc.Relocation;
import ghidra.program.model.util.CodeUnitInsertionException;
public class ElfeBPFRelocationFixupHandler extends RelocationFixupHandler {
@Override
public boolean processRelocation(Program program, Relocation relocation, Address oldImageBase,
Address newImageBase) throws MemoryAccessException, CodeUnitInsertionException {
return process64BitRelocation(program, relocation, oldImageBase, newImageBase);
}
@Override
public boolean handlesProgram(Program program) {
if (!ElfLoader.ELF_NAME.equals(program.getExecutableFormat())) {
return false;
}
Language language = program.getLanguage();
if (language.getLanguageDescription().getSize() != 64) {
return false;
}
Processor processor = language.getProcessor();
return (processor.equals(Processor.findOrPossiblyCreateProcessor("eBPF")));
}
}

View File

@@ -0,0 +1,36 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.bin.format.elf.relocation;
public class eBPF_ElfRelocationConstants {
/** No operation needed */
public static final int R_BPF_NONE = 0;
/** S + A */
public static final int R_BPF_64_64 = 1;
/** S + A */
public static final int R_BPF_64_ABS64 = 2;
/** S + A */
public static final int R_BPF_64_ABS32 = 3;
/** S + A */
public static final int R_BPF_64_NODYLD32 = 4;
/** (S + A) / 8 - 1 */
public static final int R_BPF_64_32 = 10;
private eBPF_ElfRelocationConstants() {
// no construct
}
}

View File

@@ -0,0 +1,111 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.bin.format.elf.relocation;
import ghidra.app.util.bin.format.elf.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.*;
import ghidra.program.model.reloc.RelocationResult;
import ghidra.program.model.reloc.Relocation.Status;
import ghidra.program.model.symbol.SymbolTable;
import ghidra.util.exception.NotFoundException;
public class eBPF_ElfRelocationHandler extends ElfRelocationHandler {
@Override
public boolean canRelocate(ElfHeader elf) {
return elf.e_machine() == ElfConstants.EM_BPF;
}
@Override
public RelocationResult relocate(ElfRelocationContext elfRelocationContext, ElfRelocation relocation,
Address relocationAddress) throws MemoryAccessException, NotFoundException {
ElfHeader elf = elfRelocationContext.getElfHeader();
if (elf.e_machine() != ElfConstants.EM_BPF) {
return RelocationResult.FAILURE;
}
Program program = elfRelocationContext.getProgram();
Memory memory = program.getMemory();
int type = relocation.getType();
if (type == eBPF_ElfRelocationConstants.R_BPF_NONE) {
return RelocationResult.SKIPPED;
}
String section_name = elfRelocationContext.relocationTable.getSectionToBeRelocated().getNameAsString();
if (section_name.toString().contains("debug")) {
return RelocationResult.SKIPPED;
}
SymbolTable table = program.getSymbolTable();
int symbolIndex = relocation.getSymbolIndex();
ElfSymbol symbol = elfRelocationContext.getSymbol(symbolIndex);
String symbolName = symbol.getNameAsString();
Address symbolAddr = table.getSymbols(symbolName).next().getAddress();
long new_value = 0;
int byteLength = 4; // most relocations affect 4-bytes
try {
switch (type){
case eBPF_ElfRelocationConstants.R_BPF_64_64: {
new_value = symbolAddr.getAddressableWordOffset();
Byte dst = memory.getByte(relocationAddress.add(0x1));
memory.setLong(relocationAddress.add(0x4), new_value);
memory.setByte(relocationAddress.add(0x1), (byte)(dst + 0x10));
break;
}
case eBPF_ElfRelocationConstants.R_BPF_64_32: {
// if we have, e.g, non-static function, it will be marked in the relocation table
// and indexed in the symbol table and it's easy to calculate the pc-relative offset
long instr_next = relocationAddress.add(0x8).getAddressableWordOffset();
if (symbol.isFunction()) {
new_value = symbolAddr.getAddressableWordOffset();
int offset = (int)(new_value - instr_next);
memory.setInt(relocationAddress.add(0x4), offset);
} else if (symbol.isSection()) {
if (memory.getInt(relocationAddress) == 0x1085) {
ElfSectionHeader sectionHeader = elfRelocationContext.getElfHeader().getSection(symbolName);
long section_start = program.getImageBase().getOffset() + sectionHeader.getAddress();
// getting call instruction offset (current imm)
int current_imm = memory.getInt(relocationAddress.add(0x4));
// calculate the call target section offset
// according to formula in "kernel.org" docs: https://www.kernel.org/doc/html/latest/bpf/llvm_reloc.html
int func_sec_offset = (current_imm + 1) * 8;
long func_addr = section_start + func_sec_offset;
int offset = (int)(func_addr - instr_next);
memory.setInt(relocationAddress.add(0x4), offset);
}
}
break;
}
default: {
if (symbolIndex == 0) {
markAsWarning(program, relocationAddress,
Long.toString(type), "applied relocation with symbol-index of 0", elfRelocationContext.getLog());
}
return RelocationResult.UNSUPPORTED;
}
}
} catch (NullPointerException e) { }
return new RelocationResult(Status.APPLIED, byteLength);
}
}