Commit | Line | Data |
---|---|---|
1cac41cb MB |
1 | #include <stdio.h> |
2 | #include <stdlib.h> | |
3 | #include <elf.h> | |
4 | ||
5 | typedef unsigned long long uint64; | |
6 | ||
7 | //SHIFT must be 16KB / 2MB align according to KALSR config | |
8 | ||
9 | #define SHIFT(idx) ((uint64)(idx) * 0x4000) | |
10 | ||
11 | #ifndef R_AARCH64_RELATIVE | |
12 | #define R_AARCH64_RELATIVE 1027 | |
13 | #endif | |
14 | #ifndef R_AARCH64_ABS64 | |
15 | #define R_AARCH64_ABS64 257 | |
16 | #endif | |
17 | ||
18 | /* | |
19 | * The rela section uses the VA | |
20 | * the VA to file offset is: | |
21 | */ | |
22 | uint64 va_to_file; | |
23 | int patch_rela(char *, uint64, uint64, uint64, uint64, uint64, uint64, uint64, uint64); | |
24 | int main(int argc, char *argv[]){ | |
25 | uint64 rs_offset = 0, re_offset = 0, ds_offset = 0; | |
26 | int index; | |
27 | char *file = NULL; | |
28 | int ret; | |
29 | if (argc != 11) | |
30 | { | |
31 | printf ("\nUsage : \n"); | |
32 | printf ("kaslr_fips vmlinux_file reloc_start_addr reloc_end_addr dynsym_addr index first_crypto_rodata last_crypto_rodata first_fmp_rodata last_fmp_rodata"); | |
33 | printf ("\n"); | |
34 | return -1; | |
35 | } | |
36 | ||
37 | file = argv[1]; | |
38 | rs_offset = atol(argv[2]); | |
39 | re_offset = atol(argv[3]); | |
40 | ds_offset = atol(argv[4]); | |
41 | index = atoi(argv[5]); | |
42 | va_to_file = atol(argv[10]); | |
43 | ||
44 | if( !file || !rs_offset || !re_offset || !ds_offset ) | |
45 | { | |
46 | printf ("kaslr_fips vmlinux_file reloc_start_addr reloc_end_addr dynsym_add\n"); | |
47 | printf ("kaslr_fips index %d\n", index); | |
48 | return -1; | |
49 | } | |
50 | ||
51 | // printf("----- start patching %s with reloc_s %llx reloc_e %llx dynsym_s %llx index %d----\n", file, rs_offset, re_offset, ds_offset, index); | |
52 | ret = patch_rela(file, rs_offset, re_offset, ds_offset, SHIFT(index), atol(argv[6]), atol(argv[7]), atol(argv[8]), atol(argv[9])); | |
53 | if(ret) return ret; | |
54 | // printf("----- end patching %s -----\n", file); | |
55 | return 0; | |
56 | } | |
57 | ||
58 | /* | |
59 | * rela_start: relocation section start in the vmlinux | |
60 | * rela_end | |
61 | * dynsym_start | |
62 | */ | |
63 | ||
64 | int patch_rela(char *file, uint64 rela_start, uint64 rela_end, uint64 dynsym_start, uint64 offset, uint64 first_crypto_rodata, uint64 last_crypto_rodata, uint64 first_fmp_rodata, uint64 last_fmp_rodata){ | |
65 | uint64 rs_offset = rela_start - va_to_file; | |
66 | uint64 re_offset = rela_end - va_to_file; | |
67 | uint64 ds_offset = dynsym_start - va_to_file; | |
68 | ||
69 | FILE *fp = NULL; | |
70 | ||
71 | fp = fopen(file, "r+"); | |
72 | if (NULL == fp){ | |
73 | printf ("Unable to open file : %s", file); | |
74 | return -1; | |
75 | } | |
76 | ||
77 | Elf64_Rela rela_entry; | |
78 | Elf64_Sym sym_entry; | |
79 | uint64 addr = 0, value = 0; | |
80 | size_t read_size = 0; | |
81 | for (; rs_offset < re_offset; rs_offset += sizeof(Elf64_Rela)){ | |
82 | //seek and read the rela entry | |
83 | if(0 != fseek(fp, rs_offset, SEEK_SET)){ | |
84 | fclose(fp); | |
85 | return -1; | |
86 | } | |
87 | ||
88 | read_size = fread((void*) &rela_entry, sizeof(rela_entry), 1, fp); | |
89 | if(0 == read_size) continue; | |
90 | /*printf("%llx, %llx\n", ELF64_R_TYPE(rela_entry.r_info), R_AARCH64_RELATIVE);*/ | |
91 | addr = rela_entry.r_offset; | |
92 | if (0x0 == addr) continue; | |
93 | ||
94 | if ( !((addr >= first_crypto_rodata && addr <= last_crypto_rodata) || | |
95 | (addr >= first_fmp_rodata && addr <= last_fmp_rodata))) | |
96 | continue; | |
97 | ||
98 | if (ELF64_R_TYPE(rela_entry.r_info) == R_AARCH64_RELATIVE) { | |
99 | value = offset + rela_entry.r_addend; | |
100 | ||
101 | } else if(ELF64_R_TYPE(rela_entry.r_info) == R_AARCH64_ABS64) { | |
102 | uint64 sym_index = ELF64_R_SYM(rela_entry.r_info); | |
103 | uint64 sym_offset = ds_offset + sym_index * (sizeof(Elf64_Sym)); | |
104 | ||
105 | //seek to the start of the symbol table entry | |
106 | if (0 !=fseek(fp, sym_offset, SEEK_SET)){ | |
107 | fclose(fp); | |
108 | return -1; | |
109 | } | |
110 | read_size = fread((void*) &sym_entry, sizeof(sym_entry), 1, fp); | |
111 | if(0 == read_size) continue; | |
112 | ||
113 | value = sym_entry.st_value + rela_entry.r_addend + offset; | |
114 | } else { | |
115 | // printf("Try to patch none supported type %llx\n", (uint64)ELF64_R_TYPE(rela_entry.r_info)); | |
116 | } | |
117 | /*printf("%llx, %llx, %llx, %llx, %llx\n", (uint64) rela_entry.r_offset, */ | |
118 | /*(uint64)rela_entry.r_info, */ | |
119 | /*(uint64)rela_entry.r_addend, */ | |
120 | /*addr - VA_TO_FILE, value);*/ | |
121 | if (0 != fseek(fp, addr - va_to_file, SEEK_SET)){ | |
122 | fclose(fp); | |
123 | return -1; | |
124 | } | |
125 | ||
126 | if (fwrite((const void *) &value, sizeof(uint64), 1, fp) != 1){ | |
127 | fclose(fp); | |
128 | return -1; | |
129 | } | |
130 | } | |
131 | ||
132 | fclose(fp); | |
133 | return 0; | |
134 | } | |
135 |