Копирование части стека и использование mmap для сопоставления с текущим процессом. - PullRequest
2 голосов
/ 13 декабря 2010

Я хочу, чтобы моя программа выполняла следующие действия:

  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 ]

4 голосов
/ 13 декабря 2010

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

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

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

0 голосов
/ 13 декабря 2010

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

...