在学习C的过程中,我犯了一些错误并打印出未初始化的字符数组元素.
如果我将数组的大小扩展为相当大,比如说大小为100万个元素然后打印内容,那么出来的并不总是用户不可读,但似乎包含一些运行时信息.
请考虑以下代码:
#include <stdio.h>
main() {
char s[1000000];
int c, i;
printf("Enter input string:\n");
for (i = 0; ( c = getchar()) != '\n'; i++) {
s[i] = c;
}
printf("Contents of input string:\n");
for (i = 0; i < 999999; i++) {
putchar(s[i]);
}
printf("\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
只需滚动输出,我会发现如下内容:
?? ?L' ?????? _ dyldVersionNumber_dyldVersionString_dyld_all_image_infos_dyld_fatal_error_dyld_shared_cache_ranges_error_string__mh_dylinker_header_stub_binding_helper_dyld_func_lookup_offset_to_dyld_all_image_infos__dyld_start__ZN13dyldbootstrapL30randomizeExecutableLoadAddressEPK12macho_headerPPKcPm__ZN13dyldbootstrap5startEPK12macho_headeriPPKcl__ZN4dyldL17setNewProgramVarsERK11ProgramVars__ZN4dyld17getExecutablePathEv__ZN4dyld22mainExecutablePreboundEv__ZN4dyld14mainExecutableEv__ZN4dyld21findImageByMachHeaderEPK11mach_header__ZN4dyld26findImageContainingAddressEPKv
并且,
Apple Inc.1&0 $ U?0?*?H ?? CA0?"0ple Certification Authority10U?GP ?? GP ?? ^ y? - ?6?WLU ???? Kl ??"0?>?P? A ??????????????????????????????????????????????????????????????????????????????????? ?ˬ,运算δλ0 24 C'= + I(??ε?? ^'=:????????B 12 q GSU/A ???? P 25 LE〜 LkP?A ?? tb
?!t?<?A?3 ??? 0X?Z2?h?es?g?e?I?v?3e?w ?? - ?? z0?v0U?0U ?0?0U +?iG?v ?? k?.@ ?? GM ^ 0U#0?+?iG?v ?? k?.@ ?? GM ^ 0?U 0?0 ??H ?? cd0? ?0+ https: //www.apple.com/appleca/0?+0???? 对任何一方对此证书的认可都假定接受当时适用的标准使用条款和条件,证书政策?\ 6?Lx ? 팛 ??瓦特Δ v?w0O ???? = G7?@ ?,Ա?ؾ?的??? d?yO4آ>?X·K ??} 9 ?? S'8I 10 O 01? H 18 [d c3w:??!??????,V 10ںSO - 6 U7 ?? 2B ??? q〜R 10 B $*-4 M ^ C K P&???? ???? 7?UU!0?0?0
我相信有一次我的$PATH环境变量甚至打印出来了.
未初始化变量的内容是否会带来安全风险?
更新1

更新2
因此从答案中可以清楚地看出,这确实是一种安全风险.这让我感到惊讶.
除了初始化该内存的程序之外,程序是否无法声明其内存内容受到保护以允许操作系统限制对它的任何访问?
Cra*_*lus 10
大多数C程序用于malloc分配内存.一个常见的误解是malloc归零内存返回.它实际上没有.
结果,由于存储器块被"回收"的事实,很可能得到具有"值"信息的存储器块.
此漏洞的一个示例是tarSolaris上发布内容的程序/etc/passwd.根本原因是分配给tar从磁盘读取块的内存未初始化,并且在获取此内存块之前,该tar实用程序调用了OS系统调用/etc/passwd.由于内存回收和tar没有初始化大块碎片的事实/etc/passwd被打印到日志.这是通过替代解决malloc用calloc.
如果您没有明确且正确地初始化内存,这是安全隐含的实际示例.
所以是的,请正确初始化你的记忆.
更新:
除了初始化该内存的程序之外,程序是否无法声明其内存内容受到保护以允许操作系统限制对它的任何访问?
答案是肯定的(见最后),没有.
我认为你在这里看错了.更合适的问题是,例如,为什么不malloc根据请求初始化内存或清除释放时的内存,而是回收它?
答案是API的设计者明确决定不初始化(或清除内存),因为对大型内存块1执行此操作会影响性能,2)并不总是必要的(例如,您可能无法在应用程序中处理)或者您的应用程序中的几个部分,如果它们被暴露,您实际关注的数据).因此设计师决定不这样做,因为它会无意中影响性能,并将球传给程序员来决定这一点.
因此,对于操作系统而言,为什么操作系统有责任清除页面?您期望从您的操作系统及时交出内存,但安全性取决于程序员.
已经说过,你可以使用一些机制来确保敏感数据不会在Linux中使用mlock存储在交换中.
mlock()和mlockall()分别将部分或全部调用进程的虚拟地址空间锁定到RAM中,防止将内存分页到交换区域.munlock()和munlockall()执行相反操作,分别解锁部分或全部调用进程的虚拟地址空间,以便在内核内存管理器需要时,可以再次交换指定虚拟地址范围内的页面.内存锁定和解锁以整页为单位执行.
是的,至少在可以将数据传输给外部用户的系统上.
在网络服务器(甚至iPod)上有一系列的攻击,你可以从其他进程转储内存的内容 - 所以获得操作系统的类型和版本,其他应用程序中的数据甚至是东西的详细信息像密码表