2010-12-12 1 views
2

Я хочу, чтобы моя программа, чтобы сделать следующее:Копирование части стека и использовать ММАП для отображения его текущего процесса

  1. Откройте новый файл.
  2. Скопируйте часть (стежка) в стек, которая включает в себя текущий адрес указателя кадра в файл.
  3. Сопоставьте содержимое файла обратно в адресное пространство процесса в том же диапазоне, что и исходная часть стека, чтобы процесс использовал файл для этой части своего стека, а не область памяти. система изначально была выделена для стека.

Ниже приведен мой код. Я получаю ошибку сегментации при вызове mmap, в частности, когда mmap делает системный вызов с помощью vsyscall. (Я работаю с gcc 4.4.3, glibc 2.11.1, под Ubuntu Server (x86-64). Я скомпилировал и запустил обе версии с 64-битной и 32-разрядной конфигурациями с теми же результатами.

#include <stdio.h> 
#include <stdlib.h> 
#include <stdbool.h> 
#include <stdint.h> 
#include <string.h> 
#include <sys/mman.h> 
#include <assert.h> 
#include <unistd.h> 
#include <sys/mman.h> 
#include <sys/types.h> 
#include <sys/wait.h> 

#define PAGE_SIZE 0x1000 
#define FILENAME_LENGTH 0x10 
#if defined ARCH && ARCH == 32 
#define PAGE_SIZE_COMPLEMENT 0xfffff000 
#define UINT uint32_t 
#define INT int32_t 
#define BP "ebp" 
#define SP "esp" 
#define X_FORMAT "%x" 
#else 
#define PAGE_SIZE_COMPLEMENT 0xfffffffffffff000 
#define UINT uint64_t 
#define INT int64_t 
#define BP "rbp" 
#define SP "rsp" 
#define X_FORMAT "%lx" 
#endif 
#define PAGE_ROUND_UP(v) (((v) + PAGE_SIZE - 1) & PAGE_SIZE_COMPLEMENT) 
#define PAGE_ROUND_DOWN(v) ((v) & PAGE_SIZE_COMPLEMENT) 


UINT stack_low, stack_high, stack_length; 

void find_stack_high(void) { 

    UINT bp = 0; 
    UINT raw_stack_high = 0; 

    /* Set the global stack high to the best 
    * approximation. 
    */ 

    asm volatile ("mov %%"BP", %0" : "=m"(bp)); 
    while (bp) { 
     raw_stack_high = bp; 
     bp = *(UINT *)bp; 
    } 
    stack_high = PAGE_ROUND_UP(raw_stack_high); 
} 


int file_create(void) { 

    int fd; 
    char filename[FILENAME_LENGTH]; 

    strcpy(filename, "tmp.XXXXXX"); 
    fd = mkstemp(filename); 
    if (fd == -1) { 
     perror("file_create:mkstemp"); 
     exit(EXIT_FAILURE); 
    } 

    unlink(filename); 
    return fd; 
} 


int main(void) { 


    int fd, bytes_written; 
    UINT bp; 
    off_t offset; 

    printf("In main\n"); 

    fd = file_create(); 
    printf("fd %d\n", fd); 

    find_stack_high(); 

    // Get the current frame pointer. 

    asm volatile ("mov %%"BP", %0" : "=m" (bp)); 

    // Store page boundary below 
    // frame pointer as end of potentially shared stack. 

    stack_low = PAGE_ROUND_DOWN(bp); 
    stack_length = stack_high - stack_low; 

    printf("start "X_FORMAT" end "X_FORMAT" length "X_FORMAT"\n", 
      stack_low, stack_high, stack_length); 

    bytes_written = 
     write(fd, (const void *)stack_low, PAGE_SIZE); 
    if (bytes_written != PAGE_SIZE) { 
     perror("main: write"); 
     fprintf(stderr, "Num bytes: %x\n", bytes_written); 
     exit(EXIT_FAILURE); 
    } 

    offset = 0; 

    if (mmap((void *)stack_low, PAGE_SIZE, PROT_READ | PROT_WRITE, 
     MAP_SHARED | MAP_FIXED | MAP_GROWSDOWN, fd, offset) == 
     MAP_FAILED) { 
     perror("file_copy: mmap"); 
     exit(EXIT_FAILURE); 
    } 

    close(fd); 

    return EXIT_SUCCESS; 
} 

Спасибо!

+2

Он определенно нуждается SYS/mman.h в третий раз. – bmargulies

+0

@bmargulies: +1 за смех –

+0

Извините - не заметили дублирования. –

ответ

0

Пробовал включения выполнить разрешение? в любом случае, этот симптом свидетельствует о том, что вы сумели отобразить более чем в верхней части стека, уничтожая указатель возврата.

4

изменения стека (например, обратный адрес для вызова mmap) после того, как вы его скопировали. Я могу думать о двух возможных способах этого:

  1. Напишите asm, который не нуждается в стеке для выполнения нового сопоставления.
  2. Позвоните в функцию с огромными локальными данными, чтобы рабочий стек находился на другой странице со страниц, которые вы просматриваете. Затем вы можете сопоставить более низкие адреса со вторым вызовом до mmap после возвращения этой функции.

бы вы ни делали, это ужасный хак и, вероятно, плохая идея ..

+0

Да, я думаю, это проблема. Я сделал последнюю из ваших двух стратегий в предыдущем проекте, который работал, но я пытался упростить свой код и забыл причину этого конкретного требования. –

+2

@Amittai Aviram: вы можете использовать 'makecontext()' для копирования стека и 'mmap' в другом временном контексте, который использует другой стек. – caf

+0

Вы также можете использовать обработчик сигналов с чередующимся сигнальным стеком, чтобы избежать проблемы слияния стека под запущенным кодом. –

Смежные вопросы