gpt4 book ai didi

c++ - 使用旧 GLIBC 版本检测堆栈溢出

转载 作者:太空狗 更新时间:2023-10-29 12:20:16 24 4
gpt4 key购买 nike

我们怀疑我们在多线程程序中遇到堆栈溢出。然而,由于它是一个嵌入式应用程序,我们无法让 valgrind 等为它工作。此外,我们只能使用不支持标志 -fstack-protector-all 的 GCC v4.0.0 和 GLIBC v2.3.2。

在这种情况下,我们如何着手检测我们看到的段错误是否是堆栈溢出的结果?我们已将所有线程的堆栈大小加倍,这解决了问题,但我们想确保这是真正的解决方法。

最佳答案

您可以稍微小心地自己解决这个问题。如果您将程序设置为使用您分配的堆栈,您可以添加一个“保护页”来捕获对超过给定堆栈末尾的第一页的读写。然后,您可以安装一个信号处理程序来捕获信号,并告诉您段错误是否是由该保护页面内的访问引起的。

这是我能做的最小的例子,展示了如何做到这一点:

#include <stdio.h>
#include <ucontext.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <malloc.h>
#include <signal.h>

static char *guard = NULL;
static const int pagesize = getpagesize();

static void handler(int sig, siginfo_t *info, void *ctx) {
if ((char*)info->si_addr >= guard && (char*)info->si_addr - guard <= pagesize) {
write(2, "stack overflow\n", 15);
}
write(2, "sigsegv caught\n", 15);
_exit(-1);
}

static void install_handler() {
// register sigsegv handler:
static struct sigaction act;

act.sa_sigaction = handler;
sigemptyset(&act.sa_mask);
act.sa_flags=SA_SIGINFO|SA_ONSTACK;

// give the signal handler an alternative stack
static char stack[4096];
stack_t ss;
ss.ss_size = sizeof(stack);
ss.ss_sp = stack;
if (sigaltstack(&ss, 0)) {
perror("sigaltstack");
fprintf(stderr,"failed to set sigstack\n");
exit(-1);
}

if (sigaction(SIGSEGV, &act, NULL)) {
perror("sigaction");
fprintf(stderr,"failed to set handler\n");
exit(-1);
}
}

static int overflow() {
return overflow() + 1;
}

static void test()
{
install_handler();
puts("start test");
// real code that might overflow
// test non-overflow segv
//*(char*)0 = 0;
// test overflow
overflow();
puts("finish test");
}

int main()
{
// create a stack and guard page:
const int pagesize = getpagesize();
char *st1=(char*)memalign(pagesize,1+(pagesize*4));
guard = st1+(pagesize*4);
if (mprotect(guard, pagesize, PROT_NONE)) {
perror("mprotect");
fprintf(stderr,"failed to protect guard page: %p \n", guard);
return -1;
}

ucontext_t ctx[2];
getcontext(&ctx[1]);
ctx[1].uc_stack.ss_sp = st1;
ctx[1].uc_stack.ss_size = 4*pagesize;
ctx[1].uc_link = &ctx[0];
makecontext(&ctx[1], test, 0);

swapcontext(&ctx[0], &ctx[1]);
return 0;
}

除了使用您自己的堆栈让您的代码在其中运行外,您还必须提供另一个堆栈以供使用的信号传递,否则信号传递本身将因保护页面而失败。

关于c++ - 使用旧 GLIBC 版本检测堆栈溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11691106/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com