簡體   English   中英

C:如何檢查是否已寫入 memory 地址?

[英]C: How can I check if a memory address has been written?

C中有沒有辦法檢查我自己的進程的memory地址是否寫入?
例如:如果我的程序接受放置在緩沖區中的輸入,我是否可以通過檢查緩沖區的下一個地址是否已寫入來檢查輸入是否溢出緩沖區?
我知道我可以檢查緩沖區的下一個地址的內容並驗證它是否已被修改,但是這樣對我正在處理的工作不利......

我正在研究保護緩沖區溢出和格式字符串錯誤的情況

我知道我可以檢查緩沖區的下一個地址的內容並驗證它是否已被修改,但是這樣對我正在處理的工作不利......

不幸的是,這是在沒有平台和實現特定擴展的情況下使用 C 時唯一的可能性。

However, there are C compilers that can produce machine code which will detect many buffer overflows in these kinds of context - for example GCC has switches -fsanitize=undefined and -fsanitize=address which can be used together and which will output diagnostics to the terminal當發生緩沖區溢出時。 它們使程序運行速度慢得多。 或者,您可以使用valgrind運行程序,它也可以調試分配緩沖區溢出的多種情況。

要添加到您的研究中:

If programming on linux platform that supports mprotect call and when dealing with only dynamic allocation, you can overallocate the memory to at least more then 1 page and mprotect the memory after the memory that you return as dynamically allocated.

例如:

#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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM