我刚接触c,正在读一本有关软件漏洞的书,偶然发现了这个缓冲区溢出示例,它提到这可能导致缓冲区溢出。我正在尝试确定情况如何。
int handle_query_string(char *query_string)
{
struct keyval *qstring_values, *ent;
char buf[1024];
if(!query_string) {
return 0;
}
qstring_values = split_keyvalue_pairs(query_string);
if((ent = find_entry(qstring_values, "mode")) != NULL) {
sprintf(buf, "MODE=%s", ent->value);
putenv(buf);
}
}
我正在密切注意这段代码,因为这似乎是导致缓冲区溢出的地方。if((ent = find_entry(qstring_values, "mode")) != NULL)
{
sprintf(buf, "MODE=%s", ent->value);
putenv(buf);
}
最佳答案
这里非常重要的一点是,您将指向本地变量的指针传递给putenv
。当handle_query_string
返回时,该缓冲区将不再存在。之后,它将包含垃圾变量。请注意,putenv
确实要求传递给它的字符串在程序的其余部分保持不变。从putenv(重点是我的)的文档中:
可以通过使用动态分配进行更正。 char *buf = malloc(1024)
代替char buf[1024]
另一件事是sprintf(buf, "MODE=%s", ent->value);
可能溢出。如果字符串ent->value
太长,则会发生这种情况。一种解决方案是改用snprintf
。
snprintf(buf, sizeof buf, "MODE=%s", ent->value);
这样可以防止溢出,但是仍然可能会引起问题,因为如果ent->value
太大而无法容纳在buf
中,那么出于明显的原因,buf
将不包含完整字符串。这是纠正两个问题的一种方法:
int handle_query_string(char *query_string)
{
struct keyval *qstring_values, *ent;
char *buf = NULL;
if(!query_string)
return 0;
qstring_values = split_keyvalue_pairs(query_string);
if((ent = find_entry(qstring_values, "mode")) != NULL)
{
// Make sure that the buffer is big enough instead of using
// a fixed size. The +5 on size is for "MODE=" and +1 is
// for the string terminator
const char[] format_string = "MODE=%s";
const size_t size = strlen(ent->value) + 5 + 1;
buf = malloc(size);
// Always check malloc for failure or chase nasty bugs
if(!buf) exit(EXIT_FAILURE);
sprintf(buf, format_string, ent->value);
putenv(buf);
}
}
由于我们使用的是malloc
,因此分配将在函数退出后保留。并且出于相同的原因,我们确保缓冲区事先足够大,因此不必使用snprintf
而不是sprintf
。从理论上讲,这会导致内存泄漏,除非您对分配的所有字符串都使用
free
,但是实际上,退出main
之前不进行释放很少会成为问题。也许会很高兴知道。最好知道,即使现在此代码已受到相当的保护,它仍然不是线程安全的。
query_string
的内容以及ent->value
的内容都可以更改。您的代码没有显示它,但是find_entry
很有可能返回指向query_string
中某个地方的指针。这当然也可以解决,但是会变得复杂。关于c++ - 缓冲区溢出示例:为什么此代码很危险?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/62946319/