clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name rtld_machine.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/libexec/ld.so/obj -resource-dir /usr/local/lib/clang/13.0.0 -D DO_CLEAN_BOOT -I /usr/src/libexec/ld.so -I /usr/src/libexec/ld.so/amd64 -D DEF_WEAK(x)=asm("") -D DEF_STRONG(x)=asm("") -D strsep=_dl_strsep -D strlcat=_dl_strlcat -D strlen=_dl_strlen -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/libexec/ld.so/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fno-builtin -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/libexec/ld.so/amd64/rtld_machine.c
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | |
61 | |
62 | |
63 | |
64 | |
65 | |
66 | #define _DYN_LOADER |
67 | |
68 | #include <sys/types.h> |
69 | #include <sys/exec_elf.h> |
70 | #include <sys/syscall.h> |
71 | #include <sys/unistd.h> |
72 | |
73 | #include <machine/reloc.h> |
74 | |
75 | #include "util.h" |
76 | #include "resolve.h" |
77 | |
78 | int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden; |
79 | |
80 | |
81 | |
82 | |
83 | |
84 | |
85 | |
86 | |
87 | |
88 | |
89 | |
90 | |
91 | |
92 | |
93 | |
94 | #define _RF_S 0x80000000 /* Resolve symbol */ |
95 | #define _RF_A 0x40000000 /* Use addend */ |
96 | #define _RF_P 0x20000000 /* Location relative */ |
97 | #define _RF_G 0x10000000 /* GOT offset */ |
98 | #define _RF_B 0x08000000 /* Load address relative */ |
99 | #define _RF_E 0x02000000 /* ERROR */ |
100 | #define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */ |
101 | #define _RF_RS(s) ((s) & 0xff) /* right shift */ |
102 | static const int reloc_target_flags[] = { |
103 | 0, |
104 | _RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), |
105 | _RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), |
106 | _RF_G|_RF_A| _RF_SZ(32) | _RF_RS(0), |
107 | _RF_E|_RF_A| _RF_SZ(32) | _RF_RS(0), |
108 | _RF_S| _RF_SZ(32) | _RF_RS(0), |
109 | _RF_S| _RF_SZ(64) | _RF_RS(0), |
110 | _RF_S| _RF_SZ(64) | _RF_RS(0), |
111 | _RF_A| _RF_B| _RF_SZ(64) | _RF_RS(0), |
112 | _RF_E, |
113 | _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), |
114 | _RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), |
115 | _RF_S|_RF_A| _RF_SZ(16) | _RF_RS(0), |
116 | _RF_S|_RF_A|_RF_P| _RF_SZ(16) | _RF_RS(0), |
117 | _RF_S|_RF_A| _RF_SZ(8) | _RF_RS(0), |
118 | _RF_S|_RF_A|_RF_P| _RF_SZ(8) | _RF_RS(0), |
119 | _RF_E, |
120 | _RF_E, |
121 | _RF_E, |
122 | _RF_E, |
123 | _RF_E, |
124 | _RF_E, |
125 | _RF_E, |
126 | _RF_E |
127 | }; |
128 | |
129 | #define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0) |
130 | #define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0) |
131 | #define RELOC_BASE_RELATIVE(t) ((reloc_target_flags[t] & _RF_B) != 0) |
132 | #define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0) |
133 | #define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff) |
134 | #define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff) |
135 | #define RELOC_ERROR(t) (reloc_target_flags[t] & _RF_E) |
136 | |
137 | static const Elf_Addr reloc_target_bitmask[] = { |
138 | #define _BM(x) (~(Elf_Addr)0 >> ((8*sizeof(reloc_target_bitmask[0])) - (x))) |
139 | 0, |
140 | _BM(64), |
141 | _BM(32), |
142 | _BM(32), |
143 | _BM(32), |
144 | 0, |
145 | _BM(64), |
146 | _BM(64), |
147 | _BM(64), |
148 | _BM(32), |
149 | _BM(32), |
150 | _BM(32), |
151 | _BM(16), |
152 | _BM(16), |
153 | _BM(8), |
154 | _BM(8), |
155 | 0, |
156 | 0, |
157 | 0, |
158 | 0, |
159 | 0, |
160 | 0, |
161 | 0, |
162 | 0 |
163 | #undef _BM |
164 | }; |
165 | #define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t]) |
166 | |
167 | void _dl_reloc_plt(Elf_Addr *where, Elf_Addr value); |
168 | |
169 | int |
170 | _dl_md_reloc(elf_object_t *object, int rel, int relsz) |
171 | { |
172 | long i; |
173 | long numrel; |
174 | long relrel; |
175 | int fails = 0; |
176 | Elf_Addr loff; |
177 | Elf_Addr prev_value = 0; |
178 | const Elf_Sym *prev_sym = NULL; |
179 | Elf_RelA *rels; |
180 | |
181 | loff = object->obj_base; |
182 | numrel = object->Dyn.info[relsz] / sizeof(Elf_RelA); |
183 | relrel = rel == DT_RELA ? object->relacount : 0; |
| |
184 | rels = (Elf_RelA *)(object->Dyn.info[rel]); |
185 | if (rels == NULL) |
| 9 | | Assuming 'rels' is not equal to NULL | |
|
| |
186 | return 0; |
187 | |
188 | if (relrel > numrel) |
| |
189 | _dl_die("relacount > numrel: %ld > %ld", relrel, numrel); |
190 | |
191 | |
192 | for (i = 0; i < relrel; i++, rels++) { |
| 12 | | Loop condition is false. Execution continues on line 198 | |
|
193 | Elf_Addr *where; |
194 | |
195 | where = (Elf_Addr *)(rels->r_offset + loff); |
196 | *where = rels->r_addend + loff; |
197 | } |
198 | for (; i < numrel; i++, rels++) { |
| 13 | | Assuming 'i' is < 'numrel' | |
|
| 14 | | Loop condition is true. Entering loop body | |
|
199 | Elf_Addr *where, value, mask; |
200 | Elf_Word type; |
201 | const Elf_Sym *sym; |
202 | const char *symn; |
203 | |
204 | type = ELF_R_TYPE(rels->r_info); |
205 | |
206 | if (RELOC_ERROR(type)) |
| 15 | | Assuming the condition is false | |
|
| |
207 | _dl_die("relocation error %d idx %ld", type, i); |
208 | |
209 | if (type == R_TYPE(NONE)) |
| 17 | | Assuming 'type' is not equal to R_TYPE(NONE) | |
|
| |
210 | continue; |
211 | |
212 | if (type == R_TYPE(JUMP_SLOT) && rel != DT_JMPREL) |
| 19 | | Assuming 'type' is not equal to R_TYPE(JUMP_SLOT) | |
|
213 | continue; |
214 | |
215 | where = (Elf_Addr *)(rels->r_offset + loff); |
216 | |
217 | if (RELOC_USE_ADDEND(type)) |
| 20 | | Assuming the condition is false | |
|
| |
218 | value = rels->r_addend; |
219 | else |
220 | value = 0; |
221 | |
222 | sym = NULL; |
| 22 | | Null pointer value stored to 'sym' | |
|
223 | symn = NULL; |
224 | if (RELOC_RESOLVE_SYMBOL(type)) { |
| 23 | | Assuming the condition is false | |
|
| |
225 | sym = object->dyn.symtab; |
226 | sym += ELF_R_SYM(rels->r_info); |
227 | symn = object->dyn.strtab + sym->st_name; |
228 | |
229 | if (sym->st_shndx != SHN_UNDEF && |
230 | ELF_ST_BIND(sym->st_info) == STB_LOCAL) { |
231 | value += loff; |
232 | } else if (sym == prev_sym) { |
233 | value += prev_value; |
234 | } else { |
235 | struct sym_res sr; |
236 | |
237 | sr = _dl_find_symbol(symn, |
238 | SYM_SEARCH_ALL|SYM_WARNNOTFOUND| |
239 | ((type == R_TYPE(JUMP_SLOT))? |
240 | SYM_PLT:SYM_NOTPLT), sym, object); |
241 | if (sr.sym == NULL) { |
242 | resolve_failed: |
243 | if (ELF_ST_BIND(sym->st_info) != |
| 31 | | Access to field 'st_info' results in a dereference of a null pointer (loaded from variable 'sym') |
|
244 | STB_WEAK) |
245 | fails++; |
246 | continue; |
247 | } |
248 | prev_sym = sym; |
249 | prev_value = (Elf_Addr)(sr.obj->obj_base + |
250 | sr.sym->st_value); |
251 | value += prev_value; |
252 | } |
253 | } |
254 | |
255 | if (type == R_TYPE(JUMP_SLOT)) { |
| |
256 | _dl_reloc_plt(where, value); |
257 | continue; |
258 | } |
259 | |
260 | if (type == R_TYPE(COPY)) { |
| 26 | | Assuming 'type' is equal to R_TYPE(COPY) | |
|
| |
261 | void *dstaddr = where; |
262 | const void *srcaddr; |
263 | const Elf_Sym *dstsym = sym; |
264 | struct sym_res sr; |
265 | |
266 | sr = _dl_find_symbol(symn, |
267 | SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT, |
268 | dstsym, object); |
269 | if (sr.sym == NULL) |
| 28 | | Assuming field 'sym' is equal to NULL | |
|
| |
270 | goto resolve_failed; |
| 30 | | Control jumps to line 243 | |
|
271 | |
272 | srcaddr = (void *)(sr.obj->obj_base + sr.sym->st_value); |
273 | _dl_bcopy(srcaddr, dstaddr, dstsym->st_size); |
274 | continue; |
275 | } |
276 | |
277 | if (RELOC_PC_RELATIVE(type)) |
278 | value -= (Elf_Addr)where; |
279 | if (RELOC_BASE_RELATIVE(type)) |
280 | value += loff; |
281 | |
282 | mask = RELOC_VALUE_BITMASK(type); |
283 | value >>= RELOC_VALUE_RIGHTSHIFT(type); |
284 | value &= mask; |
285 | |
286 | if (RELOC_TARGET_SIZE(type) > 32) { |
287 | *where &= ~mask; |
288 | *where |= value; |
289 | } else { |
290 | Elf32_Addr *where32 = (Elf32_Addr *)where; |
291 | |
292 | *where32 &= ~mask; |
293 | *where32 |= value; |
294 | } |
295 | } |
296 | |
297 | return fails; |
298 | } |
299 | |
300 | void |
301 | _dl_reloc_plt(Elf_Addr *where, Elf_Addr value) |
302 | { |
303 | *where = value; |
304 | } |
305 | |
306 | |
307 | |
308 | |
309 | Elf_Addr |
310 | _dl_bind(elf_object_t *object, int index) |
311 | { |
312 | Elf_RelA *rel; |
313 | const Elf_Sym *sym; |
314 | const char *symn; |
315 | struct sym_res sr; |
316 | int64_t cookie = pcookie; |
317 | struct { |
318 | struct __kbind param; |
319 | Elf_Addr newval; |
320 | } buf; |
321 | |
322 | rel = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]) + index; |
323 | |
324 | sym = object->dyn.symtab; |
325 | sym += ELF_R_SYM(rel->r_info); |
326 | symn = object->dyn.strtab + sym->st_name; |
327 | |
328 | sr = _dl_find_symbol(symn, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, |
329 | sym, object); |
330 | if (sr.sym == NULL) |
331 | _dl_die("lazy binding failed!"); |
332 | |
333 | buf.newval = sr.obj->obj_base + sr.sym->st_value; |
334 | |
335 | if (__predict_false(sr.obj->traced) && _dl_trace_plt(sr.obj, symn)) |
336 | return buf.newval; |
337 | |
338 | buf.param.kb_addr = (Elf_Word *)(object->obj_base + rel->r_offset); |
339 | buf.param.kb_size = sizeof(Elf_Addr); |
340 | |
341 | |
342 | { |
343 | register long syscall_num __asm("rax") = SYS_kbind; |
344 | register void *arg1 __asm("rdi") = &buf; |
345 | register long arg2 __asm("rsi") = sizeof(buf); |
346 | register long arg3 __asm("rdx") = cookie; |
347 | |
348 | __asm volatile("syscall" : "+r" (syscall_num), "+r" (arg3) : |
349 | "r" (arg1), "r" (arg2) : "cc", "rcx", "r11", "memory"); |
350 | } |
351 | return buf.newval; |
352 | } |
353 | |
354 | int |
355 | _dl_md_reloc_got(elf_object_t *object, int lazy) |
356 | { |
357 | extern void _dl_bind_start(void); |
358 | int fails = 0; |
359 | Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT]; |
360 | int i, num; |
361 | Elf_RelA *rel; |
362 | |
363 | if (pltgot == NULL) |
| 1 | Assuming 'pltgot' is not equal to NULL | |
|
| |
364 | return 0; |
365 | |
366 | if (object->Dyn.info[DT_PLTREL] != DT_RELA) |
| 3 | | Assuming the condition is false | |
|
| |
367 | return 0; |
368 | |
369 | if (__predict_false(!lazy)) { |
| |
| |
370 | fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); |
| |
371 | } else { |
372 | pltgot[1] = (Elf_Addr)object; |
373 | pltgot[2] = (Elf_Addr)&_dl_bind_start; |
374 | |
375 | rel = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]); |
376 | num = (object->Dyn.info[DT_PLTRELSZ]); |
377 | for (i = 0; i < num/sizeof(Elf_RelA); i++, rel++) { |
378 | Elf_Addr *where; |
379 | where = (Elf_Addr *)(rel->r_offset + object->obj_base); |
380 | *where += object->obj_base; |
381 | } |
382 | } |
383 | |
384 | return fails; |
385 | } |