• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/procd/jail/elf.c

  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