diff options
Diffstat (limited to 'src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory')
12 files changed, 930 insertions, 0 deletions
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/CMakeLists.txt new file mode 100644 index 0000000000..d2ae61f923 --- /dev/null +++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +add_subdirectory(ReadProcessMemory_neg1) +add_subdirectory(test1) +add_subdirectory(test2) + diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/CMakeLists.txt new file mode 100644 index 0000000000..400c9219f6 --- /dev/null +++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(SOURCES + ReadProcessMemory_neg.c +) + +add_executable(paltest_readprocessmemory_readprocessmemory_neg1 + ${SOURCES} +) + +add_dependencies(paltest_readprocessmemory_readprocessmemory_neg1 coreclrpal) + +target_link_libraries(paltest_readprocessmemory_readprocessmemory_neg1 + pthread + m + coreclrpal +) diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/ReadProcessMemory_neg.c b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/ReadProcessMemory_neg.c new file mode 100644 index 0000000000..aecd5ad576 --- /dev/null +++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/ReadProcessMemory_neg.c @@ -0,0 +1,127 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*============================================================= +** +** Source: ReadProcessMemory_neg.c +** +** Purpose: Negative test the ReadProcessMemory API. +** Call ReadProcessMemory to read unreadabel memory area +** +** +**============================================================*/ +#include <palsuite.h> + +#define REGIONSIZE 1024 + +int __cdecl main(int argc, char *argv[]) +{ + int err; + BOOL bResult; + HANDLE ProcessHandle; + DWORD ProcessID; + LPVOID lpProcessAddress = NULL; + char ProcessBuffer[REGIONSIZE]; + ULONG_PTR size = 0; + + + /*Initialize the PAL environment*/ + err = PAL_Initialize(argc, argv); + if(0 != err) + { + return FAIL; + } + + /*retrieve the current process ID*/ + ProcessID = GetCurrentProcessId(); + + /*retrieve the current process handle*/ + ProcessHandle = OpenProcess( + PROCESS_ALL_ACCESS, + FALSE, /*not inherited*/ + ProcessID); + + if(NULL == ProcessHandle) + { + Fail("\nFailed to call OpenProcess API to retrieve " + "current process handle error code=%u\n", + GetLastError()); + } + + + + /*allocate the virtual memory*/ + lpProcessAddress = VirtualAlloc( + NULL, /*system determine where to allocate the region*/ + REGIONSIZE, /*specify the size*/ + MEM_RESERVE, /*allocation type*/ + PAGE_READONLY); /*access protection*/ + + if(NULL == lpProcessAddress) + { + Fail("\nFailed to call VirtualAlloc API to allocate " + "virtual memory, error code=%u\n", GetLastError()); + } + + /*zero the memory*/ + memset(ProcessBuffer, 0, REGIONSIZE); + /*try to retrieve the unreadable memory area*/ + bResult = ReadProcessMemory( + ProcessHandle, /*current process handle*/ + lpProcessAddress, /*base of memory area*/ + (LPVOID)ProcessBuffer, + REGIONSIZE, /*buffer length in bytes*/ + &size); + + + /*check the return value*/ + if(0 != bResult) + { + Trace("\nFailed to call ReadProcessMemory API for a negative test, " + "Try to read an unreadable memory area will cause fail " + "but it successes\n"); + + err = CloseHandle(ProcessHandle); + if(0 == err) + { + Trace("\nFailed to call CloseHandle API, error code=%u\n", + GetLastError()); + } + + /*decommit the specified region*/ + err = VirtualFree(lpProcessAddress, REGIONSIZE, MEM_DECOMMIT); + if(0 == err) + { + Trace("\nFailed to call VirtualFree API, error code=%u\n", + GetLastError()); + } + Fail(""); + } + + err = CloseHandle(ProcessHandle); + if(0 == err) + { + Trace("\nFailed to call CloseHandle API, error code = %u\n", + GetLastError()); + + err = VirtualFree(lpProcessAddress, REGIONSIZE, MEM_DECOMMIT); + if(0 == err) + { + Trace("\nFailed to call VirtualFree API, error code=%u\n", + GetLastError()); + } + + Fail(""); + } + /*decommit the specified region*/ + err = VirtualFree(lpProcessAddress, REGIONSIZE, MEM_DECOMMIT); + if(0 == err) + { + Fail("\nFailed to call VirtualFree API, error code=%u\n", + GetLastError()); + } + + PAL_Terminate(); + return PASS; +} diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/testinfo.dat new file mode 100644 index 0000000000..08c8f3291d --- /dev/null +++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/testinfo.dat @@ -0,0 +1,12 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +Version = 1.0 +Section = Filemapping_memmgt +Function = ReadProcessMemory +Name = Negative test ReadProcessMemory API to read unreadable memory area +TYPE = DEFAULT +EXE1 = readprocessmemory_neg +Description +=Test the ReadProcessMemory to read unreadable memory area diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test1/CMakeLists.txt new file mode 100644 index 0000000000..8c21f01562 --- /dev/null +++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test1/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(SOURCES + ReadProcessMemory.c +) + +add_executable(paltest_readprocessmemory_test1 + ${SOURCES} +) + +add_dependencies(paltest_readprocessmemory_test1 coreclrpal) + +target_link_libraries(paltest_readprocessmemory_test1 + pthread + m + coreclrpal +) diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test1/ReadProcessMemory.c b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test1/ReadProcessMemory.c new file mode 100644 index 0000000000..c9475f13f1 --- /dev/null +++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test1/ReadProcessMemory.c @@ -0,0 +1,126 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*============================================================= +** +** Source: ReadProcessMemory.c +** +** Purpose: Positive test the ReadProcessMemory API. +** Call ReadProcessMemory to read memory contents +** inside current process. +** +** +**============================================================*/ +#include <palsuite.h> + +#define REGIONSIZE 1024 + +int __cdecl main(int argc, char *argv[]) +{ + int err; + BOOL bResult; + HANDLE ProcessHandle; + DWORD ProcessID; + LPVOID lpProcessAddress = NULL; + char ProcessBuffer[REGIONSIZE]; + ULONG_PTR size = 0; + + + /*Initialize the PAL environment*/ + err = PAL_Initialize(argc, argv); + if(0 != err) + { + return FAIL; + } + + /*retrieve the current process ID*/ + ProcessID = GetCurrentProcessId(); + + /*retrieve the current process handle*/ + ProcessHandle = OpenProcess( + PROCESS_VM_READ,/*access flag*/ + FALSE, /*not inherited*/ + ProcessID); + + if(NULL == ProcessHandle) + { + Fail("\nFailed to call OpenProcess API to retrieve " + "current process handle error code=%u\n", + GetLastError()); + } + + /*allocate the virtual memory*/ + lpProcessAddress = VirtualAlloc( + NULL, /*system determine where to allocate the region*/ + REGIONSIZE, /*specify the size*/ + MEM_COMMIT, /*allocation type*/ + PAGE_READONLY); /*access protection*/ + + if(NULL == lpProcessAddress) + { + Fail("\nFailed to call VirtualAlloc API to allocate " + "virtual memory, error code=%u!\n", GetLastError()); + } + + /*zero the memory*/ + memset(ProcessBuffer, 0, REGIONSIZE); + + /*retrieve the memory contents*/ + bResult = ReadProcessMemory( + ProcessHandle, /*current process handle*/ + lpProcessAddress, /*base of memory area*/ + (LPVOID)ProcessBuffer, + REGIONSIZE, /*buffer length in bytes*/ + &size); + + if(!bResult || REGIONSIZE != size) + { + Trace("\nFailed to call ReadProcessMemory API " + "to retrieve the memory contents, error code=%u\n", + GetLastError()); + + err = CloseHandle(ProcessHandle); + if(0 == err) + { + Trace("\nFailed to call CloseHandle API, error code=%u\n", + GetLastError()); + } + + /*decommit the specified region*/ + err = VirtualFree(lpProcessAddress, REGIONSIZE, MEM_DECOMMIT); + if(0 == err) + { + Trace("\nFailed to call VirtualFree API, error code=%u\n", + GetLastError()); + } + Fail(""); + } + + err = CloseHandle(ProcessHandle); + if(0 == err) + { + Trace("\nFailed to call CloseHandle API, error code = %u\n", + GetLastError()); + + err = VirtualFree(lpProcessAddress, REGIONSIZE, MEM_DECOMMIT); + if(0 == err) + { + Trace("\nFailed to call VirtualFree API, error code=%u\n", + GetLastError()); + } + + Fail(""); + } + + /*decommit the specified region*/ + err = VirtualFree(lpProcessAddress, REGIONSIZE, MEM_DECOMMIT); + if(0 == err) + { + Fail("\nFailed to call VirtualFree API, error code=%u\n", + GetLastError()); + } + + PAL_Terminate(); + return PASS; +} diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test1/testinfo.dat new file mode 100644 index 0000000000..c56920d206 --- /dev/null +++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test1/testinfo.dat @@ -0,0 +1,12 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +Version = 1.0 +Section = Filemapping_memmgt +Function = ReadProcessMemory +Name = Positive test for ReadProcessMemory API to read memory contents +TYPE = DEFAULT +EXE1 = readprocessmemory +Description +=Test the ReadProcessMemory to read the memory contents diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/CMakeLists.txt new file mode 100644 index 0000000000..9e0de95a0a --- /dev/null +++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(TESTSOURCES + test2.c +) + +add_executable(paltest_readprocessmemory_test2 + ${TESTSOURCES} +) + +add_dependencies(paltest_readprocessmemory_test2 coreclrpal) + +target_link_libraries(paltest_readprocessmemory_test2 + pthread + m + coreclrpal +) + + +set(HELPERSOURCES + helper.c +) + +add_executable(paltest_readprocessmemory_test2_helper + ${HELPERSOURCES} +) + +add_dependencies(paltest_readprocessmemory_test2_helper coreclrpal) + +target_link_libraries(paltest_readprocessmemory_test2_helper + pthread + m + coreclrpal +) diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/commonconsts.h b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/commonconsts.h new file mode 100644 index 0000000000..433d820f0f --- /dev/null +++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/commonconsts.h @@ -0,0 +1,48 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*============================================================= +** +** Source: commonconsts.h +** +** +**============================================================*/ + +#ifndef _COMMONCONSTS_H_ +#define _COMMONCONSTS_H_ + +#include <pal.h> +#define REGIONSIZE 1024 + +const int TIMEOUT = 40000; + +const WCHAR szcToHelperEvName[] = { 'T', 'o', '\0' }; +const WCHAR szcFromHelperEvName[] = { 'F', 'r', 'o', 'm', '\0' }; + +const char initialValue = '-'; +const char nextValue = '|'; +const char guardValue = '*'; +const char *commsFileName = "AddrNLen.dat"; + + +/* PEDANTIC and PEDANTIC0 is a helper macro that just grumps about any + * zero return codes in a generic way. with little typing */ +#define PEDANTIC(function, parameters) \ +{ \ + if (! (function parameters) ) \ + { \ + Trace("%s: NonFatal failure of %s%s for reasons %u and %u\n", \ + __FILE__, #function, #parameters, GetLastError(), errno); \ + } \ +} +#define PEDANTIC1(function, parameters) \ +{ \ + if ( (function parameters) ) \ + { \ + Trace("%s: NonFatal failure of %s%s for reasons %u and %u\n", \ + __FILE__, #function, #parameters, GetLastError(), errno); \ + } \ +} + +#endif diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/helper.c b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/helper.c new file mode 100644 index 0000000000..59e882fc1f --- /dev/null +++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/helper.c @@ -0,0 +1,249 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*============================================================= +** +** Source: helper.c +** +** Purpose: This helper process sets up a several blocks of memory, +** then uses a file to tell its parent process where that memory is +** So it can do a WriteProcessMemory on it. When the parent process is done +** we check here that it was written properly. +** +** +**============================================================*/ + +#include "commonconsts.h" + +#include <palsuite.h> + +#if defined(BIT64) && defined(PLATFORM_UNIX) +#define LLFORMAT "%I64u" +#else +#define LLFORMAT "%u" +#endif + +struct allhandles_t +{ + HANDLE hEvToHelper; + HANDLE hEvFromHelper; + char *valuesFileName; +}; + + +/* function: wpmDoIt + * + * This is a general WriteProcessMemory testing function that sets up + * the RAM pointed to and tells the companion process on the other end + * of the handles in 'Comms' to attempt to alter 'lenDest' bytes at + * '*pDest'. + * + * '*pBuffer'[0..'lenBuffer'] is expected to be a guard region + * surrounding the '*pDest'[0..'lenDest'] region so that this function + * can verify that only the proper bytes were altered. + */ + +int wpmDoIt(struct allhandles_t Comms, + char * pBuffer, unsigned int lenBuffer, + char * pDest, unsigned int lenDest, + const char* storageDescription) +{ + char *pCurr; + FILE *commsFile; + DWORD dwRet; + + if (pBuffer > pDest || lenDest > lenBuffer) + { + Trace("WriteProcessMemory::DoIt() test implementation: " + "(pBuffer > pDest || lenDest > lenBuffer)\n"); + return FALSE; + } + + /* set up the storage */ + memset(pBuffer, guardValue, lenBuffer); + memset(pDest, initialValue, lenDest); + + /* tell the parent what RAM to adjust */ + if(!(commsFile = fopen(Comms.valuesFileName, "w"))) + { + Trace("WriteProcessMemory: fopen of '%S' failed (%u). \n", + Comms.valuesFileName, GetLastError()); + return FALSE; + } + if (!fprintf(commsFile, LLFORMAT " " LLFORMAT " '%s'\n", + pDest, lenDest, storageDescription)) + { + Trace("WriteProcessMemory: fprintf to '%S' failed (%u). \n", + Comms.valuesFileName, GetLastError()); + return FALSE; + } + PEDANTIC1(fclose, (commsFile)); + + /* Tell the parent the data is ready for it to adjust */ + PEDANTIC(ResetEvent, (Comms.hEvToHelper)); + PEDANTIC(SetEvent, (Comms.hEvFromHelper)); + + dwRet = WaitForSingleObject(Comms.hEvToHelper, TIMEOUT); /* parent is done */ + if (dwRet != WAIT_OBJECT_0) + { + Trace("helper WaitForSingleObjectTest: WaitForSingleObject " + "failed (%u)\n", GetLastError()); + return FALSE; + } + + /* check the stuff that SHOULD have changed */ + for (pCurr = pDest; pCurr < (pDest + lenDest); pCurr++) + { + if ( *pCurr != nextValue) + { + Trace("When testing '%s': alteration test failed " + "at " LLFORMAT " offset " LLFORMAT " Found '%c' instead of '%c'\n.", + storageDescription, pDest, pCurr - pDest, *pCurr, nextValue); + Trace(" 'Altered' string: '%.*s'\n",lenBuffer, pBuffer); + return FALSE; + } + } + /* check the stuff that should NOT have changed */ + for (pCurr = pBuffer; pCurr < pDest; pCurr++ ) + { + if ( *pCurr != guardValue) + { + Trace("When testing '%s': leading guard zone test failed " + "at " LLFORMAT " offset " LLFORMAT ". Found '%c' instead of '%c'\n.", + storageDescription, pDest, pCurr - pBuffer, *pCurr, guardValue); + Trace(" 'Altered' string: '%.*s'\n",lenBuffer, pBuffer); + return FALSE; + } + } + for (pCurr = pDest + lenDest; pCurr < (pBuffer + lenBuffer); pCurr++ ) + { + if ( *pCurr != guardValue) + { + Trace("When testing '%s': trailing guard zone test failed " + "at " LLFORMAT " offset " LLFORMAT ". Found '%c' instead of '%c'\n.", + storageDescription, pDest + lenDest, pCurr - pBuffer, *pCurr, guardValue); + Trace(" 'Altered' string: '%.*s'\n",lenBuffer, pBuffer); + return FALSE; + } + } + + return TRUE; +} + +int __cdecl main(int argc, char *argv[]) +{ + + BOOL success = TRUE; /* assume success */ + struct allhandles_t Comms = {0,0,0} ; + + /* variables to track storage to alter */ + char *pTarget = NULL; + unsigned int sizeTarget; + + if(0 != (PAL_Initialize(argc, argv))) + { + return FAIL; + } + + /* hook up with the events created by the parent */ + Comms.hEvToHelper = OpenEventW(EVENT_ALL_ACCESS, 0, szcToHelperEvName); + if (!Comms.hEvToHelper) + { + Fail("WriteProcessMemory: OpenEvent of '%S' failed (%u). " + "(the event should already exist!)\n", + szcToHelperEvName, GetLastError()); + } + Comms.hEvFromHelper = OpenEventW(EVENT_ALL_ACCESS, 0, szcFromHelperEvName); + if (!Comms.hEvToHelper) + { + Trace("WriteProcessMemory: OpenEvent of '%S' failed (%u). " + "(the event should already exist!)\n", + szcFromHelperEvName, GetLastError()); + success = FALSE; + goto EXIT; + } + Comms.valuesFileName = argv[1]; + + { + char autoAllocatedOnStack[51]; + + /* Get the parent process to write to the local stack */ + success &= wpmDoIt(Comms, autoAllocatedOnStack, + sizeof(autoAllocatedOnStack), + autoAllocatedOnStack + sizeof(int), + sizeof(autoAllocatedOnStack) - 2 * sizeof(int), + "const size array on stack with int sized guards"); + } + + /* Get the parent process to write to stuff on the heap */ + sizeTarget = 2 * sizeof(int) + 23 ; /* 23 is just a random prime > 16 */ + if (!(pTarget = malloc(sizeTarget))) + { + Trace("WriteProcessMemory helper: unable to allocate '%s'->%d bytes of memory" + "(%u).\n", + argv[3], sizeTarget, GetLastError()); + success = FALSE; + goto EXIT; + + } + success &= wpmDoIt(Comms, pTarget, sizeTarget, + pTarget + sizeof(int), + sizeTarget - 2 * sizeof(int), + "array on heap with int sized guards"); + + /* just to be nice try something 16 - 2 * sizeof(int) bytes long */ + { + char autoAllocatedOnStack[16]; + + /* Get the parent process to write to the local stack */ + success &= wpmDoIt(Comms, autoAllocatedOnStack, + sizeof(autoAllocatedOnStack), + autoAllocatedOnStack + sizeof(int), + sizeof(autoAllocatedOnStack) - 2 * sizeof(int), + "another 16 byte array on stack with int sized guards inside"); + } + + /* NOTE: Don't try 0 bytes long. Win32 WriteProcessMemory claims + * it writes 8 bytes in that case! */ + + /* and 1 byte long... */ + { + char autoAllocatedOnStack[1+ 2 * sizeof(int)]; + + /* Get the parent process to write to the local stack */ + success &= wpmDoIt(Comms, autoAllocatedOnStack, + sizeof(autoAllocatedOnStack), + autoAllocatedOnStack + sizeof(int), + 1, + "no bytes with int sized guards outside on stack"); + } + + +EXIT: + /* Tell the parent that we are done */ + if (!DeleteFile(Comms.valuesFileName)) + { + Trace("helper: DeleteFile failed so parent (test1) is unlikely " + "to exit cleanly\n"); + } + PEDANTIC(ResetEvent, (Comms.hEvToHelper)); + if (!SetEvent(Comms.hEvFromHelper)) + { + Trace("helper: SetEvent failed so parent (test1) is unlikely " + "to exit cleanly\n"); + } + + free(pTarget); + PEDANTIC(CloseHandle, (Comms.hEvToHelper)); + PEDANTIC(CloseHandle, (Comms.hEvFromHelper)); + + if (!success) + { + Fail(""); + } + + PAL_Terminate(); + + return success ? PASS : FAIL; +} diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/test2.c b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/test2.c new file mode 100644 index 0000000000..eda40599ce --- /dev/null +++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/test2.c @@ -0,0 +1,258 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*============================================================= +** +** Source: test2.c +** +** Purpose: Create a child process and some events for communications with it. +** When the child gets back to us with a memory location and a length, +** Call WriteProcessMemory on this location and check to see that it +** writes successfully. Then call ReadProcessMemory to check if the +** contents read are same as those written +** +** +**============================================================*/ + +#define UNICODE + +#include "commonconsts.h" + +#include <palsuite.h> + +#if defined(BIT64) && defined(PLATFORM_UNIX) +#define LLFORMAT "%I64u" +#else +#define LLFORMAT "%u" +#endif + +int __cdecl main(int argc, char *argv[]) +{ + + PROCESS_INFORMATION pi; + STARTUPINFO si; + HANDLE hEvToHelper; + HANDLE hEvFromHelper; + DWORD dwExitCode; + + DWORD dwRet; + char cmdComposeBuf[MAX_PATH]; + PWCHAR uniString; + + if(0 != (PAL_Initialize(argc, argv))) + { + return FAIL; + } + + /* Create the signals we need for cross process communication */ + hEvToHelper = CreateEvent(NULL, TRUE, FALSE, szcToHelperEvName); + if (!hEvToHelper) + { + Fail("WriteProcessMemory: CreateEvent of '%S' failed. " + "GetLastError() returned %d.\n", szcToHelperEvName, + GetLastError()); + } + if (GetLastError() == ERROR_ALREADY_EXISTS) + { + Fail("WriteProcessMemory: CreateEvent of '%S' failed. " + "(already exists!)\n", szcToHelperEvName); + } + hEvFromHelper = CreateEvent(NULL, TRUE, FALSE, szcFromHelperEvName); + if (!hEvToHelper) + { + Fail("WriteProcessMemory: CreateEvent of '%S' failed. " + "GetLastError() returned %d.\n", szcFromHelperEvName, + GetLastError()); + } + if (GetLastError() == ERROR_ALREADY_EXISTS) + { + Fail("WriteProcessMemory: CreateEvent of '%S' failed. " + "(already exists!)\n", szcFromHelperEvName); + } + ResetEvent(hEvFromHelper); + ResetEvent(hEvToHelper); + + if (!sprintf(cmdComposeBuf, "helper %s", commsFileName)) + { + Fail("Could not convert command line\n"); + } + uniString = convert(cmdComposeBuf); + + ZeroMemory( &si, sizeof(si) ); + si.cb = sizeof(si); + ZeroMemory( &pi, sizeof(pi) ); + + /* Create a new process. This is the process that will ask for + * memory munging */ + if(!CreateProcess( NULL, uniString, NULL, NULL, + FALSE, 0, NULL, NULL, &si, &pi)) + { + Trace("ERROR: CreateProcess failed to load executable '%S'. " + "GetLastError() returned %u.\n", + uniString, GetLastError()); + free(uniString); + Fail(""); + } + free(uniString); + + + while(1) + { + FILE *commsFile; + char* pSrcMemory; + char* pDestMemory; + SIZE_T Count; + SIZE_T wpmCount; + char incomingCMDBuffer[MAX_PATH + 1]; + + int err; + HANDLE readProcessHandle; + DWORD readProcessID; + char readProcessBuffer[REGIONSIZE]; // size 1024 + BOOL bResult; + size_t size = 0; + + readProcessID = pi.dwProcessId; + + /* wait until the helper tells us that it has given us + * something to do */ + dwRet = WaitForSingleObject(hEvFromHelper, TIMEOUT); + if (dwRet != WAIT_OBJECT_0) + { + Trace("test1 WaitForSingleObjectTest: WaitForSingleObject " + "failed (%u)\n", GetLastError()); + break; /* no more work incoming */ + } + + /* get the parameters to test WriteProcessMemory with */ + if (!(commsFile = fopen(commsFileName, "r"))) + { + /* no file means there is no more work */ + break; + } + if ( NULL == fgets(incomingCMDBuffer, MAX_PATH, commsFile)) + { + Fail ("unable to read from communication file %s " + "for reasons %u & %u\n", + errno, GetLastError()); + } + PEDANTIC1(fclose,(commsFile)); + sscanf(incomingCMDBuffer, LLFORMAT " " LLFORMAT, &pDestMemory, &Count); + if (argc > 1) + { + Trace("Preparing to write to " LLFORMAT " bytes @ " LLFORMAT "('%s')\n", + Count, pDestMemory, incomingCMDBuffer); + } + + /* compose some data to write to the client process */ + if (!(pSrcMemory = malloc(Count))) + { + Trace("could not dynamically allocate memory to copy from " + "for reasons %u & %u\n", + errno, GetLastError()); + goto doneIteration; + } + memset(pSrcMemory, nextValue, Count); + Trace("Preparing to write to " LLFORMAT " bytes @ " LLFORMAT " ('%s')[%u]\n", + Count, pDestMemory, incomingCMDBuffer, pSrcMemory); + + /* do the work */ + dwRet = WriteProcessMemory(pi.hProcess, + pDestMemory, + pSrcMemory, + Count, + &wpmCount); + + if (!dwRet) + { + Trace("%s: Problem: on a write to "LLFORMAT " bytes @ " LLFORMAT " ('%s')\n", + argv[0], Count, pDestMemory, incomingCMDBuffer); + Trace("test1 WriteProcessMemory returned a (!=0) (GLE=%u)\n", + GetLastError()); + } + if(Count != wpmCount) + { + Trace("%s: Problem: on a write to " LLFORMAT " bytes @ " LLFORMAT " ('%s')\n", + argv[0], Count, pDestMemory, incomingCMDBuffer); + Trace("The number of bytes written should have been " + LLFORMAT ", but was reported as " LLFORMAT " \n", Count, wpmCount); + } + + readProcessHandle = OpenProcess( + PROCESS_VM_READ, + FALSE, + readProcessID); + + if(NULL == readProcessHandle) + { + Fail("\nFailed to call OpenProcess API to retrieve " + "current process handle error code=%u\n", + GetLastError()); + } + + /*zero the memory*/ + memset(readProcessBuffer, 0, size); + + /*retrieve the memory contents*/ + bResult = ReadProcessMemory( + readProcessHandle, /*current process handle*/ + pDestMemory, /*base of memory area*/ + (LPVOID)readProcessBuffer, + Count, /*buffer length in bytes*/ + &size); + + + if( !bResult || (Count != size) ) + { + Trace("\nFailed to call ReadProcessMemory API " + "to retrieve the memory contents, error code=%u; Bresult[%u] Count[" LLFORMAT "], Size[%d]\n", + GetLastError(), bResult, Count, size); + + err = CloseHandle(readProcessHandle); + + if(0 == err) + { + Trace("\nFailed to call CloseHandle API, error code=%u\n", + GetLastError()); + } + dwExitCode = FAIL; + } + + if( !memcmp (pDestMemory, readProcessBuffer, Count ) ) + { + Trace("Difference in memory contents, expected [%s], but received [%s]\n", pDestMemory, readProcessBuffer); + dwExitCode = FAIL; + } + + Trace("ReadProcessBuffer contains [%s]\n", readProcessBuffer); + err = CloseHandle(readProcessHandle); + + free(pSrcMemory); + + doneIteration: + PEDANTIC(ResetEvent, (hEvFromHelper)); + PEDANTIC(SetEvent, (hEvToHelper)); + } + + /* wait for the child process to complete */ + WaitForSingleObject ( pi.hProcess, TIMEOUT ); + /* this may return a failure code on a success path */ + + /* check the exit code from the process */ + if( ! GetExitCodeProcess( pi.hProcess, &dwExitCode ) ) + { + Trace( "GetExitCodeProcess call failed with error code %u\n", + GetLastError() ); + dwExitCode = FAIL; + } + + + PEDANTIC(CloseHandle, (hEvToHelper)); + PEDANTIC(CloseHandle, (hEvFromHelper)); + PEDANTIC(CloseHandle, (pi.hThread)); + PEDANTIC(CloseHandle, (pi.hProcess)); + + PAL_TerminateEx(dwExitCode); + return dwExitCode; +} diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/testinfo.dat new file mode 100644 index 0000000000..58a9935a08 --- /dev/null +++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/testinfo.dat @@ -0,0 +1,18 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. + +Version = 1.0 +Section = Debug +Function = ReadProcessMemory +Name = Check that writing/reading text to/from process memory succeeds. +TYPE = DEFAULT +EXE1 = test2 +EXE2 = helper +Description += Create a child process and attempt to write to its memory += at the places and lengths it specifies via a data file. += the child verifies that all the specified memory was altered += with no overruns. Parent then tries to read memory from child += and does memory compare to ensure it read memory contents += correctly |