c语言 - 如何清理由 "out" 指针参数创建的已分配结构?



我有一个结构变量,它像下面这样传递:

//function definition
void function1(const Node* aVAR1)
{
Node* value=NULL;
.....
}
int main()
{
Node* aVAR=NULL;
aVAR=x.value;
function1(aVAR);
}

在这里,当我在 gdb 中运行它并单步进入function1()时,我看到变量aVAR创建了一个临时内存地址。

GDB:

21     aVAR=x.value;         
(gdb) p aVAR
$5 = (Node *) 0x654321
(gdb) n
Breakpoint 1, function1(aVAR1=0x7ffffffffebcdf ) at debug/../abc.c:12
12 {
(gdb) p aVAR1
$6 = (const Node *) 0x7ffffffffebcdf 

例如

  1. 最初,aVAR 的地址是0x654321
  2. 稍后一小段时间,直到function1()中的第一个指令未执行,aVAR1保存在某个临时地址中,例如0x7ffffffffebcdf
  3. 在执行Node* value=NULL;这是function1()中的第一个指令后,aVar1的地址再次被0x654321
  4. 但是这个临时(0x7ffffffffebcdf(地址不会被清理:即使在函数退出后,0x7ffffffffebcdf也不会被清除

我希望在函数退出后清除0x7ffffffffebcdf但该地址0x7ffffffffebcdf没有指针,我可以通过该指针访问此内存。 在 GCC 中链接时是否有任何选项可以防止这种情况?

如果我为 aVAR 添加一个 malloc 并在稍后使用 memset 和 free 清除它,问题会得到解决,但从逻辑上讲,当我看到时,我丢失了对 malloc(( 分配的内存块的引用,并且我将无法释放(( 分配的内存(导致内存泄漏(。

在您介绍的内容中,您有两个称为aVAR的变量。第一个是main中的局部变量,第二个是function1的参数。两者都在自动存储(或"临时"存储,如您所说的(中,因此当包含它们的函数退出时将不复存在。不需要做任何特别的事情来释放他们。

只需要释放尖头结构(假设它是malloc的(,并且只需要执行一次,无论您在其生命周期中有多少指向它。

简而言之,您所需要的只是每malloc/calloc一个free.(但请记住,strdup会调用malloc,并且将NULL传递给realloc实际上是一种malloc

我希望在函数退出后清除0x7ffffffffebcdf...

我的想象力有限,但我能想象你想要这个的原因之一是:

  1. 你认为这仍在使用;它不是,它超出了范围,并且无法访问。
  2. 如果它碰巧可以访问,因为您将其地址存储在某处,那么您犯了一个错误,再多的归零也无法治愈。
  3. 您遇到安全问题,并且希望确保清理临时内存。

所以,给定 [3] 有两个选择;在 main 返回之前将代码更改为零;或者将 main(( 更改为 mymain((:

int mymain() {
Node* aVAR=NULL;
aVAR=x.value;
function1(aVAR);
return something;
}
void clearstack() {
int data[1000];
int fd;
if ((fd = open("/dev/zero", O_RDONLY)) != -1) {
read(fd, data, sizeof data);
close(fd);
}
}
int main() {
int r = mymain();
clearstack();
return r;
}

这是有效的,因为堆栈地址将在两个函数调用之间叠加,因此您的 0x7f-febcdf 将位于数据中间[]。 实施定义行为的合唱团现在应该正在热身。 但实际上,你会更好地:

int mymain() {
Node* aVAR=NULL;
aVAR=x.value;
function1(aVAR);
aVAR = 0;
dummyfunction(&aVAR);
return aVAR == 0;
}

请注意,通过向 dummyfunction 提供 aVAR 的地址,您可以预先阻止编译器删除它可能认为无用的内容。 但是,这种行为很难预测,因为它将您的程序源代码绑定到您可以使用的任何编译器的任何版本;不是一个好的前景。

如果volatile的定义有任何严谨性,那么它在这里会很有用,但它没有。

更好的方法是使用malloc((来获取变量,然后你受到一个合约的约束,这是内存 [而局部变量只能寄存 ],你可以在释放它之前清理它。 编译器将处于不可接受的行为的外围,以优化清理。 它仍然可能使数据位于某些寄存器中,这可能会泄漏出去。

综上所述;如果攻击者真的想要发现程序中明文的秘密,您可能无法阻止它们。 他们可以在调试器或虚拟机监控程序下启动程序,并随意检查数据。

在一些现代处理器中有一些概念,CPU可以构建一种可以安全地解开秘密的飞地;但是存在许多缺陷。ARM TrustZone 的安全/正常世界与操作系统的内核/用户模式还是 x86 的 Ring0/1/2/3?有更多信息。

最新更新