19

I recently stumbled across an article that claims Microsoft is banning the memcpy() function in its secure programming shops. I understand the vulnerabilities inherent in the function, but is it necessary to ban its use entirely?

Should programs I write be avoiding memcpy() entirely, or just ensuring that it's used safely? What alternatives exist that provide similar but safer functionalilty?

Tim
  • 59,527
  • 19
  • 156
  • 165

10 Answers10

32

Microsoft provides alternatives to memcpy and wmemcpy that validate their parameters.

memcpy_s says, "Hmm, before I read from this address, let me verify for myself that it is not a null pointer; and before I write to this address, I shall perform that test again. I shall also compare the number of bytes I have been requested to copy to the claimed size of the destination; if and only if the call passes all these tests shall I perform the copy."

memcpy says "Stuff the destination into a register, stuff the source into a register, stuff the count into a register, perform MOVSB or MOVSW." (Example on geocities, not long for this world: http://www.geocities.com/siliconvalley/park/3230/x86asm/asml1013.html)

Edit: For an example in the wild of the Your Wish Is My Command approach to memcpy, consider OpenSolaris, where memcpy is (for some configurations) defined in terms of bcopy, and bcopy (for some configurations) is ...

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

Edit: Thanks, Millie Smith! Here is what was on the geocities page I linked above:

MOVS

The instruction movs is used to copy source string into the destination (yes, copy, not move). This instruction has two variants: movsb and movsw. The movsb ("move string byte") moves one byte at a time, whereas movsw moves two bytes at a time.

Since we'd like to move several bytes at a time, these movs instructions are done in batches using rep prefix. The number of movements is specified by CX register. See the example below:

:
lds   si, [src]
les   di, [dest]
cld
mov   cx, 100
rep   movsb
:

This example will copy 100 bytes from src to dest. If you replace movsb with movsw, you copy 200 bytes instead. If you remove the rep prefix, the CX register will have no effect. You will move one byte (if it is movsb, or 2 bytes if it is movsw).

Thomas L Holaday
  • 13,614
  • 6
  • 40
  • 51
  • 3
    Let's not forget that any good memcpy implementation takes memory alignment into count. – TrayMan May 15 '09 at 18:45
  • I guess movsb, movsw is not the fastest way to do memcpy anymore. I *think* (not tested) the fastest way will be to take memory alignment in consideration (as pointed out) and use SSE instructions to copy data around. I believe this is the way OS X gcc does it. – Mehrdad Afshari May 15 '09 at 19:46
  • Liked your explanation in term of x86 asm :). – Priyanka Mishra May 16 '09 at 15:12
  • @Mehrdad, my research on memcpy in glibc dead-ends with the source calling __vm_copy. vm_copy is not part of glibc, and I cannot find the source for vm_copy. Do you have a link, by any chance? – Thomas L Holaday May 16 '09 at 16:38
  • Unfortunately, memcpy_s isn't that much better. Overruns of the destination buffer is only one potential problem. Overrunning the source buffer (less common) can also cause security holes, as can copying blocks that overlap. – Adrian McCarthy Mar 25 '11 at 20:54
  • I can see value in a variant of sprintf which restricts the destination length, on the basis that there's no other practical way for a caller to determine how much data sprintf would produce. On the other hand, I'm not quite clear what value memcpy_s would provide. Oftentimes, the source operand is going to be computed as an offset into some buffer, and it would be cleaner for the caller to ensure that destoffset+numbytes neither overflows, nor is greater than, destsize. Otherwise, if one passes destsize-destoffset to memcpy_s, one won't have any protection if destoffset is out of bounds. – supercat Nov 20 '11 at 22:40
  • Geocities expired in 2009, so that link actually pulls up the rickroll video. – Millie Smith Sep 08 '15 at 23:48
  • @ThomasLHoladay, don't look at memcpy.c, look at assembler variants. For example sysdeps/x86_64/multiarch/memcpy-ssse3.S first checks if the count is less than 80 bytes and if so a jump table is used to jump to a code that moves that number of bytes without taking alignment into account. For larger blocks aligned SSE is used (and when it is not possible to align src and dst - shifts are preformed to use aligned instructions anyway). That said on fairly modern processors "rep movsb" is faster than memcpy once you copy more than 1000 bytes or so. – virco Aug 25 '16 at 14:08
9

Don't bother. Microsofts alternatives are not that much better. The main value is that these cause your code to become unportable to Linux. Microsoft is making much more money on the OS they sell to your customers than they're making on the copy of Visual C++ you bought.

MSalters
  • 173,980
  • 10
  • 155
  • 350
9

A chainsaw, if used properly, is safe. Same thing with memcpy(). But in both cases, if you hit a nail, it can fly and hurt you.

In short, memcpy() is required for low-level computing and won't go away, but for high-level programming you don't need it. There is no memcpy() in Python.

0x6adb015
  • 7,473
  • 4
  • 24
  • 38
  • 2
    Keeping in mind that this doesn't necessarily make Python better. I love Python but sometimes I just want a struct, or to cast a pointer. The same applies the other direction. – Matt Joiner Aug 26 '10 at 07:32
  • If I have the choice, I rather do, in C, *struct1 = struct2; instead of memcpy(struct1,&struct2, sizeof(struct1)); – 0x6adb015 Aug 16 '12 at 13:31
  • 5
    Python is completely off topic in a comparison between memcpy() and memcpy_s() – MarcH Dec 17 '13 at 23:33
  • @0x6adb015 Yes, obviously, this is a no-brainer. memcpy is very useful when dealing with data that need not be aligned (for instance, generic buffer input to a library function) and which cannot reasonably be expected to be aligned (various alignment requirements depending on backend implementation, etc...). Then the **only** safe, compliant, and portable way to work on such data is to memcpy it to a known-aligned variable (e.g. stack-allocated) + endianness handling. x86 hides the issue by fixing unaligned memory accesses in hardware, but there is a lot of UB potential there. – Thomas Jul 17 '14 at 04:35
6

The article itself describes a safer alternative: memcpy_s, which requires you to specify the maximum length of the target. When that number is provided independent of the amount of bytes to copy, it acts as a barrier to prevent buffer overflow. Of course, you can abuse that by giving the same number to both.

TrayMan
  • 7,180
  • 3
  • 24
  • 33
3

Is banning memcpy() in my code making me a better programmer and my application safer or just more incompatible? I'm uncertain, if MS really wants to change anything or just make any new C code incompatible with other compilers. Btw. MS does this trick on many functions and it's quite annoying. strcpy -> strcpy_s -> StringCchCopy.

merkuro
  • 6,161
  • 2
  • 27
  • 29
  • They haven't banned it; they have introduced a warning that its potentially insecure. If they have in turn heeded there warning and banned it internally then perhaps thats a good thing for the platform? This isn't a compiler portability issue, its a library portability issue. If you *choose* to use a non-standard library function then you *choose* to break portability. –  Oct 15 '09 at 11:54
2

You said it yourself: "Microsoft is banning the memcpy() function in its secure programming shops, I understand the vulnerabilities inherent in the function,"

memcpy() and a plethora of other standard functions are known to cause vulnerabilities, so why would a secure programming shop allow their use when an (albeit incremental) improvement is trivial?

No doubt in their efforts to improve the security of their own products, the code reviews clearly indicated that these functions were responsible for a significant proportion of vulnerabilities, buffer overflows etc. Rather than make wrappers for internal use only they introduced them into the standard library and added a compiler warning (not a ban) for the benefit of all.

  • Because it doesn't really solve the problem, the parameter is poor. A function using some compiler builtin which auto looked up the destination size, would be far less error prone eg) negative number becomes a huge sized unsigned size_t. Rushing a half baked so called solution, which introduces other opportunities for programming errors and claiming `security` isn't a real solution. There's other attempts at this eg) OpenBSD strlcpy and strlcat, which are rejected for similar reasons. – Rob11311 Jun 28 '14 at 13:21
2

I think that C should leave an option to the programmer to shoot his own foot. manual memory management is safe if done properly.

Anton Kazennikov
  • 3,574
  • 5
  • 30
  • 38
0

If you're using older versions, like C99 or C++98, or on Solaris, you can't use memcpy_s, unless you have the Safe C library installed.

memcpy_s() is a Microsoft-specific implementation that doesn't exist on non-MS implementations, including ANSI, prior to C11, per their own standards.

I'll leave the pro-MS and anti-MS stuff aside, because it's irrelevant.

memmove() is a better solution anyway since it addressed the overlap issue. memmove_s() is more robust, but again, only if you're in C11 or later.

mseebeck
  • 11
  • 3
0

The alternative is to call memcpy_s

Sean
  • 60,939
  • 11
  • 97
  • 136
-2

You are supposed to use memcpy_s() instead. The same kind of _s versions exist for a variety of other functions considered as unsecure.

Jem
  • 2,255
  • 18
  • 25