1 /* 2 * Copyright (C) 2015 John Crispin <blogic@openwrt.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License version 2.1 6 * as published by the Free Software Foundation 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 14 #define _GNU_SOURCE 15 16 #include <string.h> 17 #include <sys/stat.h> 18 #include <fcntl.h> 19 #include <glob.h> 20 #include <elf.h> 21 #include <linux/limits.h> 22 23 #include <libubox/utils.h> 24 25 #include "elf.h" 26 #include "fs.h" 27 #include "log.h" 28 29 struct avl_tree libraries; 30 static LIST_HEAD(library_paths); 31 32 static void alloc_library_path(const char *path) 33 { 34 struct stat s; 35 if (stat(path, &s)) 36 return; 37 38 struct library_path *p; 39 char *_path; 40 41 p = calloc_a(sizeof(*p), 42 &_path, strlen(path) + 1); 43 if (!p) 44 return; 45 46 p->path = strcpy(_path, path); 47 48 list_add_tail(&p->list, &library_paths); 49 DEBUG("adding ld.so path %s\n", path); 50 } 51 52 /* 53 * path = full path 54 * name = soname/avl key 55 */ 56 void alloc_library(const char *path, const char *name) 57 { 58 struct library *l; 59 char *_name, *_path; 60 61 l = calloc_a(sizeof(*l), 62 &_path, strlen(path) + 1, 63 &_name, strlen(name) + 1); 64 if (!l) 65 return; 66 67 l->avl.key = l->name = strcpy(_name, name); 68 l->path = strcpy(_path, path); 69 70 avl_insert(&libraries, &l->avl); 71 DEBUG("adding library %s (%s)\n", path, name); 72 } 73 74 int lib_open(char **fullpath, const char *file) 75 { 76 struct library_path *p; 77 char path[PATH_MAX]; 78 int fd = -1; 79 80 *fullpath = NULL; 81 82 list_for_each_entry(p, &library_paths, list) { 83 snprintf(path, sizeof(path), "%s/%s", p->path, file); 84 fd = open(path, O_RDONLY|O_CLOEXEC); 85 if (fd >= 0) { 86 *fullpath = strdup(path); 87 break; 88 } 89 } 90 91 return fd; 92 } 93 94 const char* find_lib(const char *file) 95 { 96 struct library *l; 97 98 l = avl_find_element(&libraries, file, l, avl); 99 if (!l) 100 return NULL; 101 102 return l->path; 103 } 104 105 static int elf64_find_section(const char *map, unsigned int type, unsigned long *offset, unsigned long *size, unsigned long *vaddr) 106 { 107 Elf64_Ehdr *e; 108 Elf64_Phdr *ph; 109 int i; 110 111 e = (Elf64_Ehdr *) map; 112 ph = (Elf64_Phdr *) (map + e->e_phoff); 113 114 for (i = 0; i < e->e_phnum; i++) { 115 if (ph[i].p_type == type) { 116 *offset = ph[i].p_offset; 117 if (size) 118 *size = ph[i].p_filesz; 119 if (vaddr) 120 *vaddr = ph[i].p_vaddr; 121 return 0; 122 } 123 } 124 125 return -1; 126 } 127 128 static int elf32_find_section(const char *map, unsigned int type, unsigned long *offset, unsigned long *size, unsigned long *vaddr) 129 { 130 Elf32_Ehdr *e; 131 Elf32_Phdr *ph; 132 int i; 133 134 e = (Elf32_Ehdr *) map; 135 ph = (Elf32_Phdr *) (map + e->e_phoff); 136 137 for (i = 0; i < e->e_phnum; i++) { 138 if (ph[i].p_type == type) { 139 *offset = ph[i].p_offset; 140 if (size) 141 *size = ph[i].p_filesz; 142 if (vaddr) 143 *vaddr = ph[i].p_vaddr; 144 return 0; 145 } 146 } 147 148 return -1; 149 } 150 151 static int elf_find_section(const char *map, unsigned int type, unsigned long *offset, unsigned long *size, unsigned long *vaddr) 152 { 153 int clazz = map[EI_CLASS]; 154 155 if (clazz == ELFCLASS32) 156 return elf32_find_section(map, type, offset, size, vaddr); 157 else if (clazz == ELFCLASS64) 158 return elf64_find_section(map, type, offset, size, vaddr); 159 160 ERROR("unknown elf format %d\n", clazz); 161 162 return -1; 163 } 164 165 static int elf32_scan_dynamic(const char *map, unsigned long dyn_offset, unsigned long dyn_size, long load_offset) 166 { 167 Elf32_Dyn *dynamic = (Elf32_Dyn *) (map + dyn_offset); 168 const char *strtab = NULL; 169 170 while ((void *) dynamic < (void *) (map + dyn_offset + dyn_size)) { 171 Elf32_Dyn *curr = dynamic; 172 173 dynamic++; 174 if (curr->d_tag != DT_STRTAB) 175 continue; 176 177 strtab = map + (curr->d_un.d_ptr - load_offset); 178 break; 179 } 180 181 if (!strtab) 182 return -1; 183 184 dynamic = (Elf32_Dyn *) (map + dyn_offset); 185 while ((void *) dynamic < (void *) (map + dyn_offset + dyn_size)) { 186 Elf32_Dyn *curr = dynamic; 187 188 dynamic++; 189 if (curr->d_tag != DT_NEEDED) 190 continue; 191 192 if (add_path_and_deps(&strtab[curr->d_un.d_val], 1, -1, 1)) 193 return -1; 194 } 195 196 return 0; 197 } 198 199 static int elf64_scan_dynamic(const char *map, unsigned long dyn_offset, unsigned long dyn_size, long load_offset) 200 { 201 Elf64_Dyn *dynamic = (Elf64_Dyn *) (map + dyn_offset); 202 const char *strtab = NULL; 203 204 while ((void *) dynamic < (void *) (map + dyn_offset + dyn_size)) { 205 Elf64_Dyn *curr = dynamic; 206 207 dynamic++; 208 if (curr->d_tag != DT_STRTAB) 209 continue; 210 211 strtab = map + (curr->d_un.d_ptr - load_offset); 212 break; 213 } 214 215 if (!strtab) 216 return -1; 217 218 dynamic = (Elf64_Dyn *) (map + dyn_offset); 219 while ((void *) dynamic < (void *) (map + dyn_offset + dyn_size)) { 220 Elf64_Dyn *curr = dynamic; 221 222 dynamic++; 223 if (curr->d_tag != DT_NEEDED) 224 continue; 225 226 if (add_path_and_deps(&strtab[curr->d_un.d_val], 1, -1, 1)) 227 return -1; 228 } 229 230 return 0; 231 } 232 233 int elf_load_deps(const char *path, const char *map) 234 { 235 unsigned long dyn_offset, dyn_size; 236 unsigned long load_offset, load_vaddr; 237 unsigned long interp_offset; 238 239 if (elf_find_section(map, PT_INTERP, &interp_offset, NULL, NULL) == 0) { 240 add_path_and_deps(map+interp_offset, 1, -1, 0); 241 } 242 243 if (elf_find_section(map, PT_LOAD, &load_offset, NULL, &load_vaddr)) { 244 DEBUG("failed to load the .load section from %s\n", path); 245 return 0; 246 } 247 248 if (elf_find_section(map, PT_DYNAMIC, &dyn_offset, &dyn_size, NULL)) { 249 DEBUG("failed to load the .dynamic section from %s\n", path); 250 return 0; 251 } 252 253 int clazz = map[EI_CLASS]; 254 255 if (clazz == ELFCLASS32) 256 return elf32_scan_dynamic(map, dyn_offset, dyn_size, load_vaddr - load_offset); 257 else if (clazz == ELFCLASS64) 258 return elf64_scan_dynamic(map, dyn_offset, dyn_size, load_vaddr - load_offset); 259 260 ERROR("unknown elf format %d\n", clazz); 261 return -1; 262 } 263 264 static void load_ldso_conf(const char *conf) 265 { 266 FILE* fp = fopen(conf, "r"); 267 char line[PATH_MAX]; 268 269 if (!fp) { 270 DEBUG("failed to open %s\n", conf); 271 return; 272 } 273 274 while (!feof(fp)) { 275 int len; 276 277 if (!fgets(line, sizeof(line), fp)) 278 break; 279 len = strlen(line); 280 if (len < 2) 281 continue; 282 if (*line == '#') 283 continue; 284 if (line[len - 1] == '\n') 285 line[len - 1] = '\0'; 286 if (!strncmp(line, "include ", 8)) { 287 char *sep = strstr(line, " "); 288 glob_t gl; 289 int i; 290 291 if (!sep) 292 continue;; 293 while (*sep == ' ') 294 sep++; 295 if (glob(sep, GLOB_NOESCAPE | GLOB_MARK, NULL, &gl)) { 296 ERROR("glob failed on %s\n", sep); 297 continue; 298 } 299 for (i = 0; i < gl.gl_pathc; i++) 300 load_ldso_conf(gl.gl_pathv[i]); 301 globfree(&gl); 302 } else { 303 alloc_library_path(line); 304 } 305 } 306 307 fclose(fp); 308 } 309 310 void init_library_search(void) 311 { 312 avl_init(&libraries, avl_strcmp, false, NULL); 313 alloc_library_path("/lib"); 314 alloc_library_path("/lib64"); 315 alloc_library_path("/usr/lib"); 316 load_ldso_conf("/etc/ld.so.conf"); 317 } 318 319 void free_library_search(void) 320 { 321 struct library_path *p, *ptmp; 322 struct library *l, *tmp; 323 324 list_for_each_entry_safe(p, ptmp, &library_paths, list) 325 free(p); 326 327 avl_remove_all_elements(&libraries, l, avl, tmp) 328 free(l); 329 } 330
This page was automatically generated by LXR 0.3.1. • OpenWrt