memcpy or mmap or other problems
I want to implement the partial function of grip's userland exec on linux(x86_64). To implement this, I think I can follow the following step:
1. open /lib/ld.so 2. check ld.so's ELF header. 3. do mmap to read ld.so's text 4. read ld.so's text and data to the space got by mmap 5. get ld.so's entry from e_entry 6. setup the stack(to be realized) 7. jmp mmap address But I now encountered the problem in step4:"read ld.so's text to the space got by mmap", I find that I can memcpy the first time successfully, but will failed on the following tries, It will report" memcpy: illegal seek error", could you please tell me why? Thank you very much. And the following is my codes: #include <elf.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/mman.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/stat.h> #include <errno.h> #define is_loaded(p) ((p)->p_type == PT_LOAD ? 1 : 0) #define is_txt_segt(p) ((is_loaded(p)) && (p)->p_flags == (PF_X|PF_R)) #define is_data_segt(p) ((is_loaded(p)) && (p)->p_flags == (PF_W|PF_R)) #define FLAGS (MAP_PRIVATE|MAP_ANONYMOUS) #define ALIGN(k, v) (((k)+((v)-1))&(~((v)-1))) #define jmp_addr(addr) asm("\tjmp *%0\n" :: "r" (addr)) void * global_ptr = NULL; void * global_base = NULL; static Elf64_Ehdr * load_elf_buf(void *elf_buf) { Elf64_Ehdr *e = (Elf64_Ehdr *) elf_buf; Elf64_Phdr *ptab = (Elf64_Phdr *) ((char *)elf_buf + e->e_phoff); Elf64_Phdr *p; size_t tot_len = 0; void * ptr, * base = NULL; int i, flags; /* we could use e->e_type, but this way reduces our code requirement */ for (i = 0, p = ptab; i < e->e_phnum; i++, p++) { if (!is_loaded(p)) continue; if (is_txt_segt(p)) { base = (void *)p->p_vaddr; global_base = (void *)base; printf("%d: the address %ld\n", i, (void *)base); } tot_len += ALIGN(p->p_memsz, p->p_align); } flags = base ? (FLAGS|MAP_FIXED) : FLAGS; if ((ptr = mmap(base, tot_len, PROT_NONE, flags, -1, 0)) == MAP_FAILED) return NULL; global_ptr = (void *)ptr; for (i = 0, p = ptab; i < e->e_phnum; i++, p++) { void * load_addr; size_t len; if (!is_loaded(p)) continue; flags = 0; /* to reduce the code size we could rely on the fact that in * implementation, the PF_ flags are the same as PROT_ */ if (p->p_flags & PF_X) flags |= PROT_EXEC; if (p->p_flags & PF_W) flags |= PROT_WRITE; if (p->p_flags & PF_R) flags |= PROT_READ; /* a very ugly way of figuring out what the base load address * of this segment is. */ load_addr = ptr + (((void *)p->p_vaddr-base)&~(p->p_align-1)); len = ALIGN(p->p_memsz, p->p_align); if (mprotect(load_addr, len, PROT_WRITE)) { munmap(p, tot_len); perror("mprotect(PROT_WRITE): "); return (NULL); } /* We need the exact load address, not the rounded down * version. Otherwis we copy to a garbage location.. */ memcpy((void *)(ptr + ((void *)p->p_vaddr - base)), (void *)elf_buf + p->p_offset, p->p_filesz); perror("memcpy: "); printf("%d: the address %ld\n", i, (void *)p->p_vaddr); if (mprotect(load_addr, len, flags)) { munmap(p, tot_len); perror("mprotect(flags): "); return NULL; } } e = (Elf64_Ehdr *) ptr; return (e); } int main() { int fd = -1; char origld[256] = "/lib64/ld-linux-x86-64.so.2"; Elf64_Ehdr *ehdr = NULL; Elf64_Phdr *phdr = NULL; Elf64_Ehdr *e = NULL; void (*entry)(); struct stat stat; //system("/lib64/ld-linux-x86-64.so.2 ./hello"); fd = open(origld, O_RDONLY); if (fd == -1) { perror("fd open: "); goto err; } if (fstat(fd, &stat) == -1) { perror("fstat"); goto err; } ehdr = mmap(0, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (ehdr == MAP_FAILED) { perror("mmap ehdr"); goto err; } /* Check ELF magic-ident */ if (ehdr->e_ident[EI_MAG0] != 0x7f || ehdr->e_ident[EI_MAG1] != 'E' || ehdr->e_ident[EI_MAG2] != 'L' || ehdr->e_ident[EI_MAG3] != 'F' ) { fprintf(stderr, "File type not supported\n"); goto err; } /* load the dynamic linker */ if ((e = load_elf_buf(ehdr)) == NULL) { fprintf(stderr, "Can not load elf \n"); goto err; } //entry = (void(*)())(ehdr->e_entry + (unsigned long long)(global_ptr - global_base)); entry = (void(*)())ehdr->e_entry; /* TODO : setup the stack */ /* transfer control to the new image */ jmp_addr(entry); err: if (ehdr) { munmap(ehdr, stat.st_size); } if (fd != -1) { close(fd); } } |
I presume it was an accident that you double-posted (I've done that myself).
But why are you trying to reproduce what the operating system's dynamic linker, dl, already does for you? |
excuse me, but I don't know what does the "double-posted" mean? could you please explain the problem in details? Thank you. I am trying to reproduce what the operating system's dynamic linker to do some work to load the program and glibc ld using large pages.
|
Well, I see now. But... how to delete the other posted thread?
|
All times are GMT -5. The time now is 08:13 PM. |