/* $Id$ */ /* Copyright (c) 2010-2021 Pierre Pronchery */ /* This file is part of DeforaOS System Loader */ /* All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include /* macros */ # undef ELFFUNC # undef ELFTYPE #if ELFSIZE == 32 # define ELFFUNC(func) _do_ ## func ## 32 # define ELFTYPE(type) Elf ## 32 ## _ ## type #elif ELFSIZE == 64 # define ELFFUNC(func) _do_ ## func ## 64 # define ELFTYPE(type) Elf ## 64 ## _ ## type #else # error ELFSIZE is not defined #endif /* prototypes */ static int ELFFUNC(ldd)(char const * filename, FILE * fp, ELFTYPE(Ehdr) * ehdr, char const * ldpath); /* functions */ /* ldd */ static int ELFFUNC(phdr)(char const * filename, FILE * fp, ELFTYPE(Ehdr) * ehdr, ELFTYPE(Phdr) * phdr, char const * ldpath); static int ELFFUNC(phdr_dyn)(char const * filename, FILE * fp, ELFTYPE(Ehdr) * ehdr, ELFTYPE(Phdr) * phdr, ELFTYPE(Dyn) * dyn, char const * ldpath); static int ELFFUNC(phdr_dyn_print)(char const * filename, char const * rpath); static char * ELFFUNC(string)(char const * filename, FILE * fp, ELFTYPE(Ehdr) * ehdr, ELFTYPE(Addr) addr, ELFTYPE(Addr) index); static int ELFFUNC(ldd)(char const * filename, FILE * fp, ELFTYPE(Ehdr) * ehdr, char const * ldpath) { int ret; ELFTYPE(Phdr) * phdr; if(ehdr->e_phnum == 0) return -_error(filename, "No program header found", 1); if(ehdr->e_phentsize != sizeof(*phdr)) return -_error(filename, "Unexpected program header size", 1); if(fseek(fp, ehdr->e_phoff, SEEK_SET) != 0) return -_error(filename, strerror(errno), 1); if((phdr = malloc(sizeof(*phdr) * ehdr->e_phnum)) == NULL) return -_error(filename, strerror(errno), 1); ret = ELFFUNC(phdr)(filename, fp, ehdr, phdr, ldpath); free(phdr); return ret; } static int ELFFUNC(phdr)(char const * filename, FILE * fp, ELFTYPE(Ehdr) * ehdr, ELFTYPE(Phdr) * phdr, char const * ldpath) { int ret = 0; size_t i; size_t cnt; ELFTYPE(Dyn) * dyn; if(fread(phdr, sizeof(*phdr), ehdr->e_phnum, fp) != ehdr->e_phnum) { if(ferror(fp) != 0) ret = -_error(filename, strerror(errno), 1); else ret = -_error(filename, "Corrupted ELF file", 1); return ret; } for(i = 0, cnt = 0; i < ehdr->e_phnum; i++) { if(phdr[i].p_type != PT_DYNAMIC) continue; if(cnt++ == 0) printf("%s:\n", filename); if(fseek(fp, phdr[i].p_offset, SEEK_SET) != 0) { ret |= -_error(filename, strerror(errno), 1); continue; } if((dyn = malloc(phdr[i].p_filesz)) == NULL) { ret |= -_error(filename, strerror(errno), 1); continue; } if(fread(dyn, phdr[i].p_filesz, 1, fp) == 1) ret = ELFFUNC(phdr_dyn)(filename, fp, ehdr, &phdr[i], dyn, ldpath); else { if(ferror(fp) != 0) ret |= -_error(filename, strerror(errno), 1); else ret |= -_error(filename, "Corrupted ELF file", 1); } free(dyn); } if(cnt == 0) ret |= -_error(filename, "Not a dynamic ELF object", 1); return ret; } static int ELFFUNC(phdr_dyn)(char const * filename, FILE * fp, ELFTYPE(Ehdr) * ehdr, ELFTYPE(Phdr) * phdr, ELFTYPE(Dyn) * dyn, char const * ldpath) { ssize_t s = -1; ssize_t r = -1; size_t i; char * p; char * rpath = NULL; for(i = 0; (i + 1) * sizeof(*dyn) < phdr->p_filesz; i++) { if(dyn[i].d_tag == DT_NULL) break; if(dyn[i].d_tag == DT_STRTAB) s = i; else if(dyn[i].d_tag == DT_RPATH) r = i; } if(s < 0) return -_error(filename, "Missing string section", 1); if(s >= 0 && r >= 0) rpath = ELFFUNC(string)(filename, fp, ehdr, dyn[s].d_un.d_val, dyn[r].d_un.d_val); #ifdef DEBUG fprintf(stderr, "DEBUG: %s() strtab=%ld rpath=%ld \"%s\"\n", __func__, dyn[s].d_un.d_val, dyn[r].d_un.d_val, rpath); #endif for(i = 0; (i + 1) * sizeof(*dyn) < phdr->p_filesz; i++) { if(dyn[i].d_tag == DT_NULL) break; if(dyn[i].d_tag != DT_NEEDED) continue; if((p = ELFFUNC(string)(filename, fp, ehdr, dyn[s].d_un.d_ptr, dyn[i].d_un.d_val)) == NULL) continue; if(ELFFUNC(phdr_dyn_print)(p, ldpath) != 0 && ELFFUNC(phdr_dyn_print)(p, rpath) != 0 && ELFFUNC(phdr_dyn_print)(p, "/usr/lib:/lib") != 0) printf("\t%s\n", p); free(p); } return 0; } static int ELFFUNC(phdr_dyn_print)(char const * filename, char const * rpath) { size_t len = strlen(filename); size_t i; char * p; struct stat st; int res; #ifdef DEBUG fprintf(stderr, "DEBUG: %s(\"%s\", \"%s\")\n", __func__, filename, rpath); #endif if(rpath == NULL) return -1; for(i = 0;;) { if(rpath[i] != ':' && rpath[i] != '\0') { i++; continue; } p = malloc(i + len + 2); snprintf(p, i + 1, "%s", rpath); snprintf(&p[i], len + 2, "/%s", filename); if((res = stat(p, &st)) == 0) printf("\t%s => %s\n", filename, p); free(p); if(res == 0) return 0; if(rpath[i] == '\0') break; rpath += i + 1; i = 0; } return -1; } static char * ELFFUNC(string)(char const * filename, FILE * fp, ELFTYPE(Ehdr) * ehdr, ELFTYPE(Addr) addr, ELFTYPE(Addr) index) { char * ret; size_t i; ELFTYPE(Shdr) shdr; char * p = NULL; if(fseek(fp, ehdr->e_shoff, SEEK_SET) != 0) { _error(filename, strerror(errno), 1); return NULL; } for(i = 0; i < ehdr->e_shnum; i++) { if(fread(&shdr, sizeof(shdr), 1, fp) != 1) { if(ferror(fp) != 0) _error(filename, strerror(errno), 1); else _error(filename, "Corrupted ELF file", 1); break; } if(shdr.sh_type != SHT_STRTAB) continue; if(shdr.sh_addr != addr) continue; if(fseek(fp, shdr.sh_offset, SEEK_SET) != 0 || (p = malloc(shdr.sh_size)) == NULL) { _error(filename, strerror(errno), 1); break; } if(fread(p, sizeof(*p), shdr.sh_size, fp) != shdr.sh_size) { if(ferror(fp) != 0) _error(filename, strerror(errno), 1); else _error(filename, "Corrupted ELF file", 1); break; } for(i = index; i < shdr.sh_size; i++) { if(p[i] != '\0') continue; if((ret = strdup(&p[index])) == NULL) _error(filename, strerror(errno), 1); free(p); return ret; } break; } free(p); return NULL; }