C++ 代码行的内存漏洞是否应为“;printf(“%s”,argv[1])&引用;是否被描述为堆栈溢出?
今天,我在Elance.com上做了一个简短的“C++技能测试”。一个问题是: 以下代码行的安全漏洞是什么:C++ 代码行的内存漏洞是否应为“;printf(“%s”,argv[1])&引用;是否被描述为堆栈溢出?,c++,printf,stack-overflow,language-lawyer,buffer-overflow,C++,Printf,Stack Overflow,Language Lawyer,Buffer Overflow,今天,我在Elance.com上做了一个简短的“C++技能测试”。一个问题是: 以下代码行的安全漏洞是什么: printf(“%s”,argv[1]) 选项1:格式化字符串 选项2:Unix系统上的堆栈溢出argv[1]本身的无效内存访问(大小写argc==0),指向格式正确的字符串(argc>=2)的指针,或NULL(argc==1) printf(“%s”,argv[1])的问题正在使用指针(argv[1]),但未检查其是否有效。以后发生的任何事情都只是次要后果。问题是在使用前未能验证arg
printf(“%s”,argv[1])代码>
选项1:格式化字符串
选项2:Unix系统上的堆栈溢出argv[1]
本身的无效内存访问(大小写argc==0
),指向格式正确的字符串(argc>=2
)的指针,或NULL(argc==1
)
printf(“%s”,argv[1])的问题
正在使用指针(argv[1]
),但未检查其是否有效。以后发生的任何事情都只是次要后果。问题是在使用前未能验证argv[1]
是否符合预期。它可能属于非常普遍的范畴。将其称为缓冲区溢出或堆栈溢出会产生误导。C++标准响应
就语言而言,可能存在以下情况:
argc<2
argc>=2
在第一种情况下,printf(“%s”,argv[1])
只是未定义的行为
在第二种情况下,程序格式良好(从argv[0]
到argv[argc-1]
保证为有效的空终止字符串:
§3.6.1/2[basic.start.main]
在后一种形式中,为了便于说明,第一个函数参数称为argc,第二个函数参数称为argv,其中argc应为从运行程序的环境传递给程序的参数数。如果argc为非零,则应通过argv在argv[0]中提供这些参数[argc-1]作为指向以空结尾的多字节字符串(ntmbs)(17.5.2.1.4.2)的初始字符的指针,argv[0]应是指向ntmbs的初始字符的指针,该字符表示用于调用程序或“”的名称。argc的值应为非负。argv[argc]的值应为0。[注:建议添加任何其他(可选)参数Terargv.-尾注]
(我的重点)
为什么堆栈溢出非常不精确
由于没有其他信息(作为编译器或体系结构),回答“堆栈溢出”是不精确的。C++标准不试图定义“栈”是什么,因此“堆栈溢出”几乎意味着没有什么C++标准。
标准的理由是一个具有保证内存模型的抽象机器
到底发生了什么
在argc<2
的情况下,没有人知道会发生什么。标准既不保证也不指定任何内容。在argc>=2
的情况下,程序定义良好。这里没有潜在的堆栈溢出
该标准保证argc
是非负的,这意味着它可以是0
。如果argc
是正的,argv[0]
通过argv[argc-1]
是指向字符串的指针
如果argc==0
,则argv[1]
不仅仅是一个空指针——它根本不存在。在这种情况下,argv[1]
尝试访问不存在的数组元素。(argv[1]
相当于*(argv+1)
;允许添加指针,但取消引用具有未定义的行为。)请注意,在这种情况下,可以通过argv[0]
访问的程序名不可用
如果argc==1
,则argv[1]==NULL
。计算argv[1]
是完全有效的,但它会生成一个空指针。使用将空指针传递到printf
%s
选项具有未定义的行为。我想您可以将其称为格式字符串问题,但真正的问题是在需要指向字符串的非空指针时使用空指针
如果argc>=2
,则argv[1]
保证指向一个字符串,printf(“%s”,argv[1])
将只打印该字符串的字符,直到但不包括终止的'\0'
(保证存在)
在这种情况下仍然存在潜在的漏洞。引用7.21.6.1第15段:
任何一次转换可产生的字符数应至少为
4095
<15>(N1570是C标准的草案;C++是指标准库的部分的C标准)。
这意味着一个实现可能会限制printf
调用产生的字符数。实际上,可能没有理由施加固定的限制;printf
可以简单地一次打印一个字符,直到它到达字符串的末尾。但原则上,如果strlen(argv[1])>4095
,如果当前的实现施加了这样的限制,那么行为可能是未定义的
不过,这并不是我所说的“堆栈溢出”——特别是因为C++标准不使用“栈”这个词(除了一些简短的引用“堆栈展开”)之外。
通过首先检查,可以避免这些问题中的大多数:
if (argc >= 2) {
printf("%s", argv[1]);
}
或者,如果你感到偏执:
if (argc >= 2 && argv[1] != NULL) {
printf("%s", argv[1]);
}
@self.绝对没有。在Elance测试中,用户只收到了一行代码,与我在本文中提供的完全相同-问题中没有提供任何上下文,只有一个问题,即以下代码行的安全漏洞是什么,提供了四个多选选项。(在“C++技能测试”中,这是引导。)那些“不相关的答案”是什么?它们实际上高度相关吗?argv[1]
可以是任何东西。可能没有任何参数传递给程序,在这种情况下,这指向