C: Как я могу проверить, был ли записан адрес памяти? - PullRequest
0 голосов
/ 17 апреля 2020

Есть ли способ в C проверить, записан ли адрес памяти моего собственного процесса?
Например: если моя программа принимает входные данные, помещенные в буфер, могу ли я проверить, имеет ли входные данные переполнил буфер, проверив, был ли записан следующий адрес в буфер?
Я знаю, что могу проверить содержимое следующего адреса в буфере и проверить, был ли он изменен, но таким образом это не хорошо для чего Я работаю над ...

Я изучаю защиту на случай, если имеются ошибки переполнения буфера и форматирования строки

Ответы [ 2 ]

0 голосов
/ 17 апреля 2020

Чтобы добавить к вашему исследованию:

Если программирование на платформе linux, поддерживающей вызов mprotect, и при работе только с динамическим распределением c, вы можете перераспределить память как минимум более чем на 1 page и mprotect память после памяти, которую вы возвращаете как динамически выделенная.

Например:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <stdint.h>
#include <stdalign.h>
#include <sys/mman.h>
#include <stddef.h>
#include <signal.h>

#if PROTECT_ME
void *malloc2(size_t size) {
    const size_t maxalign = _Alignof(max_align_t);
    assert(size < getpagesize() - sizeof(size_t) - maxalign); // roughly, could be TODO

    // allocate memory
    char * const pnt = mmap(NULL, getpagesize() + 1,
        PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    assert(pnt != (void*)-1);
    assert((uintptr_t)pnt % getpagesize() == 0);

    // calculate a pointer right after the returned pointer that has
    // to be aligned
    char * const end = pnt + getpagesize();
    char * const beg = end - size - (size % maxalign);

    // I store size in the memory before the data
    memcpy(beg - sizeof(size), &size, sizeof(size));

    // protect the data behind the pointer
    assert((uintptr_t)end % getpagesize() == 0);
    const int err = mprotect(end, 1, 0);
    assert(err == 0);

    return beg;
}

void free2(void *beg) {
    // extract size for memory preceding the data
    size_t size;
    memcpy(&size, beg - sizeof(size), sizeof(size));

    // calculate mmap returned pointer
    const size_t maxalign = _Alignof(max_align_t);
    char * const end = beg + size + (size % maxalign);
    char * const pnt = end - getpagesize();

    assert((uintptr_t)pnt % getpagesize() == 0);
    int err = munmap(pnt, getpagesize() * 2);
    assert(err == 0);
}

void signal_segv(int a) {
    fprintf(stderr, "The process had written to a bad place\n");
    abort();
}

__attribute__((__constructor__))
void _init_me(void) {
    signal(SIGSEGV, signal_segv);
}

#define malloc malloc2
#define free free2

#endif


int main() {
    int *a = malloc(5 * sizeof(*a));
    for (int i = 0; i < 10; ++i) {
        a[i] = i;  // will write out-of-bounds for a array when i == 5
        fprintf(stderr, "a[%d]=%d\n", i, a[i]);
    }
    free(a);
}

Компиляция с gcc и работа без защиты:

$ gcc 1.c && ./a.out
a[0]=0
a[1]=1
a[2]=2
a[3]=3
a[4]=4
a[5]=5
a[6]=6
a[7]=7
a[8]=8
a[9]=9

Но с включенной защитой на платформе SIGSEGV должен генерироваться при записи "достаточно" (выравнивания) за пределы массива:

$ gcc -DPROTECT_ME=1 1.c && ./a.out
a[0]=0
a[1]=1
a[2]=2
a[3]=3
a[4]=4
a[5]=5
The process had written to a bad place
Aborted (core dumped)
0 голосов
/ 17 апреля 2020

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

К сожалению, это только возможность, которую вы имеете при использовании C без платформы и расширений, определяющих реализацию c.

Однако, есть C компиляторы, которые могут создать машинный код, который обнаружит много переполнений буфера в таких контекстах - например, G CC имеет переключатели -fsanitize=undefined и -fsanitize=address, которые можно использовать вместе и которые будут выводить диагностику на терминал, когда переполнение буфера происходит. Они делают программу намного медленнее для запуска. В качестве альтернативы вы можете использовать valgrind для запуска программы, и она также может отлаживать множество случаев, когда выделенный буфер переполняется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...