LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   memcpy or mmap or other problems (https://www.linuxquestions.org/questions/programming-9/memcpy-or-mmap-or-other-problems-396736/)

snowing 12-26-2005 09:56 PM

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);
}

}

paulsm4 12-26-2005 11:26 PM

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?

snowing 12-26-2005 11:38 PM

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.

snowing 12-26-2005 11:49 PM

Well, I see now. But... how to delete the other posted thread?


All times are GMT -5. The time now is 08:13 PM.