我最近偶然发现了一篇文章,声称微软正在memcpy()
其安全编程商店中禁止该功能。我了解该功能固有的漏洞,但有必要完全禁止使用它吗?
我编写的程序应该memcpy()
完全避免,还是只是确保它被安全使用?有哪些替代品可以提供类似但更安全的功能?
Microsoft 提供了 memcpy 和 wmemcpy 的替代方法来验证它们的参数。
memcpy_s 说,“嗯,在我从这个地址读取之前,让我自己验证它不是空指针;在我写入这个地址之前,我将再次执行该测试。我还将比较我的字节数已被要求复制到声称的目的地大小;当且仅当呼叫通过所有这些测试时,我才执行复制。”
memcpy 说“将目标填充到寄存器中,将源填充到寄存器中,将计数填充到寄存器中,执行 MOVSB 或 MOVSW。” (geocities 的例子,这个世界不久:http ://www.geocities.com/siliconvalley/park/3230/x86asm/asml1013.html )
编辑:对于 memcpy 的Your Wish Is My Command方法中的一个示例,请考虑 OpenSolaris,其中 memcpy (对于某些配置)是根据 bcopy 定义的,而bcopy(对于某些配置)是......
void
33 bcopy(from, to, count)
34 #ifdef vax
35 unsigned char *from, *to;
36 int count;
37 {
38
39 asm(" movc3 12(ap),*4(ap),*8(ap)");
40 }
41 #else
42 #ifdef u3b /* movblkb only works with register args */
43 unsigned char *from, *to;
44 int count;
45 {
46 asm(" movblkb %r6, %r8, %r7");
47 }
48 #else
49 unsigned char *from, *to;
50 int count;
51 {
52 while ((count--) > 0)
53 *to++ = *from++;
54 }
55 #endif
编辑:谢谢,米莉史密斯!这是我在上面链接的 geocities 页面上的内容:
MOVS
指令 movs 用于将源字符串复制到目标中(是的,复制,而不是移动)。该指令有两种变体:movsb 和 movsw。movsb(“移动字符串字节”)一次移动一个字节,而 movsw 一次移动两个字节。
由于我们想一次移动几个字节,这些 movs 指令是使用 rep 前缀分批完成的。移动次数由 CX 寄存器指定。请参见下面的示例:
:
lds si, [src]
les di, [dest]
cld
mov cx, 100
rep movsb
:
此示例将从 src 复制 100 个字节到 dest。如果将 movsb 替换为 movsw,则改为复制 200 个字节。如果删除 rep 前缀,CX 寄存器将不起作用。您将移动一个字节(如果是 movsb,如果是 movsw,则移动 2 个字节)。
不要打扰。微软的替代品并没有那么好。主要价值在于这些会导致您的代码无法移植到 Linux。微软在他们卖给你客户的操作系统上赚的钱比他们在你购买的 Visual C++ 副本上赚的钱要多得多。
如果使用得当,电锯是安全的。与 memcpy() 相同。但在这两种情况下,如果你撞到钉子,它就会飞起来伤害你。
简而言之,低级计算需要 memcpy() 并且不会消失,但对于高级编程,您不需要它。Python 中没有 memcpy() 。
文章本身描述了一个更安全的替代方案:memcpy_s,它要求您指定目标的最大长度。当该数字独立于要复制的字节量提供时,它可以作为防止缓冲区溢出的屏障。当然,您可以通过给两者提供相同的号码来滥用它。
在我的代码中禁止 memcpy() 是让我成为更好的程序员和我的应用程序更安全还是更不兼容?我不确定,如果 MS 真的想改变任何东西,或者只是让任何新的 C 代码与其他编译器不兼容。顺便提一句。MS 在许多功能上都使用了这个技巧,这很烦人。strcpy -> strcpy_s -> StringCchCopy。
我认为 C 应该留给程序员一个选择自己的脚。如果操作正确,手动内存管理是安全的。
你自己说过:“微软在其安全编程商店中禁止使用 memcpy() 函数,我理解该函数固有的漏洞,”
众所周知,memcpy() 和许多其他标准函数会导致漏洞,那么当(尽管是增量的)改进微不足道时,为什么安全的编程商店会允许使用它们呢?
毫无疑问,在他们努力提高自己产品的安全性的过程中,代码审查清楚地表明,这些函数是造成很大一部分漏洞、缓冲区溢出等的原因。他们没有制作包装器供内部使用,而是将它们引入标准库并为了所有人的利益添加了编译器警告(不是禁令)。
另一种方法是调用memcpy_s
如果您使用的是旧版本,例如 C99 或 C++98,或者在 Solaris 上,则不能使用 memcpy_s,除非您安装了 Safe C 库。
memcpy_s() 是 Microsoft 特定的实现,根据他们自己的标准,在 C11 之前的非 MS 实现(包括 ANSI)上不存在。
我将把支持 MS 和反 MS 的东西放在一边,因为这无关紧要。
memmove() 无论如何都是一个更好的解决方案,因为它解决了重叠问题。memmove_s() 更健壮,但同样,仅当您使用 C11 或更高版本时。
您应该改用 memcpy_s() 。对于被认为是不安全的各种其他功能,存在相同类型的 _s 版本。