예제 #1
0
파일: test3.c 프로젝트: ArildF/masters
int __cdecl main(int argc, char *argv[])
{

    PROCESS_INFORMATION pi;
    STARTUPINFO si;
    HANDLE hEvToHelper;
    HANDLE hEvFromHelper;
    DWORD dwExitCode;
    

    DWORD dwRet;
    BOOL success = TRUE;  /* assume success */
    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 %u.\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 %u.\n", szcFromHelperEvName, 
             GetLastError());
    }
    if (GetLastError() == ERROR_ALREADY_EXISTS) 
    {
        Fail("WriteProcessMemory: CreateEvent of '%S' failed. "
             "(already exists!)\n", szcFromHelperEvName);
    }
    
    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;
        int Count;
        DWORD wpmCount;
        DWORD dwExpectedErrorCode;

        char incomingCMDBuffer[MAX_PATH + 1];

        /* 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))
        {
            Trace ("unable to read from communication file %s "
                  "for reasons %u & %u\n",
                  errno, GetLastError());
            success = FALSE;
            PEDANTIC1(fclose,(commsFile));
            /* it's not worth continuing this trial */
            goto doneIteration;
        }
        PEDANTIC1(fclose,(commsFile));
        sscanf(incomingCMDBuffer, "%u %u %u", 
               &pDestMemory, &Count, &dwExpectedErrorCode);
        if (argc > 1) 
        {
            Trace("Preparing to write to %u bytes @ %u ('%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());
            success = FALSE;
            goto doneIteration;
        }
        memset(pSrcMemory, nextValue, Count);

        /* do the work */
        dwRet = WriteProcessMemory(pi.hProcess, 
                                 pDestMemory,
                                 pSrcMemory,
                                 Count,
                                 &wpmCount);
            
        if(dwRet != 0)
        {
            Trace("ERROR: Situation: '%s', return code: %u, bytes 'written': %u\n",
                  incomingCMDBuffer, dwRet, wpmCount);
            Trace("ERROR: WriteProcessMemory did not fail as it should, as "
                  "it attempted to write to a range of memory which was "
                  "not completely accessible.\n");
            success = FALSE;
        }
            
        if(GetLastError() != dwExpectedErrorCode)
        {
            Trace("ERROR: GetLastError() should have returned "
                 "%u , but instead it returned %u.\n",
                 dwExpectedErrorCode, GetLastError());
            success = FALSE;
        }
        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;
    }
    if(!success)
    {
        dwExitCode = FAIL;
    }

    PEDANTIC(CloseHandle, (hEvToHelper));
    PEDANTIC(CloseHandle, (hEvFromHelper));
    PEDANTIC(CloseHandle, (pi.hThread));
    PEDANTIC(CloseHandle, (pi.hProcess));

    PAL_Terminate();
    return dwExitCode;
}
예제 #2
0
파일: test2.c 프로젝트: l1183479157/coreclr
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;
}
예제 #3
0
파일: helper.cpp 프로젝트: A-And/coreclr
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 = (char*)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;
}
예제 #4
0
파일: helper.cpp 프로젝트: A-And/coreclr
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, "%u %u '%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 %u offset %u. 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 %u offset %u. 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 %u offset %u. Found '%c' instead of '%c'\n.",
                  storageDescription, pDest + lenDest, pCurr - pBuffer, *pCurr, guardValue);
            Trace(" 'Altered' string: '%.*s'\n",lenBuffer, pBuffer);
            return FALSE;
        }
    }

    return TRUE;
}
예제 #5
0
파일: helper.cpp 프로젝트: A-And/coreclr
int __cdecl main(int argc, char *argv[])
{
     
    BOOL  success = TRUE;  /* assume success */
    DWORD dwRet;
    DWORD dwProcessId;
    char szEventName[MAX_LONGPATH];
    PWCHAR uniString;

    if(0 != (PAL_Initialize(argc, argv)))
    {
        return FAIL;
    }

    /* Open the event to let test thread tell us to get started. */
    uniString = convert(szcHelperProcessStartEvName);
    hProcessStartEvent = OpenEventW(EVENT_ALL_ACCESS, 0, uniString);
    free(uniString);
    if (!hProcessStartEvent) 
    {
        Fail("helper.main: OpenEvent of '%S' failed (%u). "
             "(the event should already exist!)\n", 
             szcHelperProcessStartEvName, GetLastError());
    }

    /* Wait for signal from test thread. */
    dwRet = WaitForSingleObject(hProcessStartEvent, TIMEOUT);
    if (dwRet != WAIT_OBJECT_0)
    {
        Fail("helper.main: WaitForSingleObject '%s' failed\n"
                "LastError:(%u)\n", szcHelperProcessStartEvName, GetLastError());
    }

    dwProcessId = GetCurrentProcessId();
    
    if ( 0 >= dwProcessId ) 
    {
        Fail ("helper.main: %s has invalid pid %d\n", argv[0], dwProcessId );
    }

    /* Open the event to tell test thread we are ready. */
    if (sprintf_s(szEventName, MAX_LONGPATH-1, "%s%d", szcHelperProcessReadyEvName, dwProcessId) < 0)
    {
        Fail ("helper.main: Insufficient event name string length for pid=%d\n", dwProcessId);
    }

    uniString = convert(szEventName);

    hProcessReadyEvent = OpenEventW(EVENT_ALL_ACCESS, 0, uniString);
    free(uniString);
    if (!hProcessReadyEvent) 
    {
        Fail("helper.main: OpenEvent of '%s' failed (%u). "
             "(the event should already exist!)\n", 
             szEventName, GetLastError());
    }

    /* Open the event to let test thread tell us to exit. */
    if (sprintf_s(szEventName, MAX_LONGPATH-1, "%s%d", szcHelperProcessFinishEvName, dwProcessId) < 0)
    {
        Fail ("helper.main: Insufficient event name string length for pid=%d\n", dwProcessId);
    }

    uniString = convert(szEventName);

    hProcessFinishEvent = OpenEventW(EVENT_ALL_ACCESS, 0, uniString);
    free(uniString);
    if (!hProcessFinishEvent) 
    {
        Fail("helper.main: OpenEvent of '%s' failed LastError:(%u).\n",
             szEventName, GetLastError());
    }

    /* Tell the test thread we are ready. */
    if (!SetEvent(hProcessReadyEvent))
    {
        Fail("helper.main: SetEvent '%s' failed LastError:(%u)\n",
            hProcessReadyEvent, GetLastError());
    }

    /* Wait for signal from test thread before exit. */
    dwRet = WaitForSingleObject(hProcessFinishEvent, TIMEOUT);
    if (WAIT_OBJECT_0 != dwRet)
    {
        Fail("helper.main: WaitForSingleObject '%s' failed pid=%d\n"
            "LastError:(%u)\n", 
            szcHelperProcessFinishEvName, dwProcessId, GetLastError());
    }

    PEDANTIC(CloseHandle, (hProcessStartEvent));
    PEDANTIC(CloseHandle, (hProcessReadyEvent));
    PEDANTIC(CloseHandle, (hProcessFinishEvent));

    PAL_Terminate();

    return success ? PASS : FAIL;
}