【问题标题】:Memcpy() in secure programming?安全编程中的 Memcpy()?
【发布时间】:2010-10-26 13:58:25
【问题描述】:

我最近偶然发现an article 声称微软正在其安全编程商店中禁止memcpy() 功能。我了解该功能固有的漏洞,但是否有必要完全禁止其使用?

我编写的程序应该完全避免memcpy(),还是只是确保它被安全使用?有哪些替代品可以提供类似但更安全的功能?

【问题讨论】:

    标签: c security memcpy


    【解决方案1】:

    如果使用得当,电锯是安全的。与 memcpy() 相同。但在这两种情况下,如果你碰到钉子,它就会飞起来伤害你。

    简而言之,memcpy() 是低级计算所必需的并且不会消失,但对于高级编程则不需要它。 Python 中没有 memcpy()。

    【讨论】:

    • 请记住,这并不一定会使 Python 变得更好。我喜欢 Python,但有时我只想要一个结构,或者转换一个指针。另一个方向也是如此。
    • 如果我可以选择,我宁愿选择,在 C 中,*struct1 = struct2;而不是 memcpy(struct1,&struct2, sizeof(struct1));
    • 在 memcpy() 和 memcpy_s() 之间的比较中,Python 完全是题外话
    • @0x6adb015 是的,显然,这很简单。 memcpy 在处理不需要对齐的数据(例如,库函数的通用缓冲区输入)和无法合理预期对齐的数据(取决于后端实现的各种对齐要求等)时非常有用。那么处理此类数据的唯一安全、合规且可移植的方法是将其 memcpy 到已知对齐的变量(例如堆栈分配)+ 字节序处理。 x86 通过修复硬件中未对齐的内存访问来隐藏这个问题,但那里有很多 UB 潜力。
    【解决方案2】:

    文章本身描述了一个更安全的替代方案:memcpy_s,它要求你指定目标的最大长度。当该数字独立于要复制的字节数提供时,它可以作为防止缓冲区溢出的屏障。当然,您可以通过给两者提供相同的号码来滥用它。

    【讨论】:

    • 重要的是要知道使用 MS 提供的安全功能会损害跨平台兼容性。
    • 是否有跨平台兼容的 memcpy_s 和 wmemcpy_s 等价物?
    • 自己滚动很简单。文章中甚至还有一个链接。我想知道的是,为什么他们不完全禁止 memcpy 以支持 memmove_s?
    • 便携式替代方案称为memcpy(dest, src, MIN(destsize,count))。但是我看不出这有什么用处。 MS 刚刚起步。
    • @R..:同意。这只是另一个正确的参数。如果错了,你又回到了开始的地方。
    【解决方案3】:

    另一种方法是致电memcpy_s

    【讨论】:

    • memcpy_s 是非标准且特定于供应商的
    【解决方案4】:

    你应该使用 memcpy_s() 代替。对于被认为是不安全的各种其他功能,存在相同类型的 _s 版本。

    【讨论】:

    • memcpy_s 是非标准且特定于供应商的
    【解决方案5】:

    Microsoft 向 memcpy 和 wmemcpy 提供 alternatives 以验证其参数。

    memcpy_s 说:“嗯,在我从这个地址读取之前,让我自己验证它不是空指针;在我写入这个地址之前,我将再次执行该测试。我还将比较数字我被要求将字节数复制到声明的目标大小;当且仅当调用通过所有这些测试时,我才执行复制。”

    memcpy 说“将目标填充到寄存器中,将源填充到寄存器中,将计数填充到寄存器中,执行 MOVSB 或 MOVSW。” (geocities 的例子,这个世界不久:http://www.geocities.com/siliconvalley/park/3230/x86asm/asml1013.html

    编辑:对于 memcpy 的 Your Wish Is My Command 方法中的一个示例,请考虑 OpenSolaris,其中 memcpy 是(对于某些配置)defined in terms of bcopybcopy(对于一些配置)是...

    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 用于将源字符串复制到目标中(是的,复制,而不是移动)。该指令有两种变体: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 个字节)。

    【讨论】:

    • 我们不要忘记,任何好的 memcpy 实现都会考虑内存对齐。
    • 我猜 movsb, movsw 不再是做 memcpy 的最快方法了。我认为(未测试)最快的方法是考虑内存对齐(如所指出的那样)并使用 SSE 指令来复制数据。我相信这就是 OS X gcc 的做法。
    • 喜欢你对 x86 asm 的解释 :)。
    • @Mehrdad,我对 glibc 中 memcpy 的研究因调用 __vm_copy 的源代码而陷入僵局。 vm_copy 不是 glibc 的一部分,我找不到 vm_copy 的源代码。你有链接吗?
    • 不幸的是,memcpy_s 并没有那么好。目标缓冲区的溢出只是一个潜在问题。超出源缓冲区(不太常见)也可能导致安全漏洞,复制重叠的块也是如此。
    【解决方案6】:

    我认为 C 应该给程序员留下一个选择,让程序员自己动手。 如果操作正确,手动内存管理是安全的。

    【讨论】:

    • 使用 memcopy_s 而不是 memcopy 是正确的。在 memcpy 中跳过健全性测试是一种过早的优化。
    • 如果您使用的是 C++,请确保不要用这个来炸掉您的整条腿。 ;)
    【解决方案7】:

    在我的代码中禁止 memcpy() 是否会使我成为更好的程序员和我的应用程序更安全还是更不兼容?我不确定,如果 MS 真的想改变任何东西,或者只是让任何新的 C 代码与其他编译器不兼容。顺便提一句。 MS在许多功能上都使用了这个技巧,这很烦人。 strcpy -> strcpy_s -> StringCchCopy.

    【讨论】:

    • 他们没有禁止它;他们提出了一个警告,表明它可能不安全。如果他们反过来注意到那里的警告并在内部禁止它,那么这对平台来说可能是件好事吗?这不是编译器可移植性问题,而是库可移植性问题。如果您选择使用非标准库函数,那么您选择会破坏可移植性。
    【解决方案8】:

    您自己说过:“微软在其安全编程商店中禁止使用 memcpy() 函数,我了解函数固有的漏洞,”

    memcpy() 和许多其他标准函数已知会导致漏洞,那么当(尽管是增量的)改进微不足道时,为什么安全的编程商店会允许使用它们呢?

    毫无疑问,在他们努力提高自己产品的安全性的过程中,代码审查清楚地表明,这些功能是造成很大一部分漏洞、缓冲区溢出等的原因。他们没有制作包装器供内部使用,而是将它们引入为了所有人的利益,标准库并添加了编译器警告(不是禁令)。

    【讨论】:

    • 因为并没有真正解决问题,所以参数很差。使用一些内置编译器自动查找目标大小的函数将更不容易出错,例如)负数变成一个巨大的无符号 size_t。匆忙推出一个半生不熟的所谓解决方案,它引入了其他编程错误的机会,并声称security 不是真正的解决方案。在这方面还有其他尝试,例如)OpenBSD strlcpy 和 strlcat,由于类似的原因被拒绝。
    【解决方案9】:

    不要打扰。微软的替代品并没有那么好。主要价值在于这些会导致您的代码无法移植到 Linux。 Microsoft 在向您的客户销售的操作系统上赚的钱比在您购买的 Visual C++ 副本上赚的钱要多。

    【讨论】:

    • 仍然可以选择使用memcpy
    • 确实如此。问题是“我应该避免 memcpy”,我的回答是“不,不要打扰”
    【解决方案10】:

    如果您使用的是旧版本,例如 C99 或 C++98,或者在 Solaris 上,则不能使用 memcpy_s,除非您安装了 Safe C 库。

    memcpy_s() 是 Microsoft 特定的实现,根据他们自己的标准,在 C11 之前的非 MS 实现(包括 ANSI)上不存在。

    我会把赞成 MS 和反对 MS 的东西放在一边,因为这无关紧要。

    memmove() 无论如何是一个更好的解决方案,因为它解决了重叠问题。 memmove_s() 更健壮,但同样,仅当您使用 C11 或更高版本时。

    【讨论】:

    • 什么的工作示例?你可以说得更详细点吗;我不确定你在问什么。
    猜你喜欢
    • 2013-02-15
    • 1970-01-01
    • 2018-12-11
    • 2013-03-10
    • 1970-01-01
    • 2017-07-31
    • 1970-01-01
    • 2018-11-27
    • 2011-07-11
    相关资源
    最近更新 更多