1*c9945492SAndroid Build Coastguard Worker /*
2*c9945492SAndroid Build Coastguard Worker * Copyright (C) 2021 The Android Open Source Project
3*c9945492SAndroid Build Coastguard Worker * All rights reserved.
4*c9945492SAndroid Build Coastguard Worker *
5*c9945492SAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
6*c9945492SAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions
7*c9945492SAndroid Build Coastguard Worker * are met:
8*c9945492SAndroid Build Coastguard Worker * * Redistributions of source code must retain the above copyright
9*c9945492SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer.
10*c9945492SAndroid Build Coastguard Worker * * Redistributions in binary form must reproduce the above copyright
11*c9945492SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer in
12*c9945492SAndroid Build Coastguard Worker * the documentation and/or other materials provided with the
13*c9945492SAndroid Build Coastguard Worker * distribution.
14*c9945492SAndroid Build Coastguard Worker *
15*c9945492SAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16*c9945492SAndroid Build Coastguard Worker * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17*c9945492SAndroid Build Coastguard Worker * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18*c9945492SAndroid Build Coastguard Worker * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19*c9945492SAndroid Build Coastguard Worker * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20*c9945492SAndroid Build Coastguard Worker * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21*c9945492SAndroid Build Coastguard Worker * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22*c9945492SAndroid Build Coastguard Worker * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23*c9945492SAndroid Build Coastguard Worker * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24*c9945492SAndroid Build Coastguard Worker * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25*c9945492SAndroid Build Coastguard Worker * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*c9945492SAndroid Build Coastguard Worker * SUCH DAMAGE.
27*c9945492SAndroid Build Coastguard Worker */
28*c9945492SAndroid Build Coastguard Worker
29*c9945492SAndroid Build Coastguard Worker #define SYSCALL_NO_TLS 1
30*c9945492SAndroid Build Coastguard Worker #include <elf.h>
31*c9945492SAndroid Build Coastguard Worker #include <errno.h>
32*c9945492SAndroid Build Coastguard Worker #include <fcntl.h>
33*c9945492SAndroid Build Coastguard Worker #include <link.h>
34*c9945492SAndroid Build Coastguard Worker #include <stdalign.h>
35*c9945492SAndroid Build Coastguard Worker #include <stdarg.h>
36*c9945492SAndroid Build Coastguard Worker #include <stdbool.h>
37*c9945492SAndroid Build Coastguard Worker #include <stdint.h>
38*c9945492SAndroid Build Coastguard Worker #include <sys/mman.h>
39*c9945492SAndroid Build Coastguard Worker #include <sys/param.h>
40*c9945492SAndroid Build Coastguard Worker #include <sys/syscall.h>
41*c9945492SAndroid Build Coastguard Worker #include <sys/user.h>
42*c9945492SAndroid Build Coastguard Worker #include <unistd.h>
43*c9945492SAndroid Build Coastguard Worker
44*c9945492SAndroid Build Coastguard Worker #include "reloc.h"
45*c9945492SAndroid Build Coastguard Worker #include "syscall.h"
46*c9945492SAndroid Build Coastguard Worker
47*c9945492SAndroid Build Coastguard Worker typedef void EntryFunc(void);
48*c9945492SAndroid Build Coastguard Worker
49*c9945492SAndroid Build Coastguard Worker // arm64 doesn't have a constant page size and has to use the value from AT_PAGESZ.
50*c9945492SAndroid Build Coastguard Worker #ifndef PAGE_SIZE
51*c9945492SAndroid Build Coastguard Worker #define PAGE_SIZE g_page_size
52*c9945492SAndroid Build Coastguard Worker #endif
53*c9945492SAndroid Build Coastguard Worker
54*c9945492SAndroid Build Coastguard Worker #define PAGE_START(x) ((x) & (~(PAGE_SIZE-1)))
55*c9945492SAndroid Build Coastguard Worker #define PAGE_END(x) PAGE_START((x) + (PAGE_SIZE - 1))
56*c9945492SAndroid Build Coastguard Worker
57*c9945492SAndroid Build Coastguard Worker #define START "_start"
58*c9945492SAndroid Build Coastguard Worker #include "crt_arch.h"
59*c9945492SAndroid Build Coastguard Worker
60*c9945492SAndroid Build Coastguard Worker int main();
61*c9945492SAndroid Build Coastguard Worker weak void _init();
62*c9945492SAndroid Build Coastguard Worker weak void _fini();
63*c9945492SAndroid Build Coastguard Worker int __libc_start_main(int (*)(), int, char **,
64*c9945492SAndroid Build Coastguard Worker void (*)(), void(*)(), void(*)());
65*c9945492SAndroid Build Coastguard Worker
66*c9945492SAndroid Build Coastguard Worker static ElfW(Phdr) replacement_phdr_table[64];
67*c9945492SAndroid Build Coastguard Worker static char replacement_interp[PATH_MAX];
68*c9945492SAndroid Build Coastguard Worker
69*c9945492SAndroid Build Coastguard Worker static bool g_debug = false;
70*c9945492SAndroid Build Coastguard Worker static const char* g_prog_name = NULL;
71*c9945492SAndroid Build Coastguard Worker static uintptr_t g_page_size = 0;
72*c9945492SAndroid Build Coastguard Worker static int g_errno = 0;
73*c9945492SAndroid Build Coastguard Worker
74*c9945492SAndroid Build Coastguard Worker __attribute__((visibility("hidden"))) extern ElfW(Dyn) _DYNAMIC[];
75*c9945492SAndroid Build Coastguard Worker
76*c9945492SAndroid Build Coastguard Worker __attribute__((used))
ri_set_errno(unsigned long val)77*c9945492SAndroid Build Coastguard Worker static long ri_set_errno(unsigned long val) {
78*c9945492SAndroid Build Coastguard Worker if (val > -4096UL) {
79*c9945492SAndroid Build Coastguard Worker g_errno = -val;
80*c9945492SAndroid Build Coastguard Worker return -1;
81*c9945492SAndroid Build Coastguard Worker }
82*c9945492SAndroid Build Coastguard Worker return val;
83*c9945492SAndroid Build Coastguard Worker }
84*c9945492SAndroid Build Coastguard Worker
85*c9945492SAndroid Build Coastguard Worker #define ri_syscall(...) ri_set_errno(__syscall(__VA_ARGS__))
86*c9945492SAndroid Build Coastguard Worker
ri_write(int fd,const void * buf,size_t amt)87*c9945492SAndroid Build Coastguard Worker static ssize_t ri_write(int fd, const void* buf, size_t amt) {
88*c9945492SAndroid Build Coastguard Worker return ri_syscall(SYS_write, fd, buf, amt);
89*c9945492SAndroid Build Coastguard Worker }
90*c9945492SAndroid Build Coastguard Worker
91*c9945492SAndroid Build Coastguard Worker __attribute__((noreturn))
ri_exit(int status)92*c9945492SAndroid Build Coastguard Worker static void ri_exit(int status) {
93*c9945492SAndroid Build Coastguard Worker ri_syscall(SYS_exit, status);
94*c9945492SAndroid Build Coastguard Worker __builtin_unreachable();
95*c9945492SAndroid Build Coastguard Worker }
96*c9945492SAndroid Build Coastguard Worker
ri_open(const char * path,int flags,mode_t mode)97*c9945492SAndroid Build Coastguard Worker static int ri_open(const char* path, int flags, mode_t mode) {
98*c9945492SAndroid Build Coastguard Worker return ri_syscall(SYS_openat, AT_FDCWD, path, flags, mode);
99*c9945492SAndroid Build Coastguard Worker }
100*c9945492SAndroid Build Coastguard Worker
ri_close(int fd)101*c9945492SAndroid Build Coastguard Worker static int ri_close(int fd) {
102*c9945492SAndroid Build Coastguard Worker return ri_syscall(SYS_close, fd);
103*c9945492SAndroid Build Coastguard Worker }
104*c9945492SAndroid Build Coastguard Worker
ri_lseek(int fd,off_t offset,int whence)105*c9945492SAndroid Build Coastguard Worker static off_t ri_lseek(int fd, off_t offset, int whence) {
106*c9945492SAndroid Build Coastguard Worker return ri_syscall(SYS_lseek, fd, offset, whence);
107*c9945492SAndroid Build Coastguard Worker }
108*c9945492SAndroid Build Coastguard Worker
ri_readlink(const char * path,char * buf,size_t size)109*c9945492SAndroid Build Coastguard Worker static ssize_t ri_readlink(const char* path, char* buf, size_t size) {
110*c9945492SAndroid Build Coastguard Worker return ri_syscall(SYS_readlinkat, AT_FDCWD, path, buf, size);
111*c9945492SAndroid Build Coastguard Worker }
112*c9945492SAndroid Build Coastguard Worker
ri_mmap(void * addr,size_t length,int prot,int flags,int fd,off_t offset)113*c9945492SAndroid Build Coastguard Worker static void* ri_mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset) {
114*c9945492SAndroid Build Coastguard Worker #ifdef SYS_mmap2
115*c9945492SAndroid Build Coastguard Worker return (void*)ri_syscall(SYS_mmap2, addr, length, prot, flags, fd, offset/SYSCALL_MMAP2_UNIT);
116*c9945492SAndroid Build Coastguard Worker #else
117*c9945492SAndroid Build Coastguard Worker return (void*)ri_syscall(SYS_mmap, addr, length, prot, flags, fd, offset);
118*c9945492SAndroid Build Coastguard Worker #endif
119*c9945492SAndroid Build Coastguard Worker }
120*c9945492SAndroid Build Coastguard Worker
ri_munmap(void * addr,size_t length)121*c9945492SAndroid Build Coastguard Worker static void* ri_munmap(void* addr, size_t length) {
122*c9945492SAndroid Build Coastguard Worker return (void*)ri_syscall(SYS_munmap, addr, length);
123*c9945492SAndroid Build Coastguard Worker }
124*c9945492SAndroid Build Coastguard Worker
ri_mprotect(void * addr,size_t len,int prot)125*c9945492SAndroid Build Coastguard Worker static int ri_mprotect(void* addr, size_t len, int prot) {
126*c9945492SAndroid Build Coastguard Worker return ri_syscall(SYS_mprotect, addr, len, prot);
127*c9945492SAndroid Build Coastguard Worker }
128*c9945492SAndroid Build Coastguard Worker
ri_pread(int fd,void * buf,size_t size,off_t ofs)129*c9945492SAndroid Build Coastguard Worker static ssize_t ri_pread(int fd, void* buf, size_t size, off_t ofs) {
130*c9945492SAndroid Build Coastguard Worker return ri_syscall(SYS_pread, fd, buf, size, __SYSCALL_LL_PRW(ofs));
131*c9945492SAndroid Build Coastguard Worker }
132*c9945492SAndroid Build Coastguard Worker
ri_strlen(const char * src)133*c9945492SAndroid Build Coastguard Worker static size_t ri_strlen(const char* src) {
134*c9945492SAndroid Build Coastguard Worker for (size_t len = 0;; ++len) {
135*c9945492SAndroid Build Coastguard Worker if (src[len] == '\0') return len;
136*c9945492SAndroid Build Coastguard Worker }
137*c9945492SAndroid Build Coastguard Worker }
138*c9945492SAndroid Build Coastguard Worker
ri_strcpy(char * dst,const char * src)139*c9945492SAndroid Build Coastguard Worker static char* ri_strcpy(char* dst, const char* src) {
140*c9945492SAndroid Build Coastguard Worker char* result = dst;
141*c9945492SAndroid Build Coastguard Worker while ((*dst = *src) != '\0') {
142*c9945492SAndroid Build Coastguard Worker ++dst;
143*c9945492SAndroid Build Coastguard Worker ++src;
144*c9945492SAndroid Build Coastguard Worker }
145*c9945492SAndroid Build Coastguard Worker return result;
146*c9945492SAndroid Build Coastguard Worker }
147*c9945492SAndroid Build Coastguard Worker
ri_strcat(char * dst,const char * src)148*c9945492SAndroid Build Coastguard Worker static char* ri_strcat(char* dst, const char* src) {
149*c9945492SAndroid Build Coastguard Worker ri_strcpy(dst + ri_strlen(dst), src);
150*c9945492SAndroid Build Coastguard Worker return dst;
151*c9945492SAndroid Build Coastguard Worker }
152*c9945492SAndroid Build Coastguard Worker
ri_memset(void * dst,int val,size_t len)153*c9945492SAndroid Build Coastguard Worker static void* ri_memset(void* dst, int val, size_t len) {
154*c9945492SAndroid Build Coastguard Worker for (size_t i = 0; i < len; ++i) {
155*c9945492SAndroid Build Coastguard Worker ((char*)dst)[i] = val;
156*c9945492SAndroid Build Coastguard Worker }
157*c9945492SAndroid Build Coastguard Worker return dst;
158*c9945492SAndroid Build Coastguard Worker }
159*c9945492SAndroid Build Coastguard Worker
160*c9945492SAndroid Build Coastguard Worker __attribute__ ((unused))
ri_memcpy(void * dst,const void * src,size_t len)161*c9945492SAndroid Build Coastguard Worker static void* ri_memcpy(void* dst, const void* src, size_t len) {
162*c9945492SAndroid Build Coastguard Worker for (size_t i = 0; i < len; ++i) {
163*c9945492SAndroid Build Coastguard Worker ((char*)dst)[i] = ((char*)src)[i];
164*c9945492SAndroid Build Coastguard Worker }
165*c9945492SAndroid Build Coastguard Worker return dst;
166*c9945492SAndroid Build Coastguard Worker }
167*c9945492SAndroid Build Coastguard Worker
ri_strncmp(const char * x,const char * y,size_t maxlen)168*c9945492SAndroid Build Coastguard Worker static int ri_strncmp(const char* x, const char *y, size_t maxlen) {
169*c9945492SAndroid Build Coastguard Worker for (size_t i = 0;; ++i) {
170*c9945492SAndroid Build Coastguard Worker if (i == maxlen) return 0;
171*c9945492SAndroid Build Coastguard Worker int result = (unsigned char)x[i] - (unsigned char)y[i];
172*c9945492SAndroid Build Coastguard Worker if (result != 0) return result;
173*c9945492SAndroid Build Coastguard Worker if (x[i] == '\0') return 0;
174*c9945492SAndroid Build Coastguard Worker }
175*c9945492SAndroid Build Coastguard Worker }
176*c9945492SAndroid Build Coastguard Worker
ri_strcmp(const char * x,const char * y)177*c9945492SAndroid Build Coastguard Worker static int ri_strcmp(const char* x, const char *y) {
178*c9945492SAndroid Build Coastguard Worker return ri_strncmp(x, y, SIZE_MAX);
179*c9945492SAndroid Build Coastguard Worker }
180*c9945492SAndroid Build Coastguard Worker
ri_strrchr(const char * str,int ch)181*c9945492SAndroid Build Coastguard Worker static char* ri_strrchr(const char* str, int ch) {
182*c9945492SAndroid Build Coastguard Worker char* result = NULL;
183*c9945492SAndroid Build Coastguard Worker while (true) {
184*c9945492SAndroid Build Coastguard Worker if (*str == ch) result = (char*)str;
185*c9945492SAndroid Build Coastguard Worker if (*str == '\0') break;
186*c9945492SAndroid Build Coastguard Worker ++str;
187*c9945492SAndroid Build Coastguard Worker }
188*c9945492SAndroid Build Coastguard Worker return result;
189*c9945492SAndroid Build Coastguard Worker }
190*c9945492SAndroid Build Coastguard Worker
ri_strchr(const char * str,int ch)191*c9945492SAndroid Build Coastguard Worker static char* ri_strchr(const char* str, int ch) {
192*c9945492SAndroid Build Coastguard Worker while (*str) {
193*c9945492SAndroid Build Coastguard Worker if (*str == ch) return (char*)str;
194*c9945492SAndroid Build Coastguard Worker ++str;
195*c9945492SAndroid Build Coastguard Worker }
196*c9945492SAndroid Build Coastguard Worker return NULL;
197*c9945492SAndroid Build Coastguard Worker }
198*c9945492SAndroid Build Coastguard Worker
ri_dirname(char * path)199*c9945492SAndroid Build Coastguard Worker static void ri_dirname(char* path) {
200*c9945492SAndroid Build Coastguard Worker char* last_slash = ri_strrchr(path, '/');
201*c9945492SAndroid Build Coastguard Worker if (last_slash == NULL) {
202*c9945492SAndroid Build Coastguard Worker path[0] = '.'; // returns "."
203*c9945492SAndroid Build Coastguard Worker path[1] = '\0';
204*c9945492SAndroid Build Coastguard Worker } else if (last_slash == path) {
205*c9945492SAndroid Build Coastguard Worker path[1] = '\0'; // returns "/"
206*c9945492SAndroid Build Coastguard Worker } else {
207*c9945492SAndroid Build Coastguard Worker *last_slash = '\0';
208*c9945492SAndroid Build Coastguard Worker }
209*c9945492SAndroid Build Coastguard Worker }
210*c9945492SAndroid Build Coastguard Worker
out_str_n(const char * str,size_t n)211*c9945492SAndroid Build Coastguard Worker static void out_str_n(const char* str, size_t n) {
212*c9945492SAndroid Build Coastguard Worker ri_write(STDERR_FILENO, str, n);
213*c9945492SAndroid Build Coastguard Worker }
214*c9945492SAndroid Build Coastguard Worker
out_str(const char * str)215*c9945492SAndroid Build Coastguard Worker static void out_str(const char* str) {
216*c9945492SAndroid Build Coastguard Worker out_str_n(str, ri_strlen(str));
217*c9945492SAndroid Build Coastguard Worker }
218*c9945492SAndroid Build Coastguard Worker
ul_to_str(unsigned long i,char * out,unsigned char base)219*c9945492SAndroid Build Coastguard Worker static char* ul_to_str(unsigned long i, char* out, unsigned char base) {
220*c9945492SAndroid Build Coastguard Worker char buf[65];
221*c9945492SAndroid Build Coastguard Worker char* cur = &buf[65];
222*c9945492SAndroid Build Coastguard Worker *--cur = '\0';
223*c9945492SAndroid Build Coastguard Worker do {
224*c9945492SAndroid Build Coastguard Worker *--cur = "0123456789abcdef"[i % base];
225*c9945492SAndroid Build Coastguard Worker i /= base;
226*c9945492SAndroid Build Coastguard Worker } while (i > 0);
227*c9945492SAndroid Build Coastguard Worker return ri_strcpy(out, cur);
228*c9945492SAndroid Build Coastguard Worker }
229*c9945492SAndroid Build Coastguard Worker
l_to_str(long i,char * out,unsigned char base)230*c9945492SAndroid Build Coastguard Worker static char* l_to_str(long i, char* out, unsigned char base) {
231*c9945492SAndroid Build Coastguard Worker if (i < 0) {
232*c9945492SAndroid Build Coastguard Worker *out = '-';
233*c9945492SAndroid Build Coastguard Worker ul_to_str(-(unsigned long)i, out + 1, base);
234*c9945492SAndroid Build Coastguard Worker return out;
235*c9945492SAndroid Build Coastguard Worker } else {
236*c9945492SAndroid Build Coastguard Worker return ul_to_str(i, out, base);
237*c9945492SAndroid Build Coastguard Worker }
238*c9945492SAndroid Build Coastguard Worker }
239*c9945492SAndroid Build Coastguard Worker
ri_strerror(int err)240*c9945492SAndroid Build Coastguard Worker static const char* ri_strerror(int err) {
241*c9945492SAndroid Build Coastguard Worker switch (err) {
242*c9945492SAndroid Build Coastguard Worker case EPERM: return "Operation not permitted";
243*c9945492SAndroid Build Coastguard Worker case ENOENT: return "No such file or directory";
244*c9945492SAndroid Build Coastguard Worker case EIO: return "I/O error";
245*c9945492SAndroid Build Coastguard Worker case ENXIO: return "No such device or address";
246*c9945492SAndroid Build Coastguard Worker case EAGAIN: return "Try again";
247*c9945492SAndroid Build Coastguard Worker case ENOMEM: return "Out of memory";
248*c9945492SAndroid Build Coastguard Worker case EACCES: return "Permission denied";
249*c9945492SAndroid Build Coastguard Worker case ENODEV: return "No such device";
250*c9945492SAndroid Build Coastguard Worker case ENOTDIR: return "Not a directory";
251*c9945492SAndroid Build Coastguard Worker case EINVAL: return "Invalid argument";
252*c9945492SAndroid Build Coastguard Worker case ENFILE: return "File table overflow";
253*c9945492SAndroid Build Coastguard Worker case EMFILE: return "Too many open files";
254*c9945492SAndroid Build Coastguard Worker case ESPIPE: return "Illegal seek";
255*c9945492SAndroid Build Coastguard Worker case ENAMETOOLONG: return "File name too long";
256*c9945492SAndroid Build Coastguard Worker case ELOOP: return "Too many symbolic links encountered";
257*c9945492SAndroid Build Coastguard Worker }
258*c9945492SAndroid Build Coastguard Worker static char buf[64];
259*c9945492SAndroid Build Coastguard Worker ri_strcpy(buf, "Unknown error ");
260*c9945492SAndroid Build Coastguard Worker l_to_str(err, buf + ri_strlen(buf), 10);
261*c9945492SAndroid Build Coastguard Worker return buf;
262*c9945492SAndroid Build Coastguard Worker }
263*c9945492SAndroid Build Coastguard Worker
outv(const char * fmt,va_list ap)264*c9945492SAndroid Build Coastguard Worker static void outv(const char *fmt, va_list ap) {
265*c9945492SAndroid Build Coastguard Worker char buf[65];
266*c9945492SAndroid Build Coastguard Worker while (true) {
267*c9945492SAndroid Build Coastguard Worker if (fmt[0] == '\0') break;
268*c9945492SAndroid Build Coastguard Worker
269*c9945492SAndroid Build Coastguard Worker #define NUM_FMT(num_fmt, type, func, base) \
270*c9945492SAndroid Build Coastguard Worker if (!ri_strncmp(fmt, num_fmt, sizeof(num_fmt) - 1)) { \
271*c9945492SAndroid Build Coastguard Worker out_str(func(va_arg(ap, type), buf, base)); \
272*c9945492SAndroid Build Coastguard Worker fmt += sizeof(num_fmt) - 1; \
273*c9945492SAndroid Build Coastguard Worker continue; \
274*c9945492SAndroid Build Coastguard Worker }
275*c9945492SAndroid Build Coastguard Worker NUM_FMT("%d", int, l_to_str, 10);
276*c9945492SAndroid Build Coastguard Worker NUM_FMT("%ld", long, l_to_str, 10);
277*c9945492SAndroid Build Coastguard Worker NUM_FMT("%u", unsigned int, ul_to_str, 10);
278*c9945492SAndroid Build Coastguard Worker NUM_FMT("%lu", unsigned long, ul_to_str, 10);
279*c9945492SAndroid Build Coastguard Worker NUM_FMT("%zu", size_t, ul_to_str, 10);
280*c9945492SAndroid Build Coastguard Worker NUM_FMT("%x", unsigned int, ul_to_str, 16);
281*c9945492SAndroid Build Coastguard Worker NUM_FMT("%lx", unsigned long, ul_to_str, 16);
282*c9945492SAndroid Build Coastguard Worker NUM_FMT("%zx", size_t, ul_to_str, 16);
283*c9945492SAndroid Build Coastguard Worker #undef NUM_FMT
284*c9945492SAndroid Build Coastguard Worker
285*c9945492SAndroid Build Coastguard Worker if (!ri_strncmp(fmt, "%p", 2)) {
286*c9945492SAndroid Build Coastguard Worker out_str(ul_to_str((unsigned long)va_arg(ap, void*), buf, 16));
287*c9945492SAndroid Build Coastguard Worker fmt += 2;
288*c9945492SAndroid Build Coastguard Worker } else if (!ri_strncmp(fmt, "%s", 2)) {
289*c9945492SAndroid Build Coastguard Worker const char* arg = va_arg(ap, const char*);
290*c9945492SAndroid Build Coastguard Worker out_str(arg ? arg : "(null)");
291*c9945492SAndroid Build Coastguard Worker fmt += 2;
292*c9945492SAndroid Build Coastguard Worker } else if (!ri_strncmp(fmt, "%%", 2)) {
293*c9945492SAndroid Build Coastguard Worker out_str("%");
294*c9945492SAndroid Build Coastguard Worker fmt += 2;
295*c9945492SAndroid Build Coastguard Worker } else if (fmt[0] == '%') {
296*c9945492SAndroid Build Coastguard Worker buf[0] = fmt[1];
297*c9945492SAndroid Build Coastguard Worker buf[1] = '\0';
298*c9945492SAndroid Build Coastguard Worker out_str("relinterp error: unrecognized output specifier: '%");
299*c9945492SAndroid Build Coastguard Worker out_str(buf);
300*c9945492SAndroid Build Coastguard Worker out_str("'\n");
301*c9945492SAndroid Build Coastguard Worker ri_exit(1);
302*c9945492SAndroid Build Coastguard Worker } else {
303*c9945492SAndroid Build Coastguard Worker size_t len = 0;
304*c9945492SAndroid Build Coastguard Worker while (fmt[len] != '\0' && fmt[len] != '%') ++len;
305*c9945492SAndroid Build Coastguard Worker out_str_n(fmt, len);
306*c9945492SAndroid Build Coastguard Worker fmt += len;
307*c9945492SAndroid Build Coastguard Worker }
308*c9945492SAndroid Build Coastguard Worker }
309*c9945492SAndroid Build Coastguard Worker }
310*c9945492SAndroid Build Coastguard Worker
311*c9945492SAndroid Build Coastguard Worker __attribute__((format(printf, 1, 2)))
debug(const char * fmt,...)312*c9945492SAndroid Build Coastguard Worker static void debug(const char* fmt, ...) {
313*c9945492SAndroid Build Coastguard Worker if (!g_debug) return;
314*c9945492SAndroid Build Coastguard Worker out_str("relinterp: ");
315*c9945492SAndroid Build Coastguard Worker
316*c9945492SAndroid Build Coastguard Worker va_list ap;
317*c9945492SAndroid Build Coastguard Worker va_start(ap, fmt);
318*c9945492SAndroid Build Coastguard Worker outv(fmt, ap);
319*c9945492SAndroid Build Coastguard Worker va_end(ap);
320*c9945492SAndroid Build Coastguard Worker out_str("\n");
321*c9945492SAndroid Build Coastguard Worker }
322*c9945492SAndroid Build Coastguard Worker
323*c9945492SAndroid Build Coastguard Worker __attribute__((format(printf, 1, 2), noreturn))
fatal(const char * fmt,...)324*c9945492SAndroid Build Coastguard Worker static void fatal(const char* fmt, ...) {
325*c9945492SAndroid Build Coastguard Worker out_str("relinterp: ");
326*c9945492SAndroid Build Coastguard Worker if (g_prog_name) {
327*c9945492SAndroid Build Coastguard Worker out_str(g_prog_name);
328*c9945492SAndroid Build Coastguard Worker out_str(": ");
329*c9945492SAndroid Build Coastguard Worker }
330*c9945492SAndroid Build Coastguard Worker out_str("fatal error: ");
331*c9945492SAndroid Build Coastguard Worker
332*c9945492SAndroid Build Coastguard Worker va_list ap;
333*c9945492SAndroid Build Coastguard Worker va_start(ap, fmt);
334*c9945492SAndroid Build Coastguard Worker outv(fmt, ap);
335*c9945492SAndroid Build Coastguard Worker va_end(ap);
336*c9945492SAndroid Build Coastguard Worker out_str("\n");
337*c9945492SAndroid Build Coastguard Worker ri_exit(1);
338*c9945492SAndroid Build Coastguard Worker }
339*c9945492SAndroid Build Coastguard Worker
optimizer_barrier(void * val)340*c9945492SAndroid Build Coastguard Worker static void* optimizer_barrier(void* val) {
341*c9945492SAndroid Build Coastguard Worker __asm__ volatile ("nop" :: "r"(&val) : "memory");
342*c9945492SAndroid Build Coastguard Worker return val;
343*c9945492SAndroid Build Coastguard Worker }
344*c9945492SAndroid Build Coastguard Worker
345*c9945492SAndroid Build Coastguard Worker typedef struct {
346*c9945492SAndroid Build Coastguard Worker unsigned long key;
347*c9945492SAndroid Build Coastguard Worker unsigned long value;
348*c9945492SAndroid Build Coastguard Worker } AuxEntry;
349*c9945492SAndroid Build Coastguard Worker
350*c9945492SAndroid Build Coastguard Worker typedef struct {
351*c9945492SAndroid Build Coastguard Worker int argc;
352*c9945492SAndroid Build Coastguard Worker char **argv;
353*c9945492SAndroid Build Coastguard Worker char **envp;
354*c9945492SAndroid Build Coastguard Worker size_t envp_count;
355*c9945492SAndroid Build Coastguard Worker AuxEntry* auxv;
356*c9945492SAndroid Build Coastguard Worker size_t auxv_count;
357*c9945492SAndroid Build Coastguard Worker } KernelArguments;
358*c9945492SAndroid Build Coastguard Worker
read_args(void * raw_args)359*c9945492SAndroid Build Coastguard Worker static KernelArguments read_args(void* raw_args) {
360*c9945492SAndroid Build Coastguard Worker KernelArguments result;
361*c9945492SAndroid Build Coastguard Worker result.argc = *(long*)raw_args;
362*c9945492SAndroid Build Coastguard Worker result.argv = (char**)((void**)raw_args + 1);
363*c9945492SAndroid Build Coastguard Worker result.envp = result.argv + result.argc + 1;
364*c9945492SAndroid Build Coastguard Worker
365*c9945492SAndroid Build Coastguard Worker char** envp = result.envp;
366*c9945492SAndroid Build Coastguard Worker while (*envp != NULL) ++envp;
367*c9945492SAndroid Build Coastguard Worker result.envp_count = envp - result.envp;
368*c9945492SAndroid Build Coastguard Worker ++envp;
369*c9945492SAndroid Build Coastguard Worker
370*c9945492SAndroid Build Coastguard Worker result.auxv = (AuxEntry*)envp;
371*c9945492SAndroid Build Coastguard Worker size_t count = 0;
372*c9945492SAndroid Build Coastguard Worker while (result.auxv[count].key != 0) {
373*c9945492SAndroid Build Coastguard Worker ++count;
374*c9945492SAndroid Build Coastguard Worker }
375*c9945492SAndroid Build Coastguard Worker result.auxv_count = count;
376*c9945492SAndroid Build Coastguard Worker return result;
377*c9945492SAndroid Build Coastguard Worker }
378*c9945492SAndroid Build Coastguard Worker
dump_auxv(const KernelArguments * args)379*c9945492SAndroid Build Coastguard Worker static void dump_auxv(const KernelArguments* args) {
380*c9945492SAndroid Build Coastguard Worker for (size_t i = 0; i < args->auxv_count; ++i) {
381*c9945492SAndroid Build Coastguard Worker const char* name = "";
382*c9945492SAndroid Build Coastguard Worker switch (args->auxv[i].key) {
383*c9945492SAndroid Build Coastguard Worker case AT_BASE: name = " [AT_BASE]"; break;
384*c9945492SAndroid Build Coastguard Worker case AT_EGID: name = " [AT_EGID]"; break;
385*c9945492SAndroid Build Coastguard Worker case AT_ENTRY: name = " [AT_ENTRY]"; break;
386*c9945492SAndroid Build Coastguard Worker case AT_EUID: name = " [AT_EUID]"; break;
387*c9945492SAndroid Build Coastguard Worker case AT_GID: name = " [AT_GID]"; break;
388*c9945492SAndroid Build Coastguard Worker case AT_PAGESZ: name = " [AT_PAGESZ]"; break;
389*c9945492SAndroid Build Coastguard Worker case AT_PHDR: name = " [AT_PHDR]"; break;
390*c9945492SAndroid Build Coastguard Worker case AT_PHENT: name = " [AT_PHENT]"; break;
391*c9945492SAndroid Build Coastguard Worker case AT_PHNUM: name = " [AT_PHNUM]"; break;
392*c9945492SAndroid Build Coastguard Worker case AT_SECURE: name = " [AT_SECURE]"; break;
393*c9945492SAndroid Build Coastguard Worker case AT_SYSINFO: name = " [AT_SYSINFO]"; break;
394*c9945492SAndroid Build Coastguard Worker case AT_SYSINFO_EHDR: name = " [AT_SYSINFO_EHDR]"; break;
395*c9945492SAndroid Build Coastguard Worker case AT_UID: name = " [AT_UID]"; break;
396*c9945492SAndroid Build Coastguard Worker }
397*c9945492SAndroid Build Coastguard Worker debug(" %lu => 0x%lx%s", args->auxv[i].key, args->auxv[i].value, name);
398*c9945492SAndroid Build Coastguard Worker }
399*c9945492SAndroid Build Coastguard Worker }
400*c9945492SAndroid Build Coastguard Worker
ri_getauxval(const KernelArguments * args,unsigned long kind,bool allow_missing)401*c9945492SAndroid Build Coastguard Worker static unsigned long ri_getauxval(const KernelArguments* args, unsigned long kind,
402*c9945492SAndroid Build Coastguard Worker bool allow_missing) {
403*c9945492SAndroid Build Coastguard Worker for (size_t i = 0; i < args->auxv_count; ++i) {
404*c9945492SAndroid Build Coastguard Worker if (args->auxv[i].key == kind) return args->auxv[i].value;
405*c9945492SAndroid Build Coastguard Worker }
406*c9945492SAndroid Build Coastguard Worker if (!allow_missing) fatal("could not find aux vector entry %lu", kind);
407*c9945492SAndroid Build Coastguard Worker return 0;
408*c9945492SAndroid Build Coastguard Worker }
409*c9945492SAndroid Build Coastguard Worker
elf_flags_to_prot(int flags)410*c9945492SAndroid Build Coastguard Worker static int elf_flags_to_prot(int flags) {
411*c9945492SAndroid Build Coastguard Worker int result = 0;
412*c9945492SAndroid Build Coastguard Worker if (flags & PF_R) result |= PROT_READ;
413*c9945492SAndroid Build Coastguard Worker if (flags & PF_W) result |= PROT_WRITE;
414*c9945492SAndroid Build Coastguard Worker if (flags & PF_X) result |= PROT_EXEC;
415*c9945492SAndroid Build Coastguard Worker return result;
416*c9945492SAndroid Build Coastguard Worker }
417*c9945492SAndroid Build Coastguard Worker
418*c9945492SAndroid Build Coastguard Worker typedef struct {
419*c9945492SAndroid Build Coastguard Worker int fd;
420*c9945492SAndroid Build Coastguard Worker char path[PATH_MAX];
421*c9945492SAndroid Build Coastguard Worker } OpenedLoader;
422*c9945492SAndroid Build Coastguard Worker
423*c9945492SAndroid Build Coastguard Worker typedef struct {
424*c9945492SAndroid Build Coastguard Worker void* base_addr;
425*c9945492SAndroid Build Coastguard Worker EntryFunc* entry;
426*c9945492SAndroid Build Coastguard Worker } LoadedInterp;
427*c9945492SAndroid Build Coastguard Worker
load_interp(const OpenedLoader * loader,ElfW (Ehdr)* hdr)428*c9945492SAndroid Build Coastguard Worker static LoadedInterp load_interp(const OpenedLoader *loader, ElfW(Ehdr)* hdr) {
429*c9945492SAndroid Build Coastguard Worker ElfW(Phdr)* phdr = (ElfW(Phdr)*)((char*)hdr + hdr->e_phoff);
430*c9945492SAndroid Build Coastguard Worker size_t phdr_count = hdr->e_phnum;
431*c9945492SAndroid Build Coastguard Worker
432*c9945492SAndroid Build Coastguard Worker size_t max_vaddr = 0;
433*c9945492SAndroid Build Coastguard Worker
434*c9945492SAndroid Build Coastguard Worker // Find the virtual address extent.
435*c9945492SAndroid Build Coastguard Worker for (size_t i = 0; i < phdr_count; ++i) {
436*c9945492SAndroid Build Coastguard Worker if (phdr[i].p_type == PT_LOAD) {
437*c9945492SAndroid Build Coastguard Worker max_vaddr = PAGE_END(MAX(max_vaddr, phdr[i].p_vaddr + phdr[i].p_memsz));
438*c9945492SAndroid Build Coastguard Worker }
439*c9945492SAndroid Build Coastguard Worker }
440*c9945492SAndroid Build Coastguard Worker
441*c9945492SAndroid Build Coastguard Worker // Map an area to fit the loader.
442*c9945492SAndroid Build Coastguard Worker void* loader_vaddr = ri_mmap(NULL, max_vaddr, PROT_READ | PROT_WRITE,
443*c9945492SAndroid Build Coastguard Worker MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
444*c9945492SAndroid Build Coastguard Worker if (loader_vaddr == (void*)MAP_FAILED) {
445*c9945492SAndroid Build Coastguard Worker fatal("reservation mmap of 0x%zx bytes for %s failed: %s", max_vaddr, loader->path,
446*c9945492SAndroid Build Coastguard Worker ri_strerror(g_errno));
447*c9945492SAndroid Build Coastguard Worker }
448*c9945492SAndroid Build Coastguard Worker
449*c9945492SAndroid Build Coastguard Worker // Map each PT_LOAD.
450*c9945492SAndroid Build Coastguard Worker for (size_t i = 0; i < phdr_count; ++i) {
451*c9945492SAndroid Build Coastguard Worker if (phdr[i].p_type == PT_LOAD) {
452*c9945492SAndroid Build Coastguard Worker size_t start = PAGE_START(phdr[i].p_vaddr);
453*c9945492SAndroid Build Coastguard Worker const size_t end = PAGE_END(phdr[i].p_vaddr + phdr[i].p_memsz);
454*c9945492SAndroid Build Coastguard Worker if (phdr[i].p_filesz > 0) {
455*c9945492SAndroid Build Coastguard Worker const size_t file_end = phdr[i].p_vaddr + phdr[i].p_filesz;
456*c9945492SAndroid Build Coastguard Worker void* tmp = ri_mmap((char*)loader_vaddr + start,
457*c9945492SAndroid Build Coastguard Worker file_end - start,
458*c9945492SAndroid Build Coastguard Worker elf_flags_to_prot(phdr[i].p_flags),
459*c9945492SAndroid Build Coastguard Worker MAP_PRIVATE | MAP_FIXED, loader->fd, PAGE_START(phdr[i].p_offset));
460*c9945492SAndroid Build Coastguard Worker if (tmp == (void*)MAP_FAILED) {
461*c9945492SAndroid Build Coastguard Worker fatal("PT_LOAD mmap failed (%s segment #%zu): %s", loader->path, i,
462*c9945492SAndroid Build Coastguard Worker ri_strerror(g_errno));
463*c9945492SAndroid Build Coastguard Worker }
464*c9945492SAndroid Build Coastguard Worker start = file_end;
465*c9945492SAndroid Build Coastguard Worker if (phdr[i].p_flags & PF_W) {
466*c9945492SAndroid Build Coastguard Worker // The bytes between p_filesz and PAGE_END(p_filesz) currently come from the file mapping,
467*c9945492SAndroid Build Coastguard Worker // but they need to be zeroed. (Apparently this zeroing isn't necessary if the segment isn't
468*c9945492SAndroid Build Coastguard Worker // writable, and zeroing a non-writable page would be inconvenient.)
469*c9945492SAndroid Build Coastguard Worker ri_memset((char*)loader_vaddr + start, '\0', PAGE_END(start) - start);
470*c9945492SAndroid Build Coastguard Worker }
471*c9945492SAndroid Build Coastguard Worker start = PAGE_END(start);
472*c9945492SAndroid Build Coastguard Worker }
473*c9945492SAndroid Build Coastguard Worker if (start < end) {
474*c9945492SAndroid Build Coastguard Worker // The memory is already zeroed, because it comes from an anonymous file mapping. Just set
475*c9945492SAndroid Build Coastguard Worker // the protections correctly.
476*c9945492SAndroid Build Coastguard Worker int result = ri_mprotect((char*)loader_vaddr + start, end - start,
477*c9945492SAndroid Build Coastguard Worker elf_flags_to_prot(phdr[i].p_flags));
478*c9945492SAndroid Build Coastguard Worker if (result != 0) {
479*c9945492SAndroid Build Coastguard Worker fatal("mprotect of PT_LOAD failed (%s segment #%zu): %s", loader->path, i,
480*c9945492SAndroid Build Coastguard Worker ri_strerror(g_errno));
481*c9945492SAndroid Build Coastguard Worker }
482*c9945492SAndroid Build Coastguard Worker }
483*c9945492SAndroid Build Coastguard Worker }
484*c9945492SAndroid Build Coastguard Worker }
485*c9945492SAndroid Build Coastguard Worker
486*c9945492SAndroid Build Coastguard Worker return (LoadedInterp) {
487*c9945492SAndroid Build Coastguard Worker .base_addr = loader_vaddr,
488*c9945492SAndroid Build Coastguard Worker .entry = (EntryFunc*)((uintptr_t)loader_vaddr + hdr->e_entry),
489*c9945492SAndroid Build Coastguard Worker };
490*c9945492SAndroid Build Coastguard Worker }
491*c9945492SAndroid Build Coastguard Worker
492*c9945492SAndroid Build Coastguard Worker typedef struct {
493*c9945492SAndroid Build Coastguard Worker ElfW(Phdr)* phdr;
494*c9945492SAndroid Build Coastguard Worker size_t phdr_count;
495*c9945492SAndroid Build Coastguard Worker uintptr_t load_bias;
496*c9945492SAndroid Build Coastguard Worker uintptr_t page_size;
497*c9945492SAndroid Build Coastguard Worker char* search_paths;
498*c9945492SAndroid Build Coastguard Worker ElfW(Ehdr)* ehdr;
499*c9945492SAndroid Build Coastguard Worker ElfW(Phdr)* first_load;
500*c9945492SAndroid Build Coastguard Worker bool secure;
501*c9945492SAndroid Build Coastguard Worker } ExeInfo;
502*c9945492SAndroid Build Coastguard Worker
get_exe_info(const KernelArguments * args)503*c9945492SAndroid Build Coastguard Worker static ExeInfo get_exe_info(const KernelArguments* args) {
504*c9945492SAndroid Build Coastguard Worker ExeInfo result = { 0 };
505*c9945492SAndroid Build Coastguard Worker result.phdr = (ElfW(Phdr)*)ri_getauxval(args, AT_PHDR, false);
506*c9945492SAndroid Build Coastguard Worker result.phdr_count = ri_getauxval(args, AT_PHNUM, false);
507*c9945492SAndroid Build Coastguard Worker result.page_size = ri_getauxval(args, AT_PAGESZ, false);
508*c9945492SAndroid Build Coastguard Worker
509*c9945492SAndroid Build Coastguard Worker unsigned long uid = ri_getauxval(args, AT_UID, false);
510*c9945492SAndroid Build Coastguard Worker unsigned long euid = ri_getauxval(args, AT_EUID, false);
511*c9945492SAndroid Build Coastguard Worker unsigned long gid = ri_getauxval(args, AT_GID, false);
512*c9945492SAndroid Build Coastguard Worker unsigned long egid = ri_getauxval(args, AT_EGID, false);
513*c9945492SAndroid Build Coastguard Worker unsigned long secure = ri_getauxval(args, AT_SECURE, true);
514*c9945492SAndroid Build Coastguard Worker result.secure = uid != euid || gid != egid || secure;
515*c9945492SAndroid Build Coastguard Worker
516*c9945492SAndroid Build Coastguard Worker debug("orig phdr = %p", (void*)result.phdr);
517*c9945492SAndroid Build Coastguard Worker debug("orig phnum = %zu", result.phdr_count);
518*c9945492SAndroid Build Coastguard Worker
519*c9945492SAndroid Build Coastguard Worker for (size_t i = 0; i < result.phdr_count; ++i) {
520*c9945492SAndroid Build Coastguard Worker if (result.phdr[i].p_type == PT_DYNAMIC) {
521*c9945492SAndroid Build Coastguard Worker result.load_bias = (uintptr_t)&_DYNAMIC - result.phdr[i].p_vaddr;
522*c9945492SAndroid Build Coastguard Worker }
523*c9945492SAndroid Build Coastguard Worker }
524*c9945492SAndroid Build Coastguard Worker debug("load_bias = 0x%lx", (unsigned long)result.load_bias);
525*c9945492SAndroid Build Coastguard Worker
526*c9945492SAndroid Build Coastguard Worker for (size_t i = 0; i < result.phdr_count; ++i) {
527*c9945492SAndroid Build Coastguard Worker ElfW(Phdr)* phdr = &result.phdr[i];
528*c9945492SAndroid Build Coastguard Worker if (phdr->p_type != PT_LOAD) continue;
529*c9945492SAndroid Build Coastguard Worker result.first_load = phdr;
530*c9945492SAndroid Build Coastguard Worker if (phdr->p_offset != 0) {
531*c9945492SAndroid Build Coastguard Worker fatal("expected zero p_offset for first PT_LOAD, found 0x%zx instead",
532*c9945492SAndroid Build Coastguard Worker (size_t)phdr->p_offset);
533*c9945492SAndroid Build Coastguard Worker }
534*c9945492SAndroid Build Coastguard Worker result.ehdr = (ElfW(Ehdr)*)(phdr->p_vaddr + result.load_bias);
535*c9945492SAndroid Build Coastguard Worker break;
536*c9945492SAndroid Build Coastguard Worker }
537*c9945492SAndroid Build Coastguard Worker debug("ehdr = %p", (void*)result.ehdr);
538*c9945492SAndroid Build Coastguard Worker
539*c9945492SAndroid Build Coastguard Worker ElfW(Word) runpath_offset = -1;
540*c9945492SAndroid Build Coastguard Worker char* strtab = NULL;
541*c9945492SAndroid Build Coastguard Worker for (ElfW(Dyn)* dyn = _DYNAMIC; dyn->d_tag != DT_NULL; dyn++) {
542*c9945492SAndroid Build Coastguard Worker switch (dyn->d_tag) {
543*c9945492SAndroid Build Coastguard Worker case DT_RUNPATH:
544*c9945492SAndroid Build Coastguard Worker runpath_offset = dyn->d_un.d_val;
545*c9945492SAndroid Build Coastguard Worker break;
546*c9945492SAndroid Build Coastguard Worker case DT_RPATH:
547*c9945492SAndroid Build Coastguard Worker if (runpath_offset == -1) runpath_offset = dyn->d_un.d_val;
548*c9945492SAndroid Build Coastguard Worker break;
549*c9945492SAndroid Build Coastguard Worker case DT_STRTAB:
550*c9945492SAndroid Build Coastguard Worker strtab = (char*)(dyn->d_un.d_ptr + result.load_bias);
551*c9945492SAndroid Build Coastguard Worker break;
552*c9945492SAndroid Build Coastguard Worker }
553*c9945492SAndroid Build Coastguard Worker }
554*c9945492SAndroid Build Coastguard Worker
555*c9945492SAndroid Build Coastguard Worker if (strtab && runpath_offset != -1) {
556*c9945492SAndroid Build Coastguard Worker result.search_paths = strtab + runpath_offset;
557*c9945492SAndroid Build Coastguard Worker debug("dt_runpath = %s", result.search_paths);
558*c9945492SAndroid Build Coastguard Worker }
559*c9945492SAndroid Build Coastguard Worker return result;
560*c9945492SAndroid Build Coastguard Worker }
561*c9945492SAndroid Build Coastguard Worker
562*c9945492SAndroid Build Coastguard Worker // Loaders typically read the PT_INTERP of the executable, e.g. to set a pathname on the loader.
563*c9945492SAndroid Build Coastguard Worker // glibc insists on the executable having PT_INTERP, and aborts if it's missing. Musl passes it
564*c9945492SAndroid Build Coastguard Worker // to debuggers to find symbols for the loader, which includes all the libc symbols.
565*c9945492SAndroid Build Coastguard Worker //
566*c9945492SAndroid Build Coastguard Worker // Make a copy of the phdr table and insert PT_INTERP into the copy.
567*c9945492SAndroid Build Coastguard Worker //
insert_pt_interp_into_phdr_table(const KernelArguments * args,const ExeInfo * exe,const char * loader_realpath)568*c9945492SAndroid Build Coastguard Worker static void insert_pt_interp_into_phdr_table(const KernelArguments* args, const ExeInfo* exe,
569*c9945492SAndroid Build Coastguard Worker const char* loader_realpath) {
570*c9945492SAndroid Build Coastguard Worker // Reserve extra space for the inserted PT_PHDR and PT_INTERP segments and a null terminator.
571*c9945492SAndroid Build Coastguard Worker if (exe->phdr_count + 3 > sizeof(replacement_phdr_table) / sizeof(replacement_phdr_table[0])) {
572*c9945492SAndroid Build Coastguard Worker fatal("too many phdr table entries in executable");
573*c9945492SAndroid Build Coastguard Worker }
574*c9945492SAndroid Build Coastguard Worker
575*c9945492SAndroid Build Coastguard Worker ElfW(Phdr) newPhdr = {
576*c9945492SAndroid Build Coastguard Worker .p_type = PT_PHDR,
577*c9945492SAndroid Build Coastguard Worker // The replacement phdr is in the BSS section, which has no file location.
578*c9945492SAndroid Build Coastguard Worker // Use 0 for the offset. If this causes a problem the replacement phdr could
579*c9945492SAndroid Build Coastguard Worker // be moved to the data section and the correct p_offset calculated.
580*c9945492SAndroid Build Coastguard Worker .p_offset = 0,
581*c9945492SAndroid Build Coastguard Worker .p_vaddr = (uintptr_t)&replacement_phdr_table - exe->load_bias,
582*c9945492SAndroid Build Coastguard Worker .p_paddr = (uintptr_t)&replacement_phdr_table - exe->load_bias,
583*c9945492SAndroid Build Coastguard Worker .p_memsz = (exe->phdr_count + 1) * sizeof(ElfW(Phdr)),
584*c9945492SAndroid Build Coastguard Worker .p_filesz = (exe->phdr_count + 1) * sizeof(ElfW(Phdr)),
585*c9945492SAndroid Build Coastguard Worker .p_flags = PF_R,
586*c9945492SAndroid Build Coastguard Worker .p_align = alignof(ElfW(Phdr)),
587*c9945492SAndroid Build Coastguard Worker };
588*c9945492SAndroid Build Coastguard Worker
589*c9945492SAndroid Build Coastguard Worker ElfW(Phdr*) cur = replacement_phdr_table;
590*c9945492SAndroid Build Coastguard Worker if (exe->phdr[0].p_type != PT_PHDR) {
591*c9945492SAndroid Build Coastguard Worker // ld.bfd does not insert a PT_PHDR if there is no PT_INTERP, fake one.
592*c9945492SAndroid Build Coastguard Worker // It has to be first. We're adding an entry so increase memsz and filesz.
593*c9945492SAndroid Build Coastguard Worker newPhdr.p_memsz += sizeof(ElfW(Phdr));
594*c9945492SAndroid Build Coastguard Worker newPhdr.p_filesz += sizeof(ElfW(Phdr));
595*c9945492SAndroid Build Coastguard Worker *cur = newPhdr;
596*c9945492SAndroid Build Coastguard Worker ++cur;
597*c9945492SAndroid Build Coastguard Worker }
598*c9945492SAndroid Build Coastguard Worker
599*c9945492SAndroid Build Coastguard Worker for (size_t i = 0; i < exe->phdr_count; ++i) {
600*c9945492SAndroid Build Coastguard Worker switch (exe->phdr[i].p_type) {
601*c9945492SAndroid Build Coastguard Worker case 0:
602*c9945492SAndroid Build Coastguard Worker fatal("unexpected null phdr entry at index %zu", i);
603*c9945492SAndroid Build Coastguard Worker break;
604*c9945492SAndroid Build Coastguard Worker case PT_PHDR:
605*c9945492SAndroid Build Coastguard Worker *cur = newPhdr;
606*c9945492SAndroid Build Coastguard Worker break;
607*c9945492SAndroid Build Coastguard Worker default:
608*c9945492SAndroid Build Coastguard Worker *cur = exe->phdr[i];
609*c9945492SAndroid Build Coastguard Worker }
610*c9945492SAndroid Build Coastguard Worker ++cur;
611*c9945492SAndroid Build Coastguard Worker }
612*c9945492SAndroid Build Coastguard Worker
613*c9945492SAndroid Build Coastguard Worker // Insert PT_INTERP at the end.
614*c9945492SAndroid Build Coastguard Worker cur->p_type = PT_INTERP;
615*c9945492SAndroid Build Coastguard Worker cur->p_offset = 0;
616*c9945492SAndroid Build Coastguard Worker cur->p_vaddr = (uintptr_t)&replacement_interp - exe->load_bias;
617*c9945492SAndroid Build Coastguard Worker cur->p_paddr = cur->p_vaddr;
618*c9945492SAndroid Build Coastguard Worker cur->p_filesz = ri_strlen(replacement_interp) + 1;
619*c9945492SAndroid Build Coastguard Worker cur->p_memsz = ri_strlen(replacement_interp) + 1;
620*c9945492SAndroid Build Coastguard Worker cur->p_flags = PF_R;
621*c9945492SAndroid Build Coastguard Worker cur->p_align = 1;
622*c9945492SAndroid Build Coastguard Worker ++cur;
623*c9945492SAndroid Build Coastguard Worker
624*c9945492SAndroid Build Coastguard Worker ri_strcpy(replacement_interp, loader_realpath);
625*c9945492SAndroid Build Coastguard Worker
626*c9945492SAndroid Build Coastguard Worker debug("new phdr = %p", (void*)&replacement_phdr_table);
627*c9945492SAndroid Build Coastguard Worker debug("new phnum = %zu", cur - replacement_phdr_table);
628*c9945492SAndroid Build Coastguard Worker
629*c9945492SAndroid Build Coastguard Worker // Update the aux vector with the new phdr+phnum.
630*c9945492SAndroid Build Coastguard Worker for (size_t i = 0; i < args->auxv_count; ++i) {
631*c9945492SAndroid Build Coastguard Worker if (args->auxv[i].key == AT_PHDR) {
632*c9945492SAndroid Build Coastguard Worker args->auxv[i].value = (unsigned long)&replacement_phdr_table;
633*c9945492SAndroid Build Coastguard Worker } else if (args->auxv[i].key == AT_PHNUM) {
634*c9945492SAndroid Build Coastguard Worker args->auxv[i].value = cur - replacement_phdr_table;
635*c9945492SAndroid Build Coastguard Worker }
636*c9945492SAndroid Build Coastguard Worker }
637*c9945492SAndroid Build Coastguard Worker
638*c9945492SAndroid Build Coastguard Worker // AT_PHDR and AT_PHNUM are now updated to point to the replacement program
639*c9945492SAndroid Build Coastguard Worker // headers, but the e_phoff and e_phnum in the ELF headers still point to the
640*c9945492SAndroid Build Coastguard Worker // original program headers. dynlink.c doesn't use e_phoff value from the
641*c9945492SAndroid Build Coastguard Worker // main application's program headers. The e_phoff and e_phnum values could
642*c9945492SAndroid Build Coastguard Worker // be updated, but that would require using mprotect to allow modifications
643*c9945492SAndroid Build Coastguard Worker // to the read-only first page.
644*c9945492SAndroid Build Coastguard Worker }
645*c9945492SAndroid Build Coastguard Worker
realpath_fd(int fd,const char * orig_path,char * out,size_t len)646*c9945492SAndroid Build Coastguard Worker static void realpath_fd(int fd, const char* orig_path, char* out, size_t len) {
647*c9945492SAndroid Build Coastguard Worker char path[64];
648*c9945492SAndroid Build Coastguard Worker ri_strcpy(path, "/proc/self/fd/");
649*c9945492SAndroid Build Coastguard Worker ul_to_str(fd, path + ri_strlen(path), 10);
650*c9945492SAndroid Build Coastguard Worker ssize_t result = ri_readlink(path, out, len);
651*c9945492SAndroid Build Coastguard Worker if (result == -1) fatal("could not get realpath of %s: %s", orig_path, ri_strerror(g_errno));
652*c9945492SAndroid Build Coastguard Worker if ((size_t)result >= len) fatal("realpath of %s too long", orig_path);
653*c9945492SAndroid Build Coastguard Worker }
654*c9945492SAndroid Build Coastguard Worker
open_loader(const ExeInfo * exe,const char * path,OpenedLoader * loader)655*c9945492SAndroid Build Coastguard Worker static int open_loader(const ExeInfo* exe, const char* path, OpenedLoader* loader) {
656*c9945492SAndroid Build Coastguard Worker debug("trying to open '%s'", path);
657*c9945492SAndroid Build Coastguard Worker loader->fd = ri_open(path, O_RDONLY, 0);
658*c9945492SAndroid Build Coastguard Worker if (loader->fd < 0) {
659*c9945492SAndroid Build Coastguard Worker debug("could not open loader %s: %s", path, ri_strerror(g_errno));
660*c9945492SAndroid Build Coastguard Worker return -1;
661*c9945492SAndroid Build Coastguard Worker }
662*c9945492SAndroid Build Coastguard Worker
663*c9945492SAndroid Build Coastguard Worker ElfW(Ehdr) hdr;
664*c9945492SAndroid Build Coastguard Worker ssize_t l = ri_pread(loader->fd, &hdr, sizeof(hdr), 0);
665*c9945492SAndroid Build Coastguard Worker if (l < 0) {
666*c9945492SAndroid Build Coastguard Worker debug("reading elf header from %s failed: %s", path, ri_strerror(g_errno));
667*c9945492SAndroid Build Coastguard Worker return -1;
668*c9945492SAndroid Build Coastguard Worker }
669*c9945492SAndroid Build Coastguard Worker if (l != sizeof(hdr)) {
670*c9945492SAndroid Build Coastguard Worker debug("file %s too short to contain elf header", path);
671*c9945492SAndroid Build Coastguard Worker return -1;
672*c9945492SAndroid Build Coastguard Worker }
673*c9945492SAndroid Build Coastguard Worker
674*c9945492SAndroid Build Coastguard Worker if (hdr.e_ident[0] != ELFMAG0 ||
675*c9945492SAndroid Build Coastguard Worker hdr.e_ident[1] != ELFMAG1 ||
676*c9945492SAndroid Build Coastguard Worker hdr.e_ident[2] != ELFMAG2 ||
677*c9945492SAndroid Build Coastguard Worker hdr.e_ident[3] != ELFMAG3) {
678*c9945492SAndroid Build Coastguard Worker debug("file %s is not an elf file", path);
679*c9945492SAndroid Build Coastguard Worker return -1;
680*c9945492SAndroid Build Coastguard Worker }
681*c9945492SAndroid Build Coastguard Worker
682*c9945492SAndroid Build Coastguard Worker if (hdr.e_machine != exe->ehdr->e_machine) {
683*c9945492SAndroid Build Coastguard Worker debug("incorrect elf machine for loader %s, expected %d got %d",
684*c9945492SAndroid Build Coastguard Worker path, exe->ehdr->e_machine, hdr.e_machine);
685*c9945492SAndroid Build Coastguard Worker return -1;
686*c9945492SAndroid Build Coastguard Worker }
687*c9945492SAndroid Build Coastguard Worker
688*c9945492SAndroid Build Coastguard Worker if (hdr.e_ident[EI_CLASS] != exe->ehdr->e_ident[EI_CLASS]) {
689*c9945492SAndroid Build Coastguard Worker debug("incorrect elf class for loader %s, expected %d got %d",
690*c9945492SAndroid Build Coastguard Worker path, exe->ehdr->e_ident[EI_CLASS], hdr.e_ident[EI_CLASS]);
691*c9945492SAndroid Build Coastguard Worker return -1;
692*c9945492SAndroid Build Coastguard Worker }
693*c9945492SAndroid Build Coastguard Worker
694*c9945492SAndroid Build Coastguard Worker realpath_fd(loader->fd, path, loader->path, sizeof(loader->path));
695*c9945492SAndroid Build Coastguard Worker
696*c9945492SAndroid Build Coastguard Worker return 0;
697*c9945492SAndroid Build Coastguard Worker }
698*c9945492SAndroid Build Coastguard Worker
open_rel_loader(const ExeInfo * exe,const char * dir,const char * rel,OpenedLoader * loader)699*c9945492SAndroid Build Coastguard Worker static int open_rel_loader(const ExeInfo* exe, const char* dir, const char* rel, OpenedLoader* loader) {
700*c9945492SAndroid Build Coastguard Worker char buf[PATH_MAX];
701*c9945492SAndroid Build Coastguard Worker
702*c9945492SAndroid Build Coastguard Worker size_t dir_len = ri_strlen(dir);
703*c9945492SAndroid Build Coastguard Worker
704*c9945492SAndroid Build Coastguard Worker if (dir_len + (dir_len == 0 ? 1 : 0) + ri_strlen(rel) + 2 > sizeof(buf)) {
705*c9945492SAndroid Build Coastguard Worker debug("path to loader exceeds PATH_MAX: %s/%s", dir, rel);
706*c9945492SAndroid Build Coastguard Worker return 1;
707*c9945492SAndroid Build Coastguard Worker }
708*c9945492SAndroid Build Coastguard Worker
709*c9945492SAndroid Build Coastguard Worker if (dir_len == 0) {
710*c9945492SAndroid Build Coastguard Worker ri_strcpy(buf, ".");
711*c9945492SAndroid Build Coastguard Worker } else {
712*c9945492SAndroid Build Coastguard Worker ri_strcpy(buf, dir);
713*c9945492SAndroid Build Coastguard Worker if (dir[dir_len-1] != '/') {
714*c9945492SAndroid Build Coastguard Worker ri_strcat(buf, "/");
715*c9945492SAndroid Build Coastguard Worker }
716*c9945492SAndroid Build Coastguard Worker }
717*c9945492SAndroid Build Coastguard Worker ri_strcat(buf, rel);
718*c9945492SAndroid Build Coastguard Worker
719*c9945492SAndroid Build Coastguard Worker return open_loader(exe, buf, loader);
720*c9945492SAndroid Build Coastguard Worker }
721*c9945492SAndroid Build Coastguard Worker
get_origin(char * buf,size_t buf_len)722*c9945492SAndroid Build Coastguard Worker static void get_origin(char* buf, size_t buf_len) {
723*c9945492SAndroid Build Coastguard Worker ssize_t len = ri_readlink("/proc/self/exe", buf, buf_len);
724*c9945492SAndroid Build Coastguard Worker if (len <= 0 || (size_t)len >= buf_len) {
725*c9945492SAndroid Build Coastguard Worker fatal("could not readlink /proc/self/exe: %s", ri_strerror(g_errno));
726*c9945492SAndroid Build Coastguard Worker }
727*c9945492SAndroid Build Coastguard Worker buf[len] = '\0';
728*c9945492SAndroid Build Coastguard Worker
729*c9945492SAndroid Build Coastguard Worker ri_dirname(buf);
730*c9945492SAndroid Build Coastguard Worker }
731*c9945492SAndroid Build Coastguard Worker
search_path_list_for_loader(const ExeInfo * exe,const char * loader_rel_path,const char * search_path,const char * search_path_name,bool expand_origin,OpenedLoader * loader)732*c9945492SAndroid Build Coastguard Worker static int search_path_list_for_loader(const ExeInfo* exe, const char* loader_rel_path, const char* search_path,
733*c9945492SAndroid Build Coastguard Worker const char* search_path_name, bool expand_origin, OpenedLoader *loader) {
734*c9945492SAndroid Build Coastguard Worker char origin_buf[PATH_MAX];
735*c9945492SAndroid Build Coastguard Worker char* origin = NULL;
736*c9945492SAndroid Build Coastguard Worker
737*c9945492SAndroid Build Coastguard Worker const char* p = search_path;
738*c9945492SAndroid Build Coastguard Worker while (p && p[0]) {
739*c9945492SAndroid Build Coastguard Worker const char* start = p;
740*c9945492SAndroid Build Coastguard Worker const char* end = ri_strchr(p, ':');
741*c9945492SAndroid Build Coastguard Worker if (end == NULL) {
742*c9945492SAndroid Build Coastguard Worker end = start + ri_strlen(p);
743*c9945492SAndroid Build Coastguard Worker p = NULL;
744*c9945492SAndroid Build Coastguard Worker } else {
745*c9945492SAndroid Build Coastguard Worker p = end + 1;
746*c9945492SAndroid Build Coastguard Worker }
747*c9945492SAndroid Build Coastguard Worker size_t n = end - start;
748*c9945492SAndroid Build Coastguard Worker char search_path_entry[PATH_MAX];
749*c9945492SAndroid Build Coastguard Worker if (n >= sizeof(search_path_entry)) {
750*c9945492SAndroid Build Coastguard Worker // Too long, skip.
751*c9945492SAndroid Build Coastguard Worker debug("%s entry too long: %s", search_path_name, start);
752*c9945492SAndroid Build Coastguard Worker continue;
753*c9945492SAndroid Build Coastguard Worker }
754*c9945492SAndroid Build Coastguard Worker
755*c9945492SAndroid Build Coastguard Worker ri_memcpy(search_path_entry, start, n);
756*c9945492SAndroid Build Coastguard Worker search_path_entry[n] = '\0';
757*c9945492SAndroid Build Coastguard Worker
758*c9945492SAndroid Build Coastguard Worker char buf[PATH_MAX];
759*c9945492SAndroid Build Coastguard Worker char* d = NULL;
760*c9945492SAndroid Build Coastguard Worker if (expand_origin) {
761*c9945492SAndroid Build Coastguard Worker d = ri_strchr(search_path_entry, '$');
762*c9945492SAndroid Build Coastguard Worker }
763*c9945492SAndroid Build Coastguard Worker if (d && (!ri_strncmp(d, "$ORIGIN", 7) || !ri_strncmp(d, "${ORIGIN}", 9))) {
764*c9945492SAndroid Build Coastguard Worker if (!origin) {
765*c9945492SAndroid Build Coastguard Worker get_origin(origin_buf, sizeof(origin_buf));
766*c9945492SAndroid Build Coastguard Worker origin = origin_buf;
767*c9945492SAndroid Build Coastguard Worker }
768*c9945492SAndroid Build Coastguard Worker
769*c9945492SAndroid Build Coastguard Worker size_t s = 7;
770*c9945492SAndroid Build Coastguard Worker if (d[1] == '{') {
771*c9945492SAndroid Build Coastguard Worker s += 2;
772*c9945492SAndroid Build Coastguard Worker }
773*c9945492SAndroid Build Coastguard Worker ri_memcpy(buf, search_path_entry, d - search_path_entry);
774*c9945492SAndroid Build Coastguard Worker buf[d - search_path_entry] = '\0';
775*c9945492SAndroid Build Coastguard Worker if (ri_strlen(buf) + ri_strlen(origin) + ri_strlen(d+s) >= sizeof(buf)) {
776*c9945492SAndroid Build Coastguard Worker debug("path to loader %s%s%s too long", buf, origin, d+s);
777*c9945492SAndroid Build Coastguard Worker continue;
778*c9945492SAndroid Build Coastguard Worker }
779*c9945492SAndroid Build Coastguard Worker
780*c9945492SAndroid Build Coastguard Worker ri_strcat(buf, origin);
781*c9945492SAndroid Build Coastguard Worker ri_strcat(buf, d+s);
782*c9945492SAndroid Build Coastguard Worker } else {
783*c9945492SAndroid Build Coastguard Worker ri_strcpy(buf, search_path_entry);
784*c9945492SAndroid Build Coastguard Worker }
785*c9945492SAndroid Build Coastguard Worker debug("trying loader %s at %s", loader_rel_path, buf);
786*c9945492SAndroid Build Coastguard Worker if (!open_rel_loader(exe, buf, loader_rel_path, loader)) {
787*c9945492SAndroid Build Coastguard Worker debug("opened loader %s at %s", loader_rel_path, buf);
788*c9945492SAndroid Build Coastguard Worker return 0;
789*c9945492SAndroid Build Coastguard Worker }
790*c9945492SAndroid Build Coastguard Worker }
791*c9945492SAndroid Build Coastguard Worker
792*c9945492SAndroid Build Coastguard Worker return -1;
793*c9945492SAndroid Build Coastguard Worker }
794*c9945492SAndroid Build Coastguard Worker
find_and_open_loader(const ExeInfo * exe,const char * ld_library_path,OpenedLoader * loader)795*c9945492SAndroid Build Coastguard Worker static int find_and_open_loader(const ExeInfo* exe, const char* ld_library_path, OpenedLoader* loader) {
796*c9945492SAndroid Build Coastguard Worker const char* loader_rel_path = LOADER_PATH;
797*c9945492SAndroid Build Coastguard Worker
798*c9945492SAndroid Build Coastguard Worker if (loader_rel_path[0] == '/') {
799*c9945492SAndroid Build Coastguard Worker return open_loader(exe, loader_rel_path, loader);
800*c9945492SAndroid Build Coastguard Worker }
801*c9945492SAndroid Build Coastguard Worker
802*c9945492SAndroid Build Coastguard Worker if (exe->secure) {
803*c9945492SAndroid Build Coastguard Worker fatal("relinterp not supported for secure executables");
804*c9945492SAndroid Build Coastguard Worker }
805*c9945492SAndroid Build Coastguard Worker
806*c9945492SAndroid Build Coastguard Worker if (!search_path_list_for_loader(exe, loader_rel_path, ld_library_path, "LD_LIBRARY_PATH", false, loader)) {
807*c9945492SAndroid Build Coastguard Worker return 0;
808*c9945492SAndroid Build Coastguard Worker }
809*c9945492SAndroid Build Coastguard Worker
810*c9945492SAndroid Build Coastguard Worker if (!exe->search_paths || ri_strlen(exe->search_paths) == 0) {
811*c9945492SAndroid Build Coastguard Worker // If no DT_RUNPATH search relative to the exe.
812*c9945492SAndroid Build Coastguard Worker char origin[PATH_MAX];
813*c9945492SAndroid Build Coastguard Worker get_origin(origin, sizeof(origin));
814*c9945492SAndroid Build Coastguard Worker return open_rel_loader(exe, origin, loader_rel_path, loader);
815*c9945492SAndroid Build Coastguard Worker }
816*c9945492SAndroid Build Coastguard Worker
817*c9945492SAndroid Build Coastguard Worker if (!search_path_list_for_loader(exe, loader_rel_path, exe->search_paths, "rpath", true, loader)) {
818*c9945492SAndroid Build Coastguard Worker return 0;
819*c9945492SAndroid Build Coastguard Worker }
820*c9945492SAndroid Build Coastguard Worker
821*c9945492SAndroid Build Coastguard Worker fatal("unable to find loader %s in rpath %s", loader_rel_path, exe->search_paths);
822*c9945492SAndroid Build Coastguard Worker }
823*c9945492SAndroid Build Coastguard Worker
824*c9945492SAndroid Build Coastguard Worker // Use a trick to determine whether the executable has been relocated yet. This variable points to
825*c9945492SAndroid Build Coastguard Worker // a variable in libc. It will be NULL if and only if the program hasn't been linked yet. This
826*c9945492SAndroid Build Coastguard Worker // should accommodate these situations:
827*c9945492SAndroid Build Coastguard Worker // - The program was actually statically-linked instead.
828*c9945492SAndroid Build Coastguard Worker // - Either a PIE or non-PIE dynamic executable.
829*c9945492SAndroid Build Coastguard Worker // - Any situation where the loader calls the executable's _start:
830*c9945492SAndroid Build Coastguard Worker // - In normal operation, the kernel calls the executable's _start, _start jumps to the loader's
831*c9945492SAndroid Build Coastguard Worker // entry point, which jumps to _start again after linking it.
832*c9945492SAndroid Build Coastguard Worker // - The executable actually has its PT_INTERP set after all.
833*c9945492SAndroid Build Coastguard Worker // - The user runs the loader, passing it the path of the executable.
834*c9945492SAndroid Build Coastguard Worker // This C file must always be compiled as PIC, or else the linker will use a COPY relocation and
835*c9945492SAndroid Build Coastguard Worker // duplicate "environ" into the executable.
is_exe_relocated(void)836*c9945492SAndroid Build Coastguard Worker static bool is_exe_relocated(void) {
837*c9945492SAndroid Build Coastguard Worker // Use the GOT to get the address of environ.
838*c9945492SAndroid Build Coastguard Worker extern char** environ;
839*c9945492SAndroid Build Coastguard Worker void* read_environ = optimizer_barrier(&environ);
840*c9945492SAndroid Build Coastguard Worker debug("read_environ = %p", read_environ);
841*c9945492SAndroid Build Coastguard Worker return read_environ != NULL;
842*c9945492SAndroid Build Coastguard Worker }
843*c9945492SAndroid Build Coastguard Worker
_start_c(long * raw_args)844*c9945492SAndroid Build Coastguard Worker void _start_c(long* raw_args) {
845*c9945492SAndroid Build Coastguard Worker const KernelArguments args = read_args(raw_args);
846*c9945492SAndroid Build Coastguard Worker const char* ld_library_path = NULL;
847*c9945492SAndroid Build Coastguard Worker
848*c9945492SAndroid Build Coastguard Worker for (size_t i = 0; i < args.envp_count; ++i) {
849*c9945492SAndroid Build Coastguard Worker if (!ri_strcmp(args.envp[i], "RELINTERP_DEBUG=1")) {
850*c9945492SAndroid Build Coastguard Worker g_debug = true;
851*c9945492SAndroid Build Coastguard Worker }
852*c9945492SAndroid Build Coastguard Worker if (!ri_strncmp(args.envp[i], "LD_LIBRARY_PATH=", 16)) {
853*c9945492SAndroid Build Coastguard Worker ld_library_path = args.envp[i] + 16;
854*c9945492SAndroid Build Coastguard Worker }
855*c9945492SAndroid Build Coastguard Worker }
856*c9945492SAndroid Build Coastguard Worker if (args.argc >= 1) {
857*c9945492SAndroid Build Coastguard Worker g_prog_name = args.argv[0];
858*c9945492SAndroid Build Coastguard Worker }
859*c9945492SAndroid Build Coastguard Worker
860*c9945492SAndroid Build Coastguard Worker if (is_exe_relocated()) {
861*c9945492SAndroid Build Coastguard Worker debug("exe is already relocated, starting main executable");
862*c9945492SAndroid Build Coastguard Worker int argc = raw_args[0];
863*c9945492SAndroid Build Coastguard Worker char **argv = (void *)(raw_args+1);
864*c9945492SAndroid Build Coastguard Worker __libc_start_main(main, argc, argv, _init, _fini, 0);
865*c9945492SAndroid Build Coastguard Worker }
866*c9945492SAndroid Build Coastguard Worker
867*c9945492SAndroid Build Coastguard Worker debug("entering relinterp");
868*c9945492SAndroid Build Coastguard Worker
869*c9945492SAndroid Build Coastguard Worker const ExeInfo exe = get_exe_info(&args);
870*c9945492SAndroid Build Coastguard Worker g_page_size = exe.page_size;
871*c9945492SAndroid Build Coastguard Worker
872*c9945492SAndroid Build Coastguard Worker OpenedLoader loader;
873*c9945492SAndroid Build Coastguard Worker if (find_and_open_loader(&exe, ld_library_path, &loader)) {
874*c9945492SAndroid Build Coastguard Worker fatal("failed to open loader");
875*c9945492SAndroid Build Coastguard Worker }
876*c9945492SAndroid Build Coastguard Worker off_t len = ri_lseek(loader.fd, 0, SEEK_END);
877*c9945492SAndroid Build Coastguard Worker if (len == (off_t)-1) fatal("lseek on %s failed: %s", loader.path, ri_strerror(g_errno));
878*c9945492SAndroid Build Coastguard Worker
879*c9945492SAndroid Build Coastguard Worker void* loader_data = ri_mmap(NULL, len, PROT_READ, MAP_PRIVATE, loader.fd, 0);
880*c9945492SAndroid Build Coastguard Worker if (loader_data == (void*)MAP_FAILED) {
881*c9945492SAndroid Build Coastguard Worker fatal("could not mmap %s: %s", loader.path, ri_strerror(g_errno));
882*c9945492SAndroid Build Coastguard Worker }
883*c9945492SAndroid Build Coastguard Worker
884*c9945492SAndroid Build Coastguard Worker LoadedInterp interp = load_interp(&loader, (ElfW(Ehdr)*)loader_data);
885*c9945492SAndroid Build Coastguard Worker if (ri_munmap(loader_data, len) != 0) fatal("munmap failed: %s", ri_strerror(g_errno));
886*c9945492SAndroid Build Coastguard Worker
887*c9945492SAndroid Build Coastguard Worker debug("original auxv:");
888*c9945492SAndroid Build Coastguard Worker dump_auxv(&args);
889*c9945492SAndroid Build Coastguard Worker
890*c9945492SAndroid Build Coastguard Worker // Create a virtual phdr table that includes PT_INTERP, for the benefit of loaders that read the
891*c9945492SAndroid Build Coastguard Worker // executable PT_INTERP.
892*c9945492SAndroid Build Coastguard Worker insert_pt_interp_into_phdr_table(&args, &exe, loader.path);
893*c9945492SAndroid Build Coastguard Worker ri_close(loader.fd);
894*c9945492SAndroid Build Coastguard Worker
895*c9945492SAndroid Build Coastguard Worker // TODO: /proc/pid/auxv isn't updated with the new auxv vector. Is it possible to update it?
896*c9945492SAndroid Build Coastguard Worker // XXX: If we try to update it, we'd use prctl(PR_SET_MM, PR_SET_MM_AUXV, &vec, size, 0)
897*c9945492SAndroid Build Coastguard Worker // Maybe updating it would be useful as a way to communicate the loader's base to a debugger.
898*c9945492SAndroid Build Coastguard Worker // e.g. lldb uses AT_BASE in the aux vector, but it caches the values at process startup, so
899*c9945492SAndroid Build Coastguard Worker // it wouldn't currently notice a changed value.
900*c9945492SAndroid Build Coastguard Worker
901*c9945492SAndroid Build Coastguard Worker // The loader uses AT_BASE to locate itself, so search for the entry and update it. Even though
902*c9945492SAndroid Build Coastguard Worker // its value is always zero, the kernel still includes the entry[0]. If this changes (or we want
903*c9945492SAndroid Build Coastguard Worker // to make weaker assumptions about the kernel's behavior), then we can copy the kernel arguments
904*c9945492SAndroid Build Coastguard Worker // onto the stack (e.g. using alloca) before jumping to the loader's entry point.
905*c9945492SAndroid Build Coastguard Worker // [0] https://github.com/torvalds/linux/blob/v5.13/fs/binfmt_elf.c#L263
906*c9945492SAndroid Build Coastguard Worker for (size_t i = 0; i < args.auxv_count; ++i) {
907*c9945492SAndroid Build Coastguard Worker if (args.auxv[i].key == AT_BASE) {
908*c9945492SAndroid Build Coastguard Worker args.auxv[i].value = (unsigned long)interp.base_addr;
909*c9945492SAndroid Build Coastguard Worker debug("new auxv:");
910*c9945492SAndroid Build Coastguard Worker dump_auxv(&args);
911*c9945492SAndroid Build Coastguard Worker debug("transferring to real loader");
912*c9945492SAndroid Build Coastguard Worker CRTJMP(interp.entry, raw_args);
913*c9945492SAndroid Build Coastguard Worker }
914*c9945492SAndroid Build Coastguard Worker }
915*c9945492SAndroid Build Coastguard Worker fatal("AT_BASE not found in aux vector");
916*c9945492SAndroid Build Coastguard Worker }
917*c9945492SAndroid Build Coastguard Worker
918*c9945492SAndroid Build Coastguard Worker
919*c9945492SAndroid Build Coastguard Worker // Normally gdb and lldb look for a symbol named "_dl_debug_state" in the
920*c9945492SAndroid Build Coastguard Worker // interpreter to get notified when the dynamic loader has modified the
921*c9945492SAndroid Build Coastguard Worker // list of shared libraries. When using relinterp, the debugger is not
922*c9945492SAndroid Build Coastguard Worker // aware of the interpreter (PT_INTERP is unset and auxv AT_BASE is 0) so it
923*c9945492SAndroid Build Coastguard Worker // doesn't know where to look for the symbol. It falls back to looking in the
924*c9945492SAndroid Build Coastguard Worker // executable, so provide a symbol for it to find. The dynamic loader will
925*c9945492SAndroid Build Coastguard Worker // need to forward its calls to its own _dl_debug_state symbol to this one.
926*c9945492SAndroid Build Coastguard Worker //
927*c9945492SAndroid Build Coastguard Worker // This has to be defined in a .c file because lldb looks for a symbol with
928*c9945492SAndroid Build Coastguard Worker // DWARF language type DW_LANG_C.
_dl_debug_state()929*c9945492SAndroid Build Coastguard Worker extern void _dl_debug_state() {
930*c9945492SAndroid Build Coastguard Worker }
931