如何清理由 "out" 指针参数创建的已分配结构?
How can I clean up an allocated structure created by an "out" pointer parameter?
我有一个结构变量,传递方式如下:
//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
= (Node *) 0x654321
(gdb) n
Breakpoint 1, function1(aVAR1=0x7ffffffffebcdf ) at debug/../abc.c:12
12 {
(gdb) p aVAR1
= (const Node *) 0x7ffffffffebcdf
例如,
- 一开始,aVAR的地址是
0x654321
- 稍后直到
function1()
中的第一条指令未被执行,aVAR1
被保存在某个临时地址中,例如 0x7ffffffffebcdf
.
- 执行
function1()
中的第一条指令 Node* value=NULL;
后,aVar1
的地址再次变为 0x654321
。
- 但是这个临时(
0x7ffffffffebcdf
)地址没有被清理:即使函数退出后,0x7ffffffffebcdf
也没有被清除
我希望 0x7ffffffffebcdf
在函数退出后被清除,但是 0x7ffffffffebcdf
地址没有我可以访问该内存的指针。在 GCC 中链接时是否有任何选项可以防止这种情况发生?
如果我为 aVAR 添加一个 malloc 并稍后使用 memset 和 free 清除它,问题得到解决但逻辑上当我看到时,我失去了对 malloc() 分配的内存块的引用,我不会能够释放()分配的内存(导致内存泄漏)。
在您介绍的内容中,您有两个名为 aVAR
的变量。第一个是 main
中的局部变量,第二个是 function1
的参数。两者都在自动存储中(或 "temporary" 存储,如您所说),因此当包含它们的函数退出时将不复存在。无需执行任何特殊操作即可释放它们。
只有指向的结构需要被释放(假设它是 malloc
ed),而且只需要释放一次,不管你在它的生命周期中有多少指针指向它。
简而言之,每个malloc
/calloc
只需要一个free
。 (但请记住,strdup
将调用 malloc
,并且将 NULL
传递给 realloc
实际上是一个 malloc
。)
I want 0x7ffffffffebcdf to be cleared after function exits...
我的想象力有限,但我可以想象你想要这个的原因是:
- 你觉得这个还在用;不是,它超出范围,无法访问。
- 如果它恰好可以访问,因为你已经将它的地址存储在某处,那么你就犯了一个错误,无论多少归零都无法解决。
- 您遇到了安全问题,您想要确保清理临时内存。
所以,给定 [3] 有两个选择;在 main returns 之前将代码更改为零;或者将您的 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;
}
请注意,通过将 VAR 的地址提供给 dummyfunction,您预扰了编译器删除它可能认为无用的内容的能力。但是,这种行为很难预测,因为它将您的程序源绑定到您可以使用的任何编译器的任何版本;前景不大。
如果 volatile 的定义有任何形式的严谨性,它在这里会有用,但它没有。
更好一点的方法是使用 malloc() 来获取变量,然后你受合同约束,这是内存 [而局部变量只能是寄存器],你可以在释放它之前擦洗它。编译器优化清理将处于不可接受的行为的外部。它仍然可能将数据留在某些寄存器中,这可能会泄漏。
说了这么多;如果攻击者真的想要揭开您程序中纯文本的秘密,您可能无法阻止他们。他们可以在调试器或管理程序下启动您的程序,并随意检查数据。
在一些现代处理器中有一些概念,其中 cpu 可以构建一种可以安全解包秘密的飞地;但也有很多缺陷。 ARM TrustZone's Secure/Normal world vs. OS's kernel/user mode or x86's Ring0/1/2/3? 有更多信息。
我有一个结构变量,传递方式如下:
//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
= (Node *) 0x654321
(gdb) n
Breakpoint 1, function1(aVAR1=0x7ffffffffebcdf ) at debug/../abc.c:12
12 {
(gdb) p aVAR1
= (const Node *) 0x7ffffffffebcdf
例如,
- 一开始,aVAR的地址是
0x654321
- 稍后直到
function1()
中的第一条指令未被执行,aVAR1
被保存在某个临时地址中,例如0x7ffffffffebcdf
. - 执行
function1()
中的第一条指令Node* value=NULL;
后,aVar1
的地址再次变为0x654321
。 - 但是这个临时(
0x7ffffffffebcdf
)地址没有被清理:即使函数退出后,0x7ffffffffebcdf
也没有被清除
我希望 0x7ffffffffebcdf
在函数退出后被清除,但是 0x7ffffffffebcdf
地址没有我可以访问该内存的指针。在 GCC 中链接时是否有任何选项可以防止这种情况发生?
如果我为 aVAR 添加一个 malloc 并稍后使用 memset 和 free 清除它,问题得到解决但逻辑上当我看到时,我失去了对 malloc() 分配的内存块的引用,我不会能够释放()分配的内存(导致内存泄漏)。
在您介绍的内容中,您有两个名为 aVAR
的变量。第一个是 main
中的局部变量,第二个是 function1
的参数。两者都在自动存储中(或 "temporary" 存储,如您所说),因此当包含它们的函数退出时将不复存在。无需执行任何特殊操作即可释放它们。
只有指向的结构需要被释放(假设它是 malloc
ed),而且只需要释放一次,不管你在它的生命周期中有多少指针指向它。
简而言之,每个malloc
/calloc
只需要一个free
。 (但请记住,strdup
将调用 malloc
,并且将 NULL
传递给 realloc
实际上是一个 malloc
。)
I want 0x7ffffffffebcdf to be cleared after function exits...
我的想象力有限,但我可以想象你想要这个的原因是:
- 你觉得这个还在用;不是,它超出范围,无法访问。
- 如果它恰好可以访问,因为你已经将它的地址存储在某处,那么你就犯了一个错误,无论多少归零都无法解决。
- 您遇到了安全问题,您想要确保清理临时内存。
所以,给定 [3] 有两个选择;在 main returns 之前将代码更改为零;或者将您的 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;
}
请注意,通过将 VAR 的地址提供给 dummyfunction,您预扰了编译器删除它可能认为无用的内容的能力。但是,这种行为很难预测,因为它将您的程序源绑定到您可以使用的任何编译器的任何版本;前景不大。
如果 volatile 的定义有任何形式的严谨性,它在这里会有用,但它没有。
更好一点的方法是使用 malloc() 来获取变量,然后你受合同约束,这是内存 [而局部变量只能是寄存器],你可以在释放它之前擦洗它。编译器优化清理将处于不可接受的行为的外部。它仍然可能将数据留在某些寄存器中,这可能会泄漏。
说了这么多;如果攻击者真的想要揭开您程序中纯文本的秘密,您可能无法阻止他们。他们可以在调试器或管理程序下启动您的程序,并随意检查数据。
在一些现代处理器中有一些概念,其中 cpu 可以构建一种可以安全解包秘密的飞地;但也有很多缺陷。 ARM TrustZone's Secure/Normal world vs. OS's kernel/user mode or x86's Ring0/1/2/3? 有更多信息。