how to make use the .rela.dyn to trigger elf loader for aarch64? - linux

I have implemented packer of x86_64 shared library.
Briefly,
a simple xor-loader is injected to a shared library (by creating a new section)
the rela.dyn act as an entrypoint for the shared library
the rela.dyn entry is patched such that it points to the address of the loader.
once the shared library is called, the xor-loader is triggered and decrypt the .text section.
The mechanism works fine for the x86_64 shared library.
The rela.dyn tricks is borrowed from
https://github.com/0xN3utr0n/Noteme/blob/master/injection.c
However, this mechanism failed on aarch64.
I found that
if I xor-ed the .text section, the xor-loader is bypassed
I got Illegal instruction (core dumped), since the .text section has not been decrypted by the xor-loader. (confirmed by inspecting the .text section by gdb)
I have the loader objdump-ed, the loader is intact.
if I don't xor the .text section, the xor-loader is called and work normally. (But the decryption is wrong, since the .text section has not been xor-ed beforehand).
Question:
What could have possible went wrong in aarch64 ?
The result of readelf for aarch64 shared library is provided below.
libtest.so is the library before packing.
While libtest_packed.so is the library after packing.
Here is the result of readelf --relocs libtest.so
Relocation section '.rela.dyn' at offset 0x550 contains 7 entries:
000000010df0 000000000403 R_AARCH64_RELATIV 780
000000010df8 000000000403 R_AARCH64_RELATIV 738
000000011018 000000000403 R_AARCH64_RELATIV 11018
000000010fc8 000300000401 R_AARCH64_GLOB_DA 0000000000000000 _ITM_deregisterTMClone + 0
000000010fd0 000400000401 R_AARCH64_GLOB_DA 0000000000000000 __cxa_finalize#GLIBC_2.17 + 0
000000010fd8 000500000401 R_AARCH64_GLOB_DA 0000000000000000 __gmon_start__ + 0
000000010fe0 000700000401 R_AARCH64_GLOB_DA 0000000000000000 _ITM_registerTMCloneTa + 0
the functions corresponding to the first 3 entries are:
0000000000000780 t frame_dummy
0000000000000738 t __do_global_dtors_aux
000000000011018 d __dso_handle
here is the result of readelf --relocs libtest_packed.so
Relocation section '.rela.dyn' at offset 0x550 contains 7 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000010df0 000000000403 R_AARCH64_RELATIV 11028
000000010df8 000000000403 R_AARCH64_RELATIV 738
000000011018 000000000403 R_AARCH64_RELATIV 11018
000000010fc8 000300000401 R_AARCH64_GLOB_DA 0000000000000000 _ITM_deregisterTMClone + 0
000000010fd0 000400000401 R_AARCH64_GLOB_DA 0000000000000000 __cxa_finalize#GLIBC_2.17 + 0
000000010fd8 000500000401 R_AARCH64_GLOB_DA 0000000000000000 __gmon_start__ + 0
000000010fe0 000700000401 R_AARCH64_GLOB_DA 0000000000000000 _ITM_registerTMCloneTa + 0
As you can see, the first entry is overwritten by the address of the loader.

Related

why virtual address of LOAD program header and runtime virtual address shown by gdb is different?

I've been trying to understand elf file format and on elf format documentation, VirtAddr of LOAD header should be the virtual address of the loaded segment. But gdb memmap shows segments to be loaded at different virt address.
$ readelf -l
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000560 0x0000000000000560 R 0x1000
LOAD 0x0000000000001000 0x0000000000001000 0x0000000000001000
0x00000000000001e5 0x00000000000001e5 R E 0x1000
LOAD 0x0000000000002000 0x0000000000002000 0x0000000000002000
0x0000000000000118 0x0000000000000118 R 0x1000
LOAD 0x0000000000002de8 0x0000000000003de8 0x0000000000003de8
0x0000000000000248 0x0000000000000250 RW 0x1000
gdb memmap
Entry point: 0x555555555040
0x00005555555542a8 - 0x00005555555542c4 is .interp
0x00005555555542c4 - 0x00005555555542e4 is .note.ABI-tag
0x00005555555542e4 - 0x0000555555554308 is .note.gnu.build-id
0x0000555555554308 - 0x0000555555554324 is .gnu.hash
0x0000555555554328 - 0x00005555555543d0 is .dynsym
0x00005555555543d0 - 0x0000555555554454 is .dynstr
0x0000555555554454 - 0x0000555555554462 is .gnu.version
0x0000555555554468 - 0x0000555555554488 is .gnu.version_r
0x0000555555554488 - 0x0000555555554548 is .rela.dyn
0x0000555555554548 - 0x0000555555554560 is .rela.plt
0x0000555555555000 - 0x000055555555501b is .init
0x0000555555555020 - 0x0000555555555040 is .plt
0x0000555555555040 - 0x00005555555551d5 is .text
0x00005555555551d8 - 0x00005555555551e5 is .fini
0x0000555555556000 - 0x000055555555600a is .rodata
0x000055555555600c - 0x0000555555556040 is .eh_frame_hdr
0x0000555555556040 - 0x0000555555556118 is .eh_frame
0x0000555555557de8 - 0x0000555555557df0 is .init_array
0x0000555555557df0 - 0x0000555555557df8 is .fini_array
0x0000555555557df8 - 0x0000555555557fd8 is .dynamic
0x0000555555557fd8 - 0x0000555555558000 is .got
0x0000555555558000 - 0x0000555555558020 is .got.plt
0x0000555555558020 - 0x0000555555558030 is .data
0x0000555555558030 - 0x0000555555558038 is .bss
VirtAddr of LOAD header should be the virtual address of the loaded segment.
This is only true for ELF images of type ET_EXEC.
But you have an ELF image of type ET_DYN (probably a position independent executable), and these are relocated at runtime to a different virtual address.

What are the meanings of columns shown by readelf, while inspecting Section Headers?

Can someone explain the meaning of these columns?
I use readelf to read a ELF file and can't find any rellevant info (like for objdump for example) about Section Headers columns.
For example what are 'ES', 'Lk' and 'Info' ?
What are all available flags in 'Flg' ?
'Al' means alignment ?
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .data PROGBITS 3ffe8000 000120 0004fa 00 WA 0 0 16
[ 2] .rodata PROGBITS 3ffe8500 000620 000ea4 00 A 0 0 16
[ 3] .bss NOBITS 3ffe93a8 0014c8 0089d0 00 WA 0 0 16
...
...
Thanks in advance,
Here is a link to the System V Application Binary Interface where is a section header defined:
typedef struct {
Elf64_Word sh_name;
Elf64_Word sh_type;
Elf64_Xword sh_flags;
Elf64_Addr sh_addr;
Elf64_Off sh_offset;
Elf64_Xword sh_size;
Elf64_Word sh_link;
Elf64_Word sh_info;
Elf64_Xword sh_addralign;
Elf64_Xword sh_entsize;
} Elf64_Shdr;
es is actually sh_entsize, it specifies the size of an entry that the header contains (example: size of the symbol forSHT_SYMTAB and SHT_DYNSYN sections)
lk is sh_link, info is sh_info and their meaning depends on the section type
(example: sh_link contains section header index with associated string table for SHT_SYMTAB and SHT_DYNSYN sections, sh_info is usually also just header table index)
These are flags defined by the standard:
SHF_WRITE 0x1
SHF_ALLOC 0x2
SHF_EXECINSTR 0x4
SHF_MERGE 0x10
SHF_STRINGS 0x20
SHF_INFO_LINK 0x40
SHF_LINK_ORDER 0x80
SHF_OS_NONCONFORMING 0x100
SHF_GROUP 0x200
SHF_TLS 0x400
SHF_COMPRESSED 0x800
and as you wrote al is sh_align.
If you want precise description of the structure check the link.

Unable to get the RoCC accelerator built with the default Accumulator example for zed board

Tried building the RoCC accelerator default accumulator example for zed board, but getting an error of "illegal instruction"
I tried the below config in the configs.scala file:-
class WithAccumRocc extends Config(
(pname,site,here) => pname match {
case RoccNMemChannels => 1
case RoccMaxTaggedMemXacts => 0
case BuildRoCC => {
Some((p: Parameters) =>
Module(new AccumulatorExample()(p.alterPartial({ case CoreName => "AccumRocc" }))))
}
}
)
class WithRoCCConfig extends Config(new WithAccumRocc ++ new DefaultFPGAConfig)
The bitstream was generated successfully but when i ran the dummy_rocc_test binary generated from the example given in riscv-isa-sim, i got the following error on the zed board.
root#zynq:~# ./fesvr-zynq pk /sdcard/Custom\ elfs/dummy_rocc
z 0000000000000000 ra 0000000000010044 sp 000000000feffb10 gp 0000000000017880
tp 0000000000000000 t0 0000000000017178 t1 0000000000017178 t2 0000000000000000
s0 000000000feffb40 s1 0000000000000000 a0 0000000000000001 a1 000000000feffb48
a2 0000000000000000 a3 0000000000000000 a4 0000000000000000 a5 000000000000007b
a6 0000000000000000 a7 0000000000000001 s2 0000000000000000 s3 0000000000000000
s4 0000000000000000 s5 0000000000000000 s6 0000000000000000 s7 0000000000000000
s8 0000000000000000 s9 0000000000000000 sA 0000000000000000 sB 0000000000000000
t3 0000000000000000 t4 0000000000000000 t5 0000000000000000 t6 0000000000000000
pc 0000000000010168 va 0000000000010168 insn 0027e00b sr 8000000000003008
An illegal instruction was executed!
Any help here would be greatly appreciated.
P.S. :- The dummy_rocc_test example is working fine with spike and has been compiled with riscv64-unknown-elf-gcc
Hello guys this issue has been resolved, once the change was made the rocket needs to be built with the new pga configuration and the vivid project must also be updated accordingly in order to generate the new bitstream.

Segmentation fault when running binaries compiled using riscv64-unknown-linux-gnu-gcc in spike

#include<stdio.h>
int main()
{
int src = 5;
int dst = 0;
asm ("mv %0,%1":"=X"(dst):"r"(src));
asm("mv a0,a1");
printf(" %d\n", dst);
return 0;
}
prashantravi#ubuntu:~/rocket-chip$ riscv64-unknown-linux-gnu-gcc -o asm_test asm_test.c
prashantravi#ubuntu:~/rocket-chip$ spike riscv/bin/pk asm_test
z 0000000000000000 ra 0000000000000000 sp 00000000fefffb50 gp 0000000000801fb8
tp 0000000000000000 t0 0000000000000000 t1 0000000000000008 t2 00000000008012e0
s0 0000000000000000 s1 0000000000000000 a0 0000000000800430 a1 0000000000000001
a2 00000000fefffb58 a3 0000000000800484 a4 0000000000800514 a5 0000000000000000
a6 00000000fefffb50 a7 0000000000000000 s2 0000000000000000 s3 0000000000000000
s4 0000000000000000 s5 0000000000000000 s6 0000000000000000 s7 0000000000000000
s8 0000000000000000 s9 0000000000000000 sA 0000000000000000 sB 0000000000000000
t3 ffffffffffffffff t4 0000000000000000 t5 0000000000000000 t6 0000000000000000
pc fffffffffffffffe va fffffffffffffffe insn ffffffff sr 8000000000003008
User fetch segfault # 0xfffffffffffffffe
I am getting the above error when i am compiling programs using riscv64-unknown-linux-gnu-gcc in spike.
The same code executes perfectly when run with riscv64-unknown-elf gcc
You can't run dynamically linked programs on the proxy-kernel.
You must statically link your programs if you are going to run them on the proxy-kernel. This is performed by default using the riscv64-unknown-elf-gcc compiler. If you are going to use the riscv64-unknown-linux-gnu-gcc compiler, you must either pass -static or you must run it on the Linux kernel.
$ riscv64-unknown-elf-gcc -o asm_test asm_test.c [or...]
$ riscv64-unknown-linux-gnu-gcc -static -o asm_test asm_test.c
$ spike pk asm_test
In more detail, how I debugged this before I remembered the above limitation:
By running $ spike -d pk asm_test 2> output.txt, we can see the trace of the program:
<snippet>
374618 : core 0: 0x0000000000800320 (0x00002197) auipc gp, 0x2
374619 : core 0: 0x0000000000800324 (0xc9818193) addi gp, gp, -872
374620 : core 0: 0x0000000000800328 (0x00050793) mv a5, a0
374621 : core 0: 0x000000000080032c (0x00000517) auipc a0, 0x0
374622 : core 0: 0x0000000000800330 (0x10450513) addi a0, a0, 260
374623 : core 0: 0x0000000000800334 (0x00013583) ld a1, 0(sp)
374624 : core 0: 0x0000000000800338 (0x00810613) addi a2, sp, 8
374625 : core 0: 0x000000000080033c (0xff017113) andi sp, sp, -16
374626 : core 0: 0x0000000000800340 (0x00000697) auipc a3, 0x0
374627 : core 0: 0x0000000000800344 (0x14468693) addi a3, a3, 324
374628 : core 0: 0x0000000000800348 (0x00000717) auipc a4, 0x0
374629 : core 0: 0x000000000080034c (0x1cc70713) addi a4, a4, 460
374630 : core 0: 0x0000000000800350 (0x00010813) mv a6, sp
374631 : core 0: 0x0000000000800354 (0xfbdff06f) j pc - 0x44
374632 : core 0: 0x0000000000800310 (0x00001e17) auipc t3, 0x1
374633 : core 0: 0x0000000000800314 (0x498e3e03) ld t3, 1176(t3)
374634 : core 0: 0x0000000000800318 (0x000e0367) jalr t1, t3, 0
374635 : core 0: 0x00000000008002e0 (0x00001397) auipc t2, 0x1
374636 : core 0: 0x00000000008002e4 (0x41c30333) sub t1, t1, t3
374637 : core 0: 0x00000000008002e8 (0x4b03be03) ld t3, 1200(t2)
374638 : core 0: 0x00000000008002ec (0xfd430313) addi t1, t1, -44
374639 : core 0: 0x00000000008002f0 (0x4b038293) addi t0, t2, 1200
374640 : core 0: 0x00000000008002f4 (0x00135313) srli t1, t1, 1
374641 : core 0: 0x00000000008002f8 (0x0082b283) ld t0, 8(t0)
374642 : core 0: 0x00000000008002fc (0x000e0067) jr t3
374643 : core 0: exception trap_instruction_access_fault, epc 0xfffffffffffffffe
374644 core 0: 0x0000000000000100 (0x34011173) csrrw sp, mscratch, sp
374645 : core 0: 0x0000000000000104 (0x04a13823) sd a0, 80(sp)
374646 : core 0: 0x0000000000000108 (0x04b13c23) sd a1, 88(sp)
If you objdump asm_test, you'll see that it's in _start, then __libc_start_main, then __libc_start_main#plt (0x800310), and then _PROCEDURE_LINKAGE_TABLE_ (0x8002e0).
From there, it attempts a jr, which jumps to 0xfffffffffffffffe, which is a misaligned fetch address. Hence the crash.

Where is the relocation information in the ELF format?

Quoting "Linkers and Loaders" in the Loaders part
"load-time relocation is far simpler than link-time relocation,
because the entire program is relocated as a unit. [...]
After reading the program into memory, the loader consults
the relocation items in the object file and fixes up the memory
locations to which the items point"
Maybe I misunderstood this point and this is only in some architectures, but my question is: where in the ELF format is specified which items need relocation at load time? how can I inquire for this list?
Relocations are to be found in special relocation sections in the ELF file. You can use the readelf --sections command to find out what sections are there in an executable or a shared library and those of type REL contain relocation instructions. The content of those relocation sections can be displayed using readelf --relocs. For example:
$ readelf --relocs /bin/ls
Relocation section '.rela.dyn' at offset 0x16c8 contains 5 entries:
Offset Info Type Sym. Value Sym. Name + Addend
00000061afd8 000c00000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
00000061b540 006d00000005 R_X86_64_COPY 000000000061b540 optind + 0
00000061b548 006e00000005 R_X86_64_COPY 000000000061b548 optarg + 0
00000061b550 006a00000005 R_X86_64_COPY 000000000061b550 stderr + 0
00000061b560 006600000005 R_X86_64_COPY 000000000061b560 stdout + 0
Relocation section '.rela.plt' at offset 0x1740 contains 99 entries:
Offset Info Type Sym. Value Sym. Name + Addend
00000061b000 000100000007 R_X86_64_JUMP_SLO 0000000000000000 strcoll + 0
00000061b008 000200000007 R_X86_64_JUMP_SLO 0000000000000000 mktime + 0
...
The .rela.dyn section contains references to references in the program's code of code or data symbols that have to be relocated at load time while .rela.plt contains mostly jump slots that are used to call functions in shared objects. Note that usually only shared objects are compiled as position-independent code while the usual executables are not. This is due to the fact that PIC code is a bit slower than non-PIC code.

Resources