Solved

ReadFile function fails

Posted on 2004-09-04
6
753 Views
Last Modified: 2008-01-09
Have a function who´s purpose is to execute other binarys (has not written it myself). It works like a clock exept on one of our customers machines. It´s on a Windows 2000 machine, fully patched english version. The function works  fine until row 155 (if(!ReadFile(hOutputRead, lpBuffer, sizeof(lpBuffer), &nBytesRead, NULL) || !nBytesRead) {). There it dies. Does any one have a clue why this happens? What are the factors that matters in this case. We are a couple of developers that cant find any reason why this happens.  I´ll include the fúnction in question and a DrWatson dump (some what edited for security reasons). Can any one pleas help.

Here is the function:
int execJob2(char *execpath, char *execargs[], char *redstdinpath, char *redstdoutpath, int *exitstat, char *execoutp, int noutp)
{
      /* runs an executable
         if a path is give for redirection of stdout it will be put in that path, if not: stdout will be merged with
         stderr and piped to a variable, if no variable is given: both stdout and stderr will be handled as setup in
         the executable

         execpath = the executable path
         execargs = all arguments, terminated by a NULL string (arg 0 is the name of the executable)
         redstdoutpath = path where to place the stdout output, if NULL it will be piped to same variable as stderr
         redstdinpath = path where to get redirected stdinput
         exitstat = pointer to an integer that is used to pass existatus and errors
         execoutp = pointer to an array to hold the (stdout and) stderr output of the executable, if NULL no redirection of stdout/stderr is done
         noutpt is the size of the execoutp array
         returns 0 = normal execution, *exitstat == exit status of executable
         returns -1 = abnormal execution, *exitstat == 1: no file at path
                      abnormal execution, *exitstat == 2: exec returned, probably no executable at path
                      abnormal execution, *exitstat == 3: pipe failed
                      abnormal execution, *exitstat == 4: redirect of stdout failed
                      abnormal execution, *exitstat == 5: fork failed
      */
      PROCESS_INFORMATION pi;
      STARTUPINFO si;
      HANDLE hOutputReadTmp,hOutputRead,hOutputWrite;
      HANDLE hInputWriteTmp,hInputRead,hInputWrite;
      HANDLE hErrorWrite;
      HANDLE hThread;
      HANDLE hOutputFile = NULL;
      HANDLE hChildProcess = NULL;
      DWORD ThreadId;
      SECURITY_ATTRIBUTES sa;

      CHAR lpBuffer[256];
      DWORD nBytesRead = 0;
      DWORD nCharsWritten;
      DWORD nBytesWrote;
      char command[4096] = "\0";
      int i=1, stat, exitCode;
      
      FILE *file;
      
      strcpy(command, "\"");
      strcat(command, execpath);
      strcat(command, "\"");  
      /* Get the arguments */
      if(execargs!=NULL) {
            while(execargs[i]!=NULL) {
                  strcat(command, " ");
                  strcat(command, "\"");
                  strcat(command, execargs[i]);
                  strcat(command, "\"");  
                  i++;
            }
      }

      /* Set up the security attributes struct. */
      sa.nLength= sizeof(SECURITY_ATTRIBUTES);
      sa.lpSecurityDescriptor = NULL;
      sa.bInheritHandle = TRUE;

      /* Create the child output pipe. */
      CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0);

      /* Create a duplicate of the output write handle for the std error write handle.
         This is necessary in case the child application closes one of its std output handles. */
      DuplicateHandle(GetCurrentProcess(),hOutputWrite,
                      GetCurrentProcess(),&hErrorWrite,0,
                      TRUE,DUPLICATE_SAME_ACCESS);

      /* Create the child input pipe. */
      CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0);

      /* Create new output read handle and the input write handles.
         Set the Properties to FALSE. Otherwise, the child inherits the properties and,
         as a result, non-closeable handles to the pipes are created. */
         DuplicateHandle(GetCurrentProcess(),hOutputReadTmp,
                         GetCurrentProcess(),
                         &hOutputRead,            /* Address of new handle. */
                         0,FALSE,            /* Make it uninheritable. */
                         DUPLICATE_SAME_ACCESS);

      DuplicateHandle(GetCurrentProcess(),hInputWriteTmp,
                      GetCurrentProcess(),
                      &hInputWrite,            /* Address of new handle. */
                      0,FALSE,                  /* Make it uninheritable. */
                      DUPLICATE_SAME_ACCESS);

      /* Close inheritable copies of the handles you do not want to be inherited. */
      CloseHandle(hOutputReadTmp);
      CloseHandle(hInputWriteTmp);

      /* Set up the start up info struct. */
      ZeroMemory(&si,sizeof(STARTUPINFO));
      si.cb = sizeof(STARTUPINFO);
      si.dwFlags = STARTF_USESTDHANDLES;
      si.wShowWindow = SW_HIDE | STARTF_USESHOWWINDOW;
      si.hStdOutput = hOutputWrite;
      si.hStdInput  = hInputRead;
      si.hStdError  = NULL;//hErrorWrite;      /* TODO: handle stderr */

      /* Launch the process that you want to redirect */
      if(!CreateProcess(NULL,
                        command,
                        NULL,
                        NULL,
                        TRUE,
                        0,
                        NULL,
                        NULL,
                        &si,
                        &pi)) {
            *exitstat = 2; /* probably no executable at path */
            return -1;
      }

      /* Set global child process handle to cause threads to exit. */
      hChildProcess = pi.hProcess;

      /* Close any unnecessary handles. */
      CloseHandle(pi.hThread);

      /* Close pipe handles (do not continue to modify the parent).
            You need to make sure that no handles to the write end of the output pipe are maintained in this process or else
            the pipe will not close when the child process exits and the ReadFile will hang. */
      CloseHandle(hOutputWrite);
      CloseHandle(hInputRead);
      CloseHandle(hErrorWrite);


      /* Launch the thread that gets the input and sends it to the child. */
      hThread = CreateThread(NULL,0,GetAndSendInputThread,
                             (LPVOID)hInputWrite,0,&ThreadId);

      if(redstdinpath!=NULL) {      
            /* Open input file. */
            redstdin = TRUE;
            hInputFile = CreateFile(redstdinpath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
            if(hInputFile==INVALID_HANDLE_VALUE) {
                  *exitstat = 1;      /* no file at path */
                  return -1;
            }
      }

      if(redstdoutpath!=NULL) {      
            /* Open output file. */
            hOutputFile = CreateFile(redstdoutpath, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL);
            if(hOutputFile==INVALID_HANDLE_VALUE) {
                  *exitstat = 4;      /* couldnt open redirect file */
                  return -1;
            }
      }      

      /* Read the child's output. Exits when child exits or pipe breaks. */
      while(TRUE) {
            if(!ReadFile(hOutputRead, lpBuffer, sizeof(lpBuffer), &nBytesRead, NULL) || !nBytesRead) {
                  if (GetLastError() == ERROR_BROKEN_PIPE)
                        break; // pipe done - normal exit path.
            }
            

            
            /* write (stdout and) stderr to execoutp */
            if(execoutp!=NULL) {
                  if(redstdoutpath==NULL) {
                        if(nBytesRead>noutp)      strncat(execoutp, lpBuffer, noutp);
                        else                  strncat(execoutp, lpBuffer, nBytesRead);            
                  }
                  //if(nBytesRead2>noutp)      strncat(execoutp, lpBuffer2, noutp);
                  //else                  strncat(execoutp, lpBuffer2, nBytesRead2);
            }
            
            /* write stdout to file */
            if(redstdoutpath!=NULL) {
                  WriteFile(hOutputFile, lpBuffer, nBytesRead, &nCharsWritten, NULL);
                                    
            }
            
      }
     
      /* Redirection is complete */

      /* Tell the thread to exit and wait for thread to die. */
      bRunThread = FALSE;

      WaitForSingleObject(hThread,INFINITE);

      if(GetExitCodeProcess(pi.hProcess, &exitCode))
            *exitstat = exitCode;

      CloseHandle(hInputFile);
      CloseHandle(hOutputFile);
      CloseHandle(hOutputRead);
      CloseHandle(hInputWrite);
      CloseHandle(hChildProcess);//FJ
      CloseHandle(hThread);//FJ
      
      return 0;
}


-------------------------------------

And the dump:

crosoft (R) Windows 2000 (TM) Version 5.00 DrWtsn32
Copyright (C) 1985-1999 Microsoft Corp. All rights reserved.



Application exception occurred:
        App:  (pid=1800)
        When: 9/1/2004 @ 14:57:12.807
        Exception number: c0000005 (access violation)

*----> System Information <----*
        Computer Name:  
        User Name: SYSTEM
        Number of Processors: 1
        Processor Type: x86 Family 6 Model 8 Stepping 6
        Windows 2000 Version: 5.0
        Current Build: 2195
        Service Pack: 4
        Current Type: Uniprocessor Free
        Registered Organization: test
        Registered Owner: test


 
State Dump for Thread Id 0x830

eax=00000700 ebx=00000000 ecx=7ffdf000 edx=00000000 esi=00000000 edi=00000388
eip=77f8c55d esp=0012c030 ebp=0012c0a0 iopl=0         nv up ei pl zr na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000246


function: ZwReadFile
        77f8c552 b8a1000000       mov     eax,0xa1
        77f8c557 8d542404         lea     edx,[esp+0x4]          ss:00945f17=????????
        77f8c55b cd2e             int     2e
        77f8c55d c22400           ret     0x24
        77f8c560 55               push    ebp
        77f8c561 8bec             mov     ebp,esp
        77f8c563 8b550c           mov     edx,[ebp+0xc]          ss:00945f86=????????
        77f8c566 8b4a04           mov     ecx,[edx+0x4]          ds:00819ee6=????????
        77f8c569 8b02             mov     eax,[edx]              ds:00000000=????????
        77f8c56b 8901             mov     [ecx],eax              ds:7ffdf000=00010000
        77f8c56d 894804           mov     [eax+0x4],ecx          ds:0081a5e6=????????
        77f8c570 8b4d08           mov     ecx,[ebp+0x8]          ss:00945f86=????????
        77f8c573 3909             cmp     [ecx],ecx              ds:7ffdf000=00010000
        77f8c575 0f843e52ffff     je      RtlAppendAsciizToString+0x80 (77f817b9)
        77f8c57b 3bc1             cmp     eax,ecx

*----> Stack Back Trace <----*

FramePtr ReturnAd Param#1  Param#2  Param#3  Param#4  Function Name
0012C0A0 00403285 00000388 0012C130 00000100 0012D264 ntdll!ZwReadFile
0012D268 00402EFF 0012E320 0012DEB0 00000000 00000000 !<nosymbols>
0012D28C 0042AAFF 0012E320 0012DEB0 00000000 0012F34C !<nosymbols>
0012FD60 00429A83 005B7500 005B7270 00000000 0048ABE0 !<nosymbols>
0012FE90 004210B1 005B7500 0048ABE0 0045D7E0 00000063 !<nosymbols>
0012FF80 0044C648 00000003 005B2910 005B2998 00000000 !<nosymbols>
0012FFC0 7C4E87F5 00000000 77F89964 7FFDF000 00000000 !<nosymbols>
0012FFF0 00000000 0044C583 00000000 000000C8 00000100 kernel32!DosDateTimeToFileTime

*----> Raw Stack Dump <----*
0012c030  0d 66 4e 7c 88 03 00 00 - 00 00 00 00 00 00 00 00  .fN|............
0012c040  00 00 00 00 78 c0 12 00 - 30 c1 12 00 00 01 00 00  ....x...0.......
0012c050  00 00 00 00 00 00 00 00 - 44 d2 12 00 90 fe 12 00  ........D.......
0012c060  00 f0 fd 7f 01 01 01 00 - b0 ff 12 00 b4 f0 4f 7c  ..............O|
0012c070  f0 34 4f 7c ff ff ff ff - 9c c0 12 00 de 95 4e 7c  .4O|..........N|
0012c080  ff ff ff ff 00 00 00 00 - 58 c0 12 00 30 c1 12 00  ........X...0...
0012c090  b0 ff 12 00 b4 f0 4f 7c - 40 66 4e 7c ff ff ff ff  ......O|@fN|....
0012c0a0  68 d2 12 00 85 32 40 00 - 88 03 00 00 30 c1 12 00  h....2@.....0...
0012c0b0  00 01 00 00 64 d2 12 00 - 00 00 00 00 fc fd 12 00  ....d...........
0012c0c0  84 08 00 00 00 00 00 00 - 00 00 00 00 a0 03 00 00  ................
0012c0d0  90 03 00 00 44 00 00 00 - 00 00 00 00 00 00 00 00  ....D...........
0012c0e0  00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00  ................
0012c0f0  00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00  ................
0012c100  00 01 00 00 01 00 00 00 - 00 00 00 00 94 03 00 00  ................
0012c110  a0 03 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00  ................
0012c120  84 03 00 00 00 00 00 00 - 88 03 00 00 05 00 00 00  ................
0012c130  00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00  ................
0012c140  00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00  ................
0012c150  00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00  ................
0012c160  00 00 00 00 00 00 00 00 - 00 00 00 00 00 00 00 00  ................

State Dump for Thread Id 0x884

eax=00000000 ebx=00000384 ecx=80431693 edx=00000001 esi=00000000 edi=00000000
eip=004033f7 esp=006bfea8 ebp=006bffb4 iopl=0         nv up ei pl zr na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000246


function: <nosymbols>
        004033d9 6a00             push    0x0
        004033db 8d4dfc           lea     ecx,[ebp+0xfc]         ss:00ed9e9a=????????
        004033de 51               push    ecx
        004033df 6a01             push    0x1
        004033e1 8d95fcfeffff     lea     edx,[ebp+0xfffffefc]   ss:006bfeb0=8043fdac
        004033e7 52               push    edx
        004033e8 a13ce44700       mov     eax,[0047e43c]         ds:0047e43c=00000000
        004033ed 50               push    eax
        004033ee ff1524a04500     call    dword ptr [0045a024]   ds:0045a024=7c5020ab
        004033f4 8b4dfc           mov     ecx,[ebp+0xfc]         ss:00ed9e9a=????????
FAULT ->004033f7 c6840dfcfeffff00                                      ss:8043158f=??
                                  mov     byte ptr [ebp+ecx+0xfffffefc],0x0
        004033ff 6a00             push    0x0
        00403401 8d95f4feffff     lea     edx,[ebp+0xfffffef4]   ss:006bfea8=f44ecbb8
        00403407 52               push    edx
        00403408 8b45fc           mov     eax,[ebp+0xfc]         ss:00ed9e9a=????????
        0040340b 50               push    eax
        0040340c 8d8dfcfeffff     lea     ecx,[ebp+0xfffffefc]   ss:006bfeb0=8043fdac
        00403412 51               push    ecx
        00403413 8b95f8feffff     mov     edx,[ebp+0xfffffef8]   ss:006bfeac=00000384
        00403419 52               push    edx
        0040341a ff1588a14500     call    dword ptr [0045a188]   ds:0045a188=7c4fc24e
        00403420 85c0             test    eax,eax

*----> Stack Back Trace <----*

FramePtr ReturnAd Param#1  Param#2  Param#3  Param#4  Function Name
006BFFB4 7C4E987C 00000384 00000000 00000000 00000384 !<nosymbols>
006BFFEC 00000000 00000000 00000000 00000000 00000000 kernel32!SetThreadExecutionState


0
Comment
Question by:sa9824
  • 2
  • 2
  • 2
6 Comments
 
LVL 3

Expert Comment

by:teratoma
ID: 11982137
This looks like stack corruption within ReadFile.  Note the return address of 0 in a call to DosDateTimeToFileTime.  Could you summarize your findings so far?  I haven't analyzed a dump in this format before.  I'm also not familiar with the Windows threading model.  Are higher addresses at the top or bottom of the stack?  Could DosDateTimeToFileTime be causing the error?  It would make sense that a DOS-related function wouldn't work perfectly under Win2k.
0
 

Author Comment

by:sa9824
ID: 11983439
Hi again!

One of our findings is that if we set the CreateProcess parameter InheritHandles (param 5) to false every thing works fine but then we can't read the childs output. About the dump I cant really answer you question on hiw to read it, it's beone my skills so far. I included it for you experts, if it would be of any help.
0
 
LVL 22

Expert Comment

by:grg99
ID: 11983789
It looks like the readfile() call wrote over the stack.

Try declaring lpbuffer[1024] as a static global array, then use sizeof(lpbuffer)/2 as the read size and see if it works any better.

0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 
LVL 3

Assisted Solution

by:teratoma
teratoma earned 100 total points
ID: 11986382
I think the file being read is also being written to by another thread, causing a buffer overrun and corrupting the stack.  Apparently ReadFile is not thread safe.  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base/readfile.asp talks about some things that can go wrong depending on how the file was created versus how it's read.  
0
 
LVL 22

Accepted Solution

by:
grg99 earned 400 total points
ID: 11989175
>I think the file being read is also being written to by another thread, causing a buffer overrun and corrupting the stack.  


Doesnt sound reasonable.  Writing to a file or pipe and reading from the other end is a standard operation, done by thousands of programs, thousands of times a second all over the world.  \


> Apparently ReadFile is not thread safe.

I don't see that said in the URL you pointed to.  It says some things about don't read or delete the inpyut buffer before ReadFile completes.  But you're not doing that.
 
I would for starters move the buffer out into global space, maybe put some buffers before and after it too to see if readfile is spilling out over them.  It looks impossible, sice you have a hard-coded "sizeof lpbuf" forthe read size, but if that parameter list is getting overwritten somehow, then the stack could get clobbered.

BTW do you have any other threads running that might be corrupting memory?  Your code looks reasonable safe, maybe its  something else?

0
 

Author Comment

by:sa9824
ID: 11991814
Hi guys!

We managed to solve it, i appears that we are trying to read from a pipe berfore any "safe" pipes has been established. I'll split the points between you guys for your input/help!  Thanx!!!
0

Featured Post

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

Have you thought about creating an iPhone application (app), but didn't even know where to get started? Here's how: ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Important pre-programming comments: I’ve never tri…
Preface I don't like visual development tools that are supposed to write a program for me. Even if it is Xcode and I can use Interface Builder. Yes, it is a perfect tool and has helped me a lot, mainly, in the beginning, when my programs were small…
The goal of this video is to provide viewers with basic examples to understand and use pointers in the C programming language.
The goal of this video is to provide viewers with basic examples to understand and use switch statements in the C programming language.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now