What's wrong with this code sample, the answer
Yesterday, I posted a question about a security sample I ran into the other day. I mentioned that the function made me cringe the instant I saw it.
Mike Dunn and Sys64378 danced around the root of what made the function cringeworthy, but Alan nailed it first.
The reason I cringed when looking at the code is that it worked by accident, not by design.
Here's the code again (C&P because it's short):
HRESULT Function(char *s1, char *s2) {
char temp[32];
HRESULT hr = StringCchCopy(temp,sizeof(temp),s1);
if (FAILED(hr)) return hr;
return StringCchCat(temp,sizeof(temp),s2);
}
The code as written is correct (yes, grue, Luciano and others pointed out that it actually doesn't do anything, but neither did the original code (this is supposed to be a secure version of an existing function).
However the problem in the code becomes blindingly obvious when you follow Sys64738's suggestion:
HRESULT Function(TCHAR *s1, TCHAR *s2) {
TCHAR temp[32];
HRESULT hr = StringCchCopy(temp,sizeof(temp),s1);
if (FAILED(hr)) return hr;
return StringCchCat(temp,sizeof(temp),s2);
}
The problem is that the function depends on the fact that temp[] is declared as an array of type "char". Once you redeclare temp (and s1 and s2) as TCHAR's (which is a likely first step in a conversion to unicode), then it would INTRODUCE a security hole the instant that someone set UNICODE=1.
Mike Dunn's answer (use StringCchCopyA and StringCchCatA) would absolutely work in this situation (because when you enabled UNICODE, then you would get a compiler error).
But I think a far better solution would be:
HRESULT Function(char *s1, char *s2) {
char temp[32];
HRESULT hr = StringCbCopy(temp,sizeof(temp),s1);
if (FAILED(hr)) return hr;
return StringCbCat(temp,sizeof(temp),s2);
}
If you use the Cb version of the safe String functions then you're safe regardless of the type of temp.
Things that weren't wrong (IMHO):
Checking for null s1 and s2. First off, this is sample code (and thus the checks would distract from the point being made), and secondly, I'm a firm believer that you don't check for correctness of input values - IMHO it's far better to crash when a caller violates your API contract than to try to resolve the issue.
Comments
Anonymous
March 09, 2007
"Checking for null s1 and s2." The StringXxxxEx versions do also that. Safer that safe. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/resources/strings/stringreference/stringfunctions/stringcbcopyex.aspAnonymous
March 09, 2007
The comment has been removedAnonymous
March 09, 2007
The comment has been removedAnonymous
March 09, 2007
<blockquote> IMHO it's far better to crash when a caller violates your API contract than to try to resolve the issue </blockquote> This depends on the environment. If you're in the kernel, you'd better not crash on an API violation if it was a simple thing to validate. Device driver developers don't always check coverage for all code paths, and better four extra bytes of binary than a BSOD. In userspace, it depends on how easy it is to run a debugger on the code in question.Anonymous
March 09, 2007
The comment has been removedAnonymous
March 09, 2007
The comment has been removedAnonymous
March 10, 2007
Our in-house coding standard requires us to use a NUMCHARS macro instead of sizeof in this usage. In fact, we have a NUMBYTES macro as well, and vanilla sizeof is not allowed (as it is a sign that the programming didn't think through whether they want CHARS or BYTES). ///d@Anonymous
March 10, 2007
The comment has been removedAnonymous
March 11, 2007
Why a bug ? Unless it is refactored, it's not a bug. If it gets refactored it should of course being rechecked in its entirety. If you consider this a bug, then it's also missing a critical section! You know some one could refactor temp to being static..Anonymous
March 11, 2007
Wouldn't it be better to 'fix' this code by using the _countof macro instead of sizeof?Anonymous
March 30, 2007
I agree with Larry, better to crash early (unless in kernel or a driver).Anonymous
May 14, 2007
Hi, I dont see the issue. If someone were to refactor the code to unicode they would HAVE to alter 'char temp[32]' to TCHAR because otherwise it won't compile ! HRESULT Function(TCHAR *s1, TCHAR *s2) { char temp[32]; HRESULT hr = StringCchCopy(temp,sizeof(temp),s1); if (FAILED(hr)) return hr; return StringCchCat(temp,sizeof(temp),s2); } On my system this produces : error C2664: 'StringCchCopyW' : cannot convert parameter 1 from 'char [32]' to 'STRSAFE_LPWSTR'Anonymous
May 14, 2007
The comment has been removed