虽然学习C,我提出了一些错误和一个字符数组是未初始化的打印元件。
如果我展开数组的大小是相当大的,说的尺寸为1万台,然后打印的内容,出来的东西并不总是用户阅读,但似乎包含一些运行时信息。
考虑下面的代码:
#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;
}
只需通过输出滚动,我发现的东西,如:
?? ?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
并且,
苹果INC.1&0 $ U?0?*?H 13 OT CA0? “0ple认证Authority10U?䑩?? ?? GP ^Ÿ?? 6?WLU ????吉隆坡 - ” 0?> 2 P? A ............ F'$kУ???? Z'G'[?73 -4 M?我?R'] _ ??? D5#KY ????? P 25 XPG? ?ˬ,运算δλ0 24 C'= + I(??ε?? ^'=:????????B 12 q GSU / A ???? P 25 LE〜 LKP?A 11 TB
?!?????吨<A 3 ??? 0X Z2ħ??? ES克^ E I V 3E瓦特?? - ????????????Z0 v0U 0U 0 0U + IG ·v -6 K -1。@ ?? GM ^ 0U#0?+?IG·v -6 K -1。@ ?? GM ^ 0?U 0→0→ 6 H 11 CD0?0+ https://www.apple.com/appleca/0?+0????Reliance本证书的任何一方承担接受当时适用的标准使用条款和条件,证书波利?\ 6?Lx的? 팛 ??瓦特&Delta; v?w0O ???? = G7?@ ?,Ա?ؾ?的??? d?yO4آ>?X·K ??} 9 ?? S' 8I 12 O 01 H 18 [d c3w:???!?????,V 10ںSO - 6 U7 ?? 2B ??? q〜R 10 B $ * -4 M ^ Cķ 2 P ???????? 7?UU!0?0?0
我相信,有一次我的$PATH
环境变量,甚至打印出来。
未初始化的变量的内容都不能带来安全风险?
更新1
更新2
因此,似乎从回答清楚,这确实是一个安全隐患。 这让我吃惊。
难道就没有办法的程序申报保护,允许操作系统限制比初始化的内存的程序之外的任何访问它的内存内容?
Most C
programs use malloc
to allocate memory. A common misunderstanding is that malloc
zeros out the memory returned. It actually does not.
As a result, due to the fact that memory chunks are "recycled" it is quite possible to get one with information of "value".
An example of this vulnerability was the tar
program on Solaris which emitted contents of /etc/passwd
. The root cause was the fact that the memory allocated to tar
to read a block from disk was not initialized and before getting this memory chunk the tar
utility made a OS system call to read /etc/passwd
. Due to the memory recycling and the fact that tar
did not initialize the chunk fragments of /etc/passwd
were printed to logs. This was solved by replacing malloc
with calloc
.
This is an actual example of security implication if you don't explicitly and properly initialize memory.
So yes, do initialize your memory properly.
Update:
Is there no way for a program to declare its memory content protected
to allow the OS to restrict any access to it other than the program
that initialized that memory?
The answer is yes (see in the end) and no.
I think that you view it the wrong way here. The more appropriate question would be for example, why doesn't malloc
initialize the memory on request or clears the memory on release but instead recycles it?
The answer is that the designers of the API explicitly decided not to initialize (or clear memory) as doing this for large blocks of memory 1)would impact performance and 2)is not always necessary (for example you may not deal, in your application or several parts in your application with data that you actually care if they are exposed). So the designers decided not to do it, as it would inadvertently impact performance, and to drop the ball to the programmer to decide on this.
So carrying this also to the OS, why should it be the OS's responsibility to clear the pages? You expect from your OS to hand you memory in a timely manner but security is up to the programmer.
Having said that there are some mechanism provided that you could use to make sure that sensitive data are not stored in swap using mlock in Linux.
mlock() and mlockall() respectively lock part or all of the calling
process's virtual address space into RAM, preventing that memory
from being paged to the swap area. munlock() and munlockall()
perform the converse operation, respectively unlocking part or all
of the calling process's virtual address space, so that pages in the
specified virtual address range may once more to be swapped out if
required by the kernel memory manager. Memory locking and unlocking
are performed in units of whole pages.
是,至少在系统中的数据可以被发送到外部用户。
已经有全系列的网络服务器(甚至是iPod的),你得到它从其他进程转储内存内容的攻击 - 所以得到OS的类型和版本的细节,在其他应用程序,甚至事情数据如密码表
它很可能在的内存区域执行一些敏感的工作,而不是清除缓冲区。
然后,将来调用可以检索经由到呼叫未清除的工作malloc()
通过unitiaised缓冲器/数组声明)或通过检查堆。 它可以检查它(恶意)或无意地复制它。 如果你做任何事的敏感因此,它是有道理的分档是(前清除内存memset()
或类似的),也许使用前/复制它。
从C标准:
6.7.8初始化
“如果具有自动存储持续时间的对象没有被明确初始化,它的值是不确定的。”
不确定的值被定义为:
either an unspecified value or a trap representation.
陷阱表示被定义为:
某些对象表示不需要表示对象类型的值。 如果一个对象的存储值具有这样的表示,并且是由不具有字符类型的左值表达式读取,该行为是定义理解过程网络连接。 如果这样的表示是通过由不具有字符类型的左值表达式MODI对象的音响ES所有或任何部分的副作用产生,该行为是理解过程音响ned.41)这种表示被称为陷阱表示。
访问这样的价值观会导致不确定的行为,可能会造成安全威胁。
本文对未初始化变量的攻击可以给一些见解上,他们可以被用来利用的系统。
如果你担心安全,最保险的办法就是初始化永诺你要使用的每一个变量。 它甚至可能会帮助你找到一些bug。 有可能是不初始化内存一些很好的理由,但在大多数情况下,初始化的每个变量/内存将是一件好事。