0

I know there is a great deal of discussion about how memcpy() is unsafe in the Windows/Microsoft world, but does that apply to Mac OS X code as well (Cocoa)? If so, what function should be used in Cocoa for maximum safety? memcpy_s() doesn't seem to be present on the platform.

Thanks.

Update: I realize speaking about memcpy() even in windows is sort of a gray area (see Memcpy() in secure programming?), but I am trying to discover whether this same exact discussion applies to Mac OS X or not. Just the fact that Mac OS X does't include a 'secure' version of memcpy() seems to imply Apple feels that things aren't that bad.

Community
  • 1
  • 1
Locksleyu
  • 5,192
  • 8
  • 52
  • 77
  • In what sense is `memcpy()` unsafe? Not thread-safe? – Costique Apr 16 '12 at 12:31
  • @Costique I guess he means that there is no additional parameter to `memcpy()` which defines the size of the destination buffer and so it's possible to overrun it. – trojanfoe Apr 16 '12 at 12:35
  • I added a update to the original post regarding memcpy's unsafeness, but trojanfoe mentioned the main disadvantage. – Locksleyu Apr 16 '12 at 12:36
  • 1
    I wouldn't have thought `memcpy()` is as bad as the `ssprintf`-family of functions, which could generate unexpected destination sizes depending on input; at least with `memcpy()` to get to define exactly how much data is written to the destination. You can make it safe yourself by always checking this is not greater than the destination buffer. – trojanfoe Apr 16 '12 at 12:38
  • @trojanfoe memcpy() is NOT safe if the source and destination memory buffers overlap. –  Apr 16 '12 at 13:04
  • @jeffsix Or if the destination points to the top of the stack, or page 0, or system space, or... well lots of places. So what? – trojanfoe Apr 16 '12 at 13:15
  • @trojanfoe "You can make it safe yourself by always checking this is not greater than the destination buffer." <- You cannot. You can make it safe by checking for lots and lots of problem cases. Unless you miss one and then it's not safe. So, it's not safe. Don't use it. –  Apr 16 '12 at 14:52
  • @jeffsix So you don't use any API function that isn't *safe*? Where's the fun in that? :) – trojanfoe Apr 16 '12 at 15:03
  • If Apple "doesn't care about security", then Microsoft encourages people to write unportable code; the return values of `_snprintf()` and `vsnprintf()` come to mind (despite claiming "vsnprintf is included for compliance to the ANSI standard", it doesn't conform to C99; I don't have C95 handy but I suspect the spec for the return value did not change). For more fun, the behaviour of `memcpy_s()` is also undefined if the source and destination overlap, so if you care you should use `memmove_s()`. If you want a little more safety, why are you using C? – tc. Dec 31 '13 at 18:52

4 Answers4

3

You should use memmove instead of memcpy when the memory areas can overlap.

They are not inherently unsafe if you program defensively and are aware of what they are actually doing.

j13r
  • 2,576
  • 2
  • 21
  • 28
  • I think by "safe", OP means "provides safeguards". Like how driving a car which doesn't have airbags nor seatbelts is not inherently unsafe if you drive defensively an are aware of what it's actually doing. – Ky - May 08 '20 at 20:14
2

It's quite new AFAIK, and not perfect, but GCC supplies a wrapper called __memcpy_chk which checks the size of the destination when possible, take a look here. The usage for it (from the same resource):

 #undef memcpy
 #define bos0(dest) __builtin_object_size (dest, 0)
 #define memcpy(dest, src, n) \
   __builtin___memcpy_chk (dest, src, n, bos0 (dest))

 char *volatile p;
 char buf[10];
 /* It is unknown what object p points to, so this is optimized
    into plain memcpy - no checking is possible.  */
 memcpy (p, "abcde", n);
 /* Destination is known and length too.  It is known at compile
    time there will be no overflow.  */
 memcpy (&buf[5], "abcde", 5);
 /* Destination is known, but the length is not known at compile time.
    This will result in __memcpy_chk call that can check for overflow
    at runtime.  */
 memcpy (&buf[5], "abcde", n);
 /* Destination is known and it is known at compile time there will
    be overflow.  There will be a warning and __memcpy_chk call that
    will abort the program at runtime.  */
 memcpy (&buf[6], "abcde", 5);
MByD
  • 135,866
  • 28
  • 264
  • 277
  • A nice talk about it (and some other stuff) may be found here: http://www.youtube.com/watch?v=38Nu7YOt6lQ – MByD Apr 16 '12 at 12:56
  • I believe this is used in the default `memcpy()` (though you may have to enable the right warning flags). – tc. Dec 31 '13 at 18:53
2

Buffer overflows (which is the security issue with memcpy, strcpy et al.) are OS-agnostic; essentially they're a problem inherent to the C language because it doesn't provide automatic bounds checking.

Used properly with due diligence, memcpy is safe; for example, if you validate the parameters yourself, or the sizes are known at compile-time. But everyone makes mistakes.

MS's approach in banning memcpy and using their own memcpy_s is to reduce bugs by forcing programmers to do the additional safety checks everywhere. You can write your own memcpy_s if you want; it's not hard to do, just implement the behaviour described on its MSDN page.

...seems to imply Apple feels that things aren't that bad.

The corollary is that Microsoft feels that things are that bad. However, what a company feels about a problem does not affect the existence of said problem, i.e. that not validating your inputs to memcpy is responsible for a class of vulnerabilities.

seabee
  • 83
  • 6
1

I'm not impressed by Microsoft's memcpy_s() because it is still up to the caller to supply the destination buffer size. Since the main thing that can go wrong with memcpy() (excepting if the source and destination buffers overlap) is caused by not knowing how big the destination buffer really is, is it not likely that the caller will put the wrong size for the destination in?

I suppose there is one class of errors it will help with exemplified by:

  char anArray[10]
  char* foo = anArray;
  memcpy_s(foo, sizeof foo, somewhereElse, 10);
  // or
  memcpy_s(foo, sizeof *foo, somewhereElse, 10);

However, both of these demonstrate a fundamental misunderstanding of C pointers and will likely not be the only problems with the code.

And what do you do if the destination is too small? Do you carry on with the truncated data? Do you put out an error message saying "Alert: programmer is an idiot"? No, it's better to know that your destination buffer is big enough before starting to do the copy.

Also, the link in the question talks about memcpy_s() having a null pointer check. Again, what are you going to do? Having the program crash is about all you can do sanely because, if a pointer you expected not to be null is null, you can't trust any part of your program's running environment. And on modern PC operating systems, the program will crash as soon as memcpy() attempts to dereference the null pointer.

JeremyP
  • 84,577
  • 15
  • 123
  • 161