Please Join me in welcoming memcpy() to the SDL Rogues Gallery
Over the last few years I have written a number of articles, papers and books describing some of the dangers of using various buffer-manipulating C runtime functions. Well-known examples of bad function calls include strcpy(), strcat(), strncpy(), strncat(), gets() and their foul brethren. The SDL bans these and many other functions with dubious security history. But, when it comes to banning functions, we must tread a very fine line because we can’t just ban something because it looks odd, or that gut instinct tells us it’s bad, we can only ban functionality that has been demonstrated to cause security vulnerabilities and only if there is a viable alternative.
Because we have seen many security vulnerabilities in products from Microsoft and many others, including ISVs and competitors, and because we have a viable replacement, I am “proud” to announce that we intend to add memcpy() will to the SDL C and C++ banned API list later this year as we make further revisions to the SDL. Right now, memcpy() is on the SDL Recommended banned list, but will soon be added to the SDL banned API requirement list now that we have more feedback from Microsoft product groups.
The following security updates all have one thing in common: memcpy().
· MS03-030 (DirectX)
· MS03-043 (Messenger Service)
· MS03-044 (Help and Support)
· MS05-039 (PnP)
· MS04-011 (PCT)
· MS05-030 (Outlook Express)
· CVE-2007-3999 (MIT Kerberos v5)
· CVE-2007-4000 (MIT Kerberos v5)
· …many more!
It’s not just memcpy() that we’re banning; we will also ban CopyMemory() and RtlCopyMemory(), and the replacement function is memcpy_s().
Banning memcpy() in your code
You too should start banning memcpy() in your new code, here’s what you can do right now:
Add the following line of code to a common header file:
#pragma deprecated (memcpy, RtlCopyMemory, CopyMemory)
Every time the compiler sees an instance of the banned functions, you’ll get the following warning:
warning C4995: 'memcpy': name was marked as #pragma deprecated
In Visual C++, you can also add this early in a common header:
#define _CRT_SECURE_WARNINGS_MEMORY
And you will get warnings like:
warning C4996: 'memcpy': This function or variable may be unsafe. Consider using memcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. c:\program files\microsoft visual studio 9.0\vc\include\wchar.h(1201) : see declaration of 'memcpy'
You can deprecate these functions if you’re using gcc by poisoning them:
#pragma GCC poison memcpy RtlCopyMemory CopyMemory
Fixing memcpy() calls
Thankfully, it’s pretty simple to migrate a call to memcpy() to a safer call to memcpy_s(); the big difference is memcpy_s() takes one extra parameter: the size of the destination buffer. If nothing else, memcpy_s makes you think about the size of the target buffer.
The SAL-decorated function signature in VC++ 2008 is:
errno_t __cdecl
memcpy_s(
_Out_opt_bytecap_post_bytecount_(_DstSize, _MaxCount)
void * _Dst,
_In_ rsize_t _DstSize,
_In_opt_bytecount_(_MaxCount) const void * _Src,
_In_ rsize_t _MaxCount
);
All you need to do is update calls to memcpy() by adding the size of the destination buffer. So calls like this:
char dst[32];
memcpy(dst,src,len);
becomes
char dst[32];
memcpy_s(dst,sizeof(dst), src,len);
Of course, you can easily make a call to memcpy_s() insecure by getting the buffer sizes wrong. The following code is no better than memcpy():
memcpy_s(dst,len, src,len);
You’ve been warned!
I wonder when Larry, Steve and Linus will start banning strcpy() in their products?