отображение двух последовательных страниц - PullRequest
3 голосов
/ 27 февраля 2009

Я пишу модульный тест для моей библиотеки манипуляций UTF8, и я хочу, чтобы мой тест вышел из строя, если функция переходит в переполнение буфера. Поэтому мне пришла в голову идея отобразить в памяти две страницы рядом друг с другом, первая с PROT_READ | PROT_WRITE, а второй с PROT_NONE. Таким образом, в случае любого переполнения, segfault гарантируется. Вот пример:


void *addr1, *addr2; /* these are the pages; mmap call left out for simplicity */
char *p = (char *) (addr1 + getpagesize() - 8);

utf8_encode(aUtf8String, p, 8); // this shouldn't segfault

Проблема в том, что когда я отображаю вторую страницу, моя программа не работает. Вот пример программы, которая воспроизводит проблему (GNU / Linux):


#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>

void checkMap(void *p) 
{ 
    if(p == MAP_FAILED) {
        printf("error running mmap: %s\n", strerror(errno));
        exit(1);
    }   
}

int main(void)
{
    void *addr1, *addr2;
    size_t pagesize;

    pagesize = getpagesize();
    checkMap(addr1 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
    checkMap(addr2 = mmap(addr1 + pagesize, pagesize, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0));  /* segfaults */
    munmap(addr1, pagesize);
    munmap(addr2, pagesize);

    return 0;
}

Интересно, что оператор printf () перед первым mmap () приводит к успешной работе программы. Кто-нибудь знает, почему mmap является segfaulting? Если моя цель недостижима с помощью mmap (), есть ли у кого-нибудь еще советы о том, как я могу проверить свой код на переполнение буфера?

Ответы [ 2 ]

3 голосов
/ 27 февраля 2009

Вы можете вызвать mprotect () , чтобы изменить флаги защиты памяти, отображенной на mmap(). Это может быть лучшим решением, чем попытка mmap() двух смежных страниц с разными средствами защиты, так как это, кажется, и вызывает ваши проблемы.

(Linux позволяет вам вызывать mprotect() на любой странице, но POSIX разрешает только те страницы, которые уже были выделены mmap().)

Это один из приемов Электрический забор используется для обнаружения переполнения буфера.

0 голосов
/ 03 марта 2009

Это не полностью связано с вашим вопросом (если только ваша конечная цель не состоит в том, чтобы заставить ваш тест работать), но, ИМХО, полагаться на этот вид обработки ошибок может быть обманчиво (особенно если вы ориентируетесь на несколько платформ, где тест должен был провалиться только из-за того, что ошибка сегмента не была вызвана каким-либо неуказанным поведением).

Возможно, другой подход будет более целесообразным для вас, например, просто выделите больший буфер, чем необходимо, поместите маркер в его конец и проверьте, не был ли он перезаписан?

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

...