Lud*_*lze 4 c c++ linux memory-management x86-64
在 C 或 C++ 中,在 Linux 上,我想以系统内存页面大小的整页来分配堆内存。
(目的是我想增加有害缓冲区溢出导致分段错误的可能性。)
当我使用 C++ 数组 new ( pointer = new char[size]) 分配内存时,其中大小是 的倍数sysconf(_SC_PAGESIZE),那么分配的内存的(虚拟)地址通常不会是 的倍数sysconf(_SC_PAGESIZE),这表明我已经得到了较大块的子集,已确认事实上,写入指针 [size] 并稍稍超出(强制缓冲区溢出)通常不会导致分段错误。
我的问题是,我能否以某种方式影响内存分配以提供完整的内存页面。
我感兴趣的处理器架构是 x86_64 又名 amd64。操作系统是最新的Ubuntu,或稳定的CentOS Linux(7.3),后者配备内核3.10和gcc-4.8。
我不关心解决方案是 C 还是 C++,因此我要求在这个问题中保留 C 标签。
1) 只要从 切换到pointer = new char[size]就会pointer = aligned_alloc(sysconf(_SC_PAGESIZE), size)导致正确的页面对齐,并且(到目前为止,对于小型测试程序)在超出分配的范围时会一致生成分段错误。正如@JohnBollinger 在他对该问题的第一个评论中指出的那样,仅通过分配方法并不能保证分段错误的生成。这可以通过 2) 来修复:
2) mprotect 函数的 Linux 手册页包含限制对内存页访问的完整示例。该示例还提供了 SIGSEGV 的信号处理程序,我对此不感兴趣,默认操作(中止)对我来说已经足够了。手册页中的示例部分如下。请注意,将 mprotect 应用于与 mmap 无关的内存区域是 POSIX 未涵盖的 Linux 特定扩展。
例子
下面的程序分配四页内存,将其中的第三页设为只读,然后执行一个循环,向上遍历分配的区域修改字节。
运行该程序时我们可能会看到的示例如下:
Run Code Online (Sandbox Code Playgroud)$ ./a.out Start of region: 0x804c000 Got SIGSEGV at address: 0x804e000节目来源
Run Code Online (Sandbox Code Playgroud)#include <unistd.h> #include <signal.h> #include <stdio.h> #include <malloc.h> #include <stdlib.h> #include <errno.h> #include <sys/mman.h> #define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0) static char *buffer; static void handler(int sig, siginfo_t *si, void *unused) { printf("Got SIGSEGV at address: 0x%lx\n", (long) si->si_addr); exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { char *p; int pagesize; struct sigaction sa; sa.sa_flags = SA_SIGINFO; sigemptyset(&sa.sa_mask); sa.sa_sigaction = handler; if (sigaction(SIGSEGV, &sa, NULL) == -1) handle_error("sigaction"); pagesize = sysconf(_SC_PAGE_SIZE); if (pagesize == -1) handle_error("sysconf"); /* Allocate a buffer aligned on a page boundary; initial protection is PROT_READ | PROT_WRITE */ buffer = memalign(pagesize, 4 * pagesize); if (buffer == NULL) handle_error("memalign"); printf("Start of region: 0x%lx\n", (long) buffer); if (mprotect(buffer + pagesize * 2, pagesize, PROT_READ) == -1) handle_error("mprotect"); for (p = buffer ; ; ) *(p++) = 'a'; printf("Loop completed\n"); /* Should never happen */ exit(EXIT_SUCCESS); }
前面引用的归属:
本页是 Linux 手册页项目 4.04 版本的一部分。
该项目的描述、有关报告错误的信息以及此页面的最新版本可以在http://www.kernel.org/doc/man-pages/中找到。