Commit 8b28efae authored by Andrew Nguyen's avatar Andrew Nguyen Committed by Alexandre Julliard

kernel32: Reject an insufficiently sized buffer in FormatMessageA/W.

parent c0e79319
...@@ -570,13 +570,20 @@ DWORD WINAPI FormatMessageA( ...@@ -570,13 +570,20 @@ DWORD WINAPI FormatMessageA(
*((LPVOID*)lpBuffer) = LocalAlloc(LMEM_ZEROINIT,max(nSize, talloced)); *((LPVOID*)lpBuffer) = LocalAlloc(LMEM_ZEROINIT,max(nSize, talloced));
memcpy(*(LPSTR*)lpBuffer,target,talloced); memcpy(*(LPSTR*)lpBuffer,target,talloced);
} else { } else {
lstrcpynA(lpBuffer,target,nSize); if (nSize < talloced)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
goto failure;
}
strcpy(lpBuffer, target);
} }
ret = talloced - 1; /* null terminator */
failure:
HeapFree(GetProcessHeap(),0,target); HeapFree(GetProcessHeap(),0,target);
HeapFree(GetProcessHeap(),0,from); HeapFree(GetProcessHeap(),0,from);
if (!(dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)) HeapFree( GetProcessHeap(), 0, format_args.args ); if (!(dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)) HeapFree( GetProcessHeap(), 0, format_args.args );
ret = (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? strlen(*(LPSTR*)lpBuffer) : strlen(lpBuffer); TRACE("-- returning %u\n", ret);
TRACE("-- returning %d\n", ret);
return ret; return ret;
} }
#undef ADD_TO_T #undef ADD_TO_T
...@@ -595,6 +602,7 @@ DWORD WINAPI FormatMessageW( ...@@ -595,6 +602,7 @@ DWORD WINAPI FormatMessageW(
__ms_va_list* args ) __ms_va_list* args )
{ {
struct format_args format_args; struct format_args format_args;
DWORD ret = 0;
LPWSTR target,t; LPWSTR target,t;
DWORD talloced; DWORD talloced;
LPWSTR from; LPWSTR from;
...@@ -741,21 +749,29 @@ DWORD WINAPI FormatMessageW( ...@@ -741,21 +749,29 @@ DWORD WINAPI FormatMessageW(
*t='\0'; *t='\0';
} }
talloced = strlenW(target)+1; talloced = strlenW(target)+1;
TRACE("-- %s\n",debugstr_w(target));
if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) { if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
/* nSize is the MINIMUM size */ /* nSize is the MINIMUM size */
DWORD len = strlenW(target) + 1; DWORD len = strlenW(target) + 1;
*((LPVOID*)lpBuffer) = LocalAlloc(LMEM_ZEROINIT,len*sizeof(WCHAR)); *((LPVOID*)lpBuffer) = LocalAlloc(LMEM_ZEROINIT,len*sizeof(WCHAR));
strcpyW(*(LPWSTR*)lpBuffer, target); strcpyW(*(LPWSTR*)lpBuffer, target);
} }
else lstrcpynW(lpBuffer, target, nSize); else
{
if (nSize < talloced)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
goto failure;
}
strcpyW(lpBuffer, target);
}
ret = talloced - 1; /* null terminator */
failure:
HeapFree(GetProcessHeap(),0,target); HeapFree(GetProcessHeap(),0,target);
HeapFree(GetProcessHeap(),0,from); HeapFree(GetProcessHeap(),0,from);
if (!(dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)) HeapFree( GetProcessHeap(), 0, format_args.args ); if (!(dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)) HeapFree( GetProcessHeap(), 0, format_args.args );
TRACE("ret=%s\n", wine_dbgstr_w((dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? TRACE("-- returning %u\n", ret);
*(LPWSTR*)lpBuffer : lpBuffer)); return ret;
return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
strlenW(*(LPWSTR*)lpBuffer):
strlenW(lpBuffer);
} }
#undef ADD_TO_T #undef ADD_TO_T
...@@ -638,6 +638,98 @@ static void test_message_from_string(void) ...@@ -638,6 +638,98 @@ static void test_message_from_string(void)
ok(r==2,"failed: r=%d\n",r); ok(r==2,"failed: r=%d\n",r);
} }
static void test_message_insufficient_buffer(void)
{
static const char init_buf[] = {'x', 'x', 'x', 'x', 'x'};
static const char expected_buf[] = {'x', 'x', 'x', 'x', 'x'};
DWORD ret;
CHAR out[5];
SetLastError(0xdeadbeef);
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "test", 0, 0, out, 0, NULL);
ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret);
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n",
GetLastError());
ok(!memcmp(expected_buf, out, sizeof(expected_buf)),
"Expected the buffer to be untouched\n");
SetLastError(0xdeadbeef);
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "test", 0, 0, out, 1, NULL);
ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret);
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n",
GetLastError());
ok(!memcmp(expected_buf, out, sizeof(expected_buf)),
"Expected the buffer to be untouched\n");
SetLastError(0xdeadbeef);
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "test", 0, 0, out, sizeof(out)/sizeof(out[0]) - 1, NULL);
ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret);
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n",
GetLastError());
ok(!memcmp(expected_buf, out, sizeof(expected_buf)),
"Expected the buffer to be untouched\n");
}
static void test_message_insufficient_buffer_wide(void)
{
static const WCHAR test[] = {'t','e','s','t',0};
static const WCHAR init_buf[] = {'x', 'x', 'x', 'x', 'x'};
static const WCHAR expected_buf[] = {'x', 'x', 'x', 'x', 'x'};
static const WCHAR broken_buf[] = {0, 'x', 'x', 'x', 'x'};
static const WCHAR broken2_buf[] = {'t','e','s',0,'x'};
DWORD ret;
WCHAR out[5];
SetLastError(0xdeadbeef);
ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, NULL, 0, 0, NULL, 0, NULL);
if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
{
win_skip("FormatMessageW is not implemented\n");
return;
}
SetLastError(0xdeadbeef);
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, test, 0, 0, out, 0, NULL);
ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret);
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n",
GetLastError());
ok(!memcmp(expected_buf, out, sizeof(expected_buf)),
"Expected the buffer to be untouched\n");
/* Windows Server 2003 and newer report failure but copy a
* truncated string to the buffer for non-zero buffer sizes. */
SetLastError(0xdeadbeef);
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, test, 0, 0, out, 1, NULL);
ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret);
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n",
GetLastError());
ok(!memcmp(expected_buf, out, sizeof(expected_buf)) ||
broken(!memcmp(broken_buf, out, sizeof(broken_buf))), /* W2K3+ */
"Expected the buffer to be untouched\n");
SetLastError(0xdeadbeef);
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, test, 0, 0, out, sizeof(out)/sizeof(out[0]) - 1, NULL);
ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret);
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n",
GetLastError());
ok(!memcmp(expected_buf, out, sizeof(expected_buf)) ||
broken(!memcmp(broken2_buf, out, sizeof(broken2_buf))), /* W2K3+ */
"Expected the buffer to be untouched\n");
}
static void test_message_null_buffer(void) static void test_message_null_buffer(void)
{ {
DWORD ret, error; DWORD ret, error;
...@@ -727,6 +819,8 @@ START_TEST(format_msg) ...@@ -727,6 +819,8 @@ START_TEST(format_msg)
{ {
test_message_from_string(); test_message_from_string();
test_message_from_string_wide(); test_message_from_string_wide();
test_message_insufficient_buffer();
test_message_insufficient_buffer_wide();
test_message_null_buffer(); test_message_null_buffer();
test_message_from_hmodule(); test_message_from_hmodule();
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment