LinuxQuestions.org
Help answer threads with 0 replies.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 12-26-2005, 09:56 PM   #1
snowing
LQ Newbie
 
Registered: Jul 2005
Posts: 26

Rep: Reputation: 15
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? 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);
}

}
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
how can i speed up memcpy? Thinking Programming 9 10-14-2005 07:53 AM
gdb and mmap dcfnef Programming 8 09-30-2005 10:25 AM
memcpy problems alaios Programming 4 09-17-2005 07:26 AM
Need help: Seg fault, Memcpy, and dynamically allocated arrays benobi Programming 3 06-09-2005 10:58 PM
using mmap AngryLlama Programming 1 02-09-2005 08:53 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 10:00 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration