1

我有一个结构变量,其传递如下:

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

    function1(aVAR);
   }

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

广发银行:

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;完 which 是 中的第一条指令后function1()aVar1的地址0x654321又是。
  4. 但是这个临时 ( 0x7ffffffffebcdf) 地址没有被清除:即使在函数退出后,0x7ffffffffebcdf也没有被清除

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

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

4

2 回答 2

2

在您介绍的内容中,您有两个名为aVAR. 第一个是 local var in main,第二个是function1's 参数。两者都在自动存储中(或您称之为“临时”存储),因此当包含它们的函数退出时将不复存在。不需要做任何特别的事情来释放它们。

只有指向的结构需要被释放(假设它被malloc'ed),并且只需要完成一次,无论你在它的生命周期中有多少指针。

简而言之,您只需要一个free/ malloccalloc(尽管请记住,这strdup将调用malloc,并且传递NULLrealloc实际上是一个malloc。)

于 2020-01-03T04:23:01.563 回答
1

我希望在函数退出后清除 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 将位于 data[] 的中间。实施定义行为的合唱团现在应该正在热身。但实际上,你会更好:

int mymain() {
    Node* aVAR=NULL;
    aVAR=x.value;

    function1(aVAR);
    aVAR = 0;
    dummyfunction(&aVAR);
    return aVAR == 0;
}

请注意,通过将 aVAR 的地址提供给 dummyfunction,您会扰乱编译器删除它可能认为无用的内容的能力。然而,这种行为很难预测,因为它将您的程序源绑定到您可以使用的任何编译器的任何版本;前景不大。

如果volatile在其定义中具有任何严格性,那么在这里它会很有用,但它没有。

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

这一切都说了;如果攻击者真的想在你的程序中发现明文的秘密,你可能无法阻止他们。他们可以在调试器或管理程序下启动您的程序,并随意检查数据。

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

于 2020-01-03T04:56:05.387 回答