标签:初始化 00 buffer 内存 Linux 进程 清零
貌似三年没写随笔了,就记录一下最近在搞的事情吧。
我们在写程序的时候,常常会忽略一件事情,那就是即时抹去敏感数据,例如用户口令和密钥,想象一下,在你的程序结束后,密钥被留在了空闲内存区,这时候如果有别的进程申请到它,或者有攻击者读到了内存数据,那就万般皆空了。
事实上,系统开发者们也考虑过这一点,并做了一定程度的防护——在Windows下,系统会在进程结束后自动清零被归还的内存,但是Linux系统不会,可能是出于性能考虑,Linux采用一种Lazy的思想来清零数据。当进程申请一块内存时,Linux只是分配一个虚拟的零页给它,这个时候程序再怎么读也只能从这块buffer中读到0,只有当写入动作发生(例如赋值给buffer中的某一字节)时,系统才会分配一块真正的物理内存(感兴趣的同志可以写个demo试试,只是持续申请内存而不赋值,再看看资源管理器,分给这个demo的内存应该是没有增加的),再将之前的虚拟内存映射并且覆盖写到它上面,Linux的页大小为4KB,此时会进行一次4KB大小的内存写入,举个例子:
1 int main() 2 { 3 unsigned char * buffer = malloc(1024); 4 5 for (int i=0; i<sizeof buffer; i++) 6 printf("%02X ", buffer[i]); 7 8 buffer[3] = 0xff; 9 10 for (int i=0; i<sizeof buffer; i++) 11 printf("%02X ", buffer[i]); 12 free(buffer); 13 return 0; 14 }
假设上面程序在Linux下运行,虽然第3行申请到的buffer没有初始化,但由于 copy-on-write 原则,第5、6行读到的值必然都是0x0,而且此时并没有实际的物理内存被分配给进程,只有第8行执行完毕时,系统才会分配一个page给当前进程,并且这个page的内容会被覆盖写为 00 00 00 ff 00 00 00......
这种机制可以防止一个进程读到其他进程释放掉的内存中的敏感数据,但是,所谓“防君子不防小人”,它能有效防止“合法”读取内存数据,但根本防不了 DMA、cold-boot这类攻击行为。所以,对敏感数据,还是要及时擦除才对。
然而,内存的清零并不是调用一下memset那么简单,如果在上述程序的第12行 free之前加上一句 memset(buffer, 0, sizeof buffer),那只要编译器开了优化,它就会被当作死代码清除掉的——Dead Store Elimination 在GCC -O1时就会被开启,而GCC默认的优化选项是-O2。
关于内存的清零,有一篇 USENIX Security 2017的文章讲的比较全面,这里贴出链接 https://www.usenix.org/system/files/conference/usenixsecurity17/sec17-yang.pdf ,感兴趣的同志可以看看,有时间我再详细说一下这个问题。
标签:初始化,00,buffer,内存,Linux,进程,清零 来源: https://www.cnblogs.com/weir007/p/11544119.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。