gpt4 book ai didi

c++ - 考虑 makecontext() 什么是 uc_stack.ss_size 好?

转载 作者:行者123 更新时间:2023-11-30 04:41:14 29 4
gpt4 key购买 nike

在调用makecontext之前,为什么我们需要设置堆栈大小ss_size

我刚刚有一个针对 makecontext/swapcontext 代码段的单元测试用例,它因 SIGSEGV 而失败。发生的事情是堆栈大小太小,不相关的内存(碰巧是一些独特的指针)被损坏并报告了段错误。所以段错误是在这些不相关的指针上,我本可以有例如一些字符串,然后内存损坏将不会被注意到。

我原以为 SIGSEGV 会在堆栈大小 ss_size 不足时立即引发,但是考虑到上述内存损坏,我得出结论,不可能从此处的 SIGSEGV 恢复。这让我回到了这个问题,为什么我们需要首先设置堆栈大小,当它没有被用来发出溢出信号时?它有什么用?


编辑:

嗯,这都是关于 makecontext(3) 的.这些函数仍在用于绿色线程、协程等。考虑到这些任务(在我看来)也不在 c++ 中,只是没有真正的替代品。

ss_sizesigaltstack(2) 中定义在 getcontext(3) 中定义的 ucontext_t 中需要 uc_stack .

关注 minimal verifiable example如上所述,通过“绘制”内存显示内存损坏。

#include <iostream>
#include <ucontext.h>
#include <memory>
#include <cstring>
#include <stdio.h>
#include <unistd.h>

ucontext_t caller, callee;
void cb(void){
//paint stack with 2
char tmp[7000];
std::memset(tmp,2,7000);
//note stack size specified 6k bytes in size
//this should not be allowed.
//furthermore there is not even some signal raised here
//i expected raised SIGSEGV when this call stack exceeds ss_size
//it makes ss_size useless no?
}
int main(){
//
std::memset(&caller,0,sizeof(caller));
std::memset(&callee,0,sizeof(callee));

//create stack and paint 0
std::unique_ptr<std::byte[]> stack(new std::byte[10000]());
std::memset(stack.get(),0,10000);//paint stack 0

//make context
//note stack specified to [2000,8000)
//that means [0,2000) and [8000,10000) should not be touched
if(getcontext(&callee) == -1) {std::cout << errno << ":" << std::strerror(errno) << std::endl; return 1;}
callee.uc_link = &caller;
callee.uc_stack.ss_sp = stack.get()+2000;
callee.uc_stack.ss_size = 6000; //what is this line good for, what is it guarding?
makecontext(&callee,cb,0);

//swap to callee
if(swapcontext(&caller,&callee) == -1) {std::cout << errno << ":" << std::strerror(errno) << std::endl; return 1;}

//print color - should be 0
//if 2 then memory corrupted by callee
std::cout << int(stack[996]) << std::endl;
std::cout << int(stack[997]) << std::endl;
std::cout << int(stack[998]) << std::endl;
std::cout << int(stack[999]) << std::endl;
return 0;
}

再一次,我不明白的是为什么我们需要设置堆栈大小 ss_size,因为它看起来没有被用来防止内存损坏或其他任何事情。看起来它只是在那里,但没有任何用处。但是我不敢相信它没有用。那么它“守卫”/有什么用呢?

好吧,我不想给这个问题带来更多的困惑。目标是通过安装 SIGSEGV 信号处理程序来恢复,从而摆脱固定大小的函数调用堆栈,但由于内存损坏,这看起来像是不可能完成的任务;或者有一个可增长的堆栈,例如使用 mmap(2)带有 MAP_GROWSDOWN 标志,但这看起来是 broken因此不是一个选择。

最佳答案

callee.uc_stack.ss_size = 6000; // what is this line good for, what is it guarding?

此行集是堆栈大小(如您在 man sigalstack 中所读)。来自阅读makecontext from glibc ss_size 用于确定堆栈结束,其中 glibc setups the stack的新语境。因为某些机器上的堆栈“向数字较低的地址增长”(就像它在 x86 architecturewiki x86 上所做的那样),makecontext 需要/想要将它的数据放在堆栈的末尾。所以它需要确定堆栈的末尾,这就是 ss_size 的用途。

ss_size 设置为任何值并不意味着溢出堆栈大小将向您的进程发出操作系统信号,通知您的进程试图访问受限内存区域. *context 的实现不是(也不应该)设计为将地址 ss_sp + ss_size (+ 1) 作为内核保护内存,因此写入该地址将触发段错误。这仍然是所有正常变量。与写入未知内存位置(例如溢出数组)一样,无效地址可能恰好在您的进程地址空间内,因此根据内核,进程将在其地址空间内写入一切都很好。正如您在此处所做的那样 - 您的 cb 函数写入 new std::byte[10000] 内存,从内核的角度来看,这没有任何问题。

您很可能可以分配 new std::byte[6000] 并在 valgrind 或 gdb 或其他工具下运行您的进程以检查恶意写入。

关于c++ - 考虑 makecontext() 什么是 uc_stack.ss_size 好?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59167321/

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