00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00039 #include <err.h>
00040 #include <fcntl.h>
00041 #include <gelf.h>
00042 #include <stdint.h>
00043 #include <stdio.h>
00044 #include <stdlib.h>
00045 #include <string.h>
00046 #include <sysexits.h>
00047 #include <sys/stat.h>
00048 #include <sys/types.h>
00049 #include <sys/mman.h>
00050 #include <unistd.h>
00051 #include "module.h"
00052 #include "files.h"
00053 #include "list.h"
00054 #include "debug.h"
00055
00056 static m_result_t persistent_shdr_open(char *module_path, uint64_t module_inode, uintptr_t module_start, module_dsr_t *module_dsr);
00057
00058 struct list_head module_dsr_list;
00059
00067 void
00068 m_module_relocate_symbols(uintptr_t got_start,
00069 uintptr_t got_end,
00070 uintptr_t old_start,
00071 uintptr_t old_end,
00072 uintptr_t new_start,
00073 uintptr_t new_end)
00074 {
00075 uintptr_t entry;
00076 uintptr_t symbol_old_addr;
00077 uintptr_t symbol_new_addr;
00078
00079 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "relocate.got_start = %lx\n", got_start);
00080 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "relocate.got_end = %lx\n", got_end);
00081 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "relocate.old_start = %lx\n", old_start);
00082 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "relocate.old_end = %lx\n", old_end);
00083 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "relocate.new_start = %lx\n", new_start);
00084 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "relocate.new_end = %lx\n", new_end);
00085
00086 mprotect(got_start - (got_start % 4096), got_end - (got_start - (got_start % 4096)), PROT_READ | PROT_WRITE | PROT_EXEC);
00087
00088 for (entry = got_start; entry < got_end; entry+=sizeof(uintptr_t)) {
00089 symbol_old_addr = *((uintptr_t *) entry);
00090
00091 if (symbol_old_addr >= old_start && symbol_old_addr < old_end) {
00092 symbol_new_addr = symbol_old_addr - old_start + new_start;
00093 *((uintptr_t *) entry) = symbol_new_addr;
00094
00095 M_DEBUG_PRINT(M_DEBUG_SEGMENT, "relocate_symbol: %lx ==> %lx\n", symbol_old_addr, symbol_new_addr );
00096 }
00097 }
00098 }
00099
00100
00116 static
00117 m_result_t
00118 persistent_shdr_open(char *module_path,
00119 uint64_t module_inode,
00120 uintptr_t module_start,
00121 module_dsr_t *module_dsr)
00122 {
00123 m_result_t result = M_R_FAILURE;
00124 int fd;
00125 Elf *e;
00126 char *name;
00127 Elf_Scn *scn;
00128 GElf_Shdr shdr;
00129 size_t shstrndx;
00130 GElf_Ehdr ehdr;
00131 int have_persistent = 0;
00132
00133 if (module_dsr == NULL) {
00134 result = M_R_INVALIDARG;
00135 goto out;
00136 }
00137
00138 if (elf_version(EV_CURRENT) == EV_NONE) {
00139 errx(EX_SOFTWARE, "ELF library initialization failed: %s", elf_errmsg(-1));
00140 }
00141
00142 if ((fd = open(module_path, O_RDONLY, 0)) < 0) {
00143 result = M_R_INVALIDFILE;
00144 goto out;
00145 }
00146
00147 if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
00148 errx(EX_SOFTWARE, "elf_begin() failed: %s.", elf_errmsg(-1));
00149 }
00150
00151 if (elf_kind(e) != ELF_K_ELF) {
00152 result = M_R_INVALIDFILE;
00153 goto err_end;
00154 }
00155
00156 gelf_getehdr(e, &ehdr);
00157 shstrndx = ehdr.e_shstrndx;
00158
00159 scn = NULL;
00160 while ((scn = elf_nextscn(e, scn)) != NULL) {
00161 if (gelf_getshdr(scn, &shdr) != &shdr) {
00162 errx(EX_SOFTWARE, "getshdr() failed: %s.", elf_errmsg(-1));
00163 }
00164 if ((name = elf_strptr(e, shstrndx, shdr.sh_name)) == NULL) {
00165 errx(EX_SOFTWARE, "elf_strptr() failed: %s.", elf_errmsg(-1));
00166 }
00167 if (strcmp(name, ".persistent") == 0) {
00168 module_dsr->persistent_scn = scn;
00169 memcpy((void *) &module_dsr->persistent_shdr, &shdr, sizeof(GElf_Shdr));
00170 have_persistent = 1;
00171 break;
00172 }
00173 }
00174
00175 if (have_persistent) {
00176 strcpy(module_dsr->module_path, module_path);
00177 module_dsr->module_start = module_start;
00178 module_dsr->module_inode = module_inode;
00179 module_dsr->fd = fd;
00180 module_dsr->elf = e;
00181
00182
00183 scn = NULL;
00184 while ((scn = elf_nextscn(e, scn)) != NULL) {
00185 if (gelf_getshdr(scn, &shdr) != &shdr) {
00186 errx(EX_SOFTWARE, "getshdr() failed: %s.", elf_errmsg(-1));
00187 }
00188 if ((name = elf_strptr(e, shstrndx, shdr.sh_name)) == NULL) {
00189 errx(EX_SOFTWARE, "elf_strptr() failed: %s.", elf_errmsg(-1));
00190 }
00191 if (strcmp(name, ".got") == 0) {
00192 memcpy((void *) &module_dsr->GOT_shdr, &shdr, sizeof(GElf_Shdr));
00193 result = M_R_SUCCESS;
00194 goto out;
00195 }
00196 }
00197 assert(0 && "PANIC: No GOT section\n");
00198 }
00199 err_end:
00200 (void) elf_end(e);
00201 (void) close(fd);
00202 out:
00203 return result;
00204 }
00205
00206
00207 static
00208 void
00209 persistent_shdr_close(module_dsr_t *module_dsr)
00210 {
00211 (void) elf_end(module_dsr->elf);
00212 (void) close(module_dsr->fd);
00213 }
00214
00215
00223 m_result_t
00224 m_module_create_module_dsr_list(struct list_head *module_dsr_listp)
00225 {
00226 char fname[64];
00227 pid_t pid;
00228 FILE *f;
00229 char buf[128+M_MODULE_PATH_MAX];
00230 char perm[5], dev[6], mapname[M_MODULE_PATH_MAX];
00231 uint64_t start, end, inode, foo;
00232 char prev_mapname[M_MODULE_PATH_MAX];
00233 module_dsr_t *module_dsr = NULL;
00234
00235
00236
00237 pid = getpid();
00238
00239 if (snprintf(fname, sizeof(fname), "/proc/%i/maps", pid) < 0) {
00240 return M_R_FAILURE;
00241 }
00242 if ((f = fopen(fname, "r")) == NULL) {
00243 return M_R_FAILURE;
00244 }
00245 INIT_LIST_HEAD(module_dsr_listp);
00246
00247 while (!feof(f)) {
00248 if(fgets(buf, sizeof(buf), f) == 0)
00249 break;
00250 mapname[0] = '\0';
00251 sscanf(buf, "%lx-%lx %4s %lx %5s %lu %s", &start, &end, perm,
00252 &foo, dev, &inode, mapname);
00253 if (module_dsr == NULL) {
00254 if (!(module_dsr = (module_dsr_t *) malloc(sizeof(module_dsr_t)))) {
00255
00256 return M_R_FAILURE;
00257 }
00258 }
00259 if (strlen(mapname) > 0 && strcmp(prev_mapname, mapname) != 0) {
00260 if (persistent_shdr_open(mapname, inode, start, module_dsr)
00261 == M_R_SUCCESS)
00262 {
00263 list_add(&module_dsr->list, module_dsr_listp);
00264 module_dsr = NULL;
00265 strcpy(prev_mapname, mapname);
00266 }
00267 }
00268 }
00269
00270
00271 if (module_dsr) {
00272 free(module_dsr);
00273 }
00274
00275 return M_R_SUCCESS;
00276 }