3

我的问题是从安全的角度来看的。我正在清理一些代码,我发现当前代码存在不受控制的格式字符串漏洞;它将一个字符串传递给类似的printf()东西:

void print_it(char * str)
{
    printf(str);

这显然被认为是不安全的编程,即使 gcc 通常也会给你发出至少某种警告:

警告:格式不是字符串文字,也没有格式参数

现在要“修复”问题,我们可以确保您得到的内容被视为字符串

printf("%s", str);

但我想知道是否有任何......使用长度指定器的额外安全性。就像是:

printf("%.*s", (int)sizeof(str), str);

我想不出有什么理由会更安全,但如果我在这里遗漏了一些明显的东西,我也不会感到惊讶。

4

3 回答 3

5

有点,但不是现代 C 商店安全地保护他们的 printf 语句的程度。当您处理非空终止字符串时使用它,这在与 Fortran 代码交互时非常常见。

严格来说,为了防止读取失控,这将是一项安全收益,也许您将在违反空字符后打印敏感数据。

printf("%.*s", (int)sizeof(str), str);

更糟;您刚刚说“忽略空字符并打印出全部内容”。或者更确切地说,除非您一直处理空格填充的字符串直到它们的内存结束,否则情况会更糟,如果字符串来自 Fortran,情况可能就是这种情况。

然而,非常重要:

printf("%s", str);

printf(str)是一个重大的安全漏洞。阅读有关使用说明符的printf 攻击%n,该说明符写入.

于 2013-03-07T19:02:38.953 回答
1

有一些额外的安全性

printf("%.*s", (int)sizeof(str), str);

因为它会打印最多字节——通常是四个或八个字节——所以如果指向一个不是 0 终止的数组,sizeof(char*)它就不会去读取大部分内存。strchar

但更典型的是,它会在没有充分理由的情况下缩短输出。

如果你的意思是

printf("%.*s", (int)strlen(str), str);

这是完全没有意义的,因为在需要精度的情况下printfstrlen调用将执行相同的无效内存访问。

于 2013-03-07T19:36:25.367 回答
0

当数组传递给函数时,这个想法将不起作用,因为数组衰减为指针或任何 malloc 的指针。因为sizeof(var)要给出指针的大小,而不是数组。所以不能在 printf() 中使用来指定长度。

这仅适用于自动(堆栈分配)数组。那么这什么时候有用呢?我可以想到两种情况:

1.当你写入数组超过数组的大小时。

在这种情况下,您已经通过在不属于您的地方进行写入导致了未定义的行为。故事结局。

2.当字符串末尾没有空字节时(但没有越过数组的边界)。

在这种情况下,数组有一些有效的内容,但没有空字节。这里有两种可能性:

2.a. 使用长度说明符将打印数组的全部内容。因此,如果您访问数组中未初始化的字节(即使在其大小范围内),它仍然会导致未定义的行为。否则,您必须跟踪有效内容的长度,以便%s在 printf() 中使用长度说明符来避免 UB。在这种情况下,您已经知道有效内容的长度。因此,您可以简单地自己终止它,而不是告诉 printf()打印有效内容。

2.b。假设您已经用零初始化了整个数组。在这种情况下,数组将是一个有效的字符串,因此不需要长度修饰符。

所以我会说它没有多大用处。

于 2013-03-07T19:35:27.873 回答