4
votes

I'm trying to pass a mutex handle, to a child process trough command line, or any other way.

How can I do that? How do I acess the mutex from the child?

This is how I'm creating the child process:

HANDLE ghMutex;

     if( !CreateProcess( _T("C:\\Users\\Kumppler\\Documents\\Visual Studio 2010\\Projects\\teste3\\Debug\\teste3.exe"),   // No module name (use command line)
                aux2,                              // Command line
                NULL,                              // Process handle not inheritable
                NULL,                              // Thread handle not inheritable
                TRUE,                              // Set handle inheritance to TRUE
                STARTF_USESTDHANDLES,              // inherit the standard input, standard output, and standard error handles
                NULL,                              // Use parent's environment block
                NULL,                              // Use parent's starting directory 
                &si[j],                            // Pointer to STARTUPINFO structure
                &pi[j] )                           // Pointer to PROCESS_INFORMATION structure
            )                     

EDIT:

I need to use the mutex for more than one child process, is it ok?

So here is what I'm doing right now:

HANDLE ghMutex;
int mutex;
char mutexstring[7];

mutex=(int)ghMutex;
itoa(mutexValue,mutexString,10);

I'll pass the mutexString trough command line, and then convert it back at child process:

mutexValue=atoi(argv[2]);

Mutex=(HANDLE)mutexValue;

My question, is it okay to do the (HANDLE) casting??

2

2 Answers

6
votes

Two options:

  1. You can use named objects. Process A creates the Mutex with a name and then spawns Process B. Process B then calls OpenMutex or CreateMutex with the same name, and it will get a handle to the same mutex.

    Drawbacks are in name selection. If you have a name collision, you can get unpredictable results. An attacker could create a mutex with the same name and create a denial of service situation. One way to deal with this is to generate the name randomly. For example, Process A could generate a GUID for the name, and then pass that GUID (as a string) on the command line to Process B.

  2. You can use inheritance. Child processes can inherit many types of handles from the parent process, including mutex handles. Set the bInheritHandles parameters in the CreateProcess command (which your sample is already doing), and pass the value of the handle (as a string) on the command line to the child process. The child process can then convert the command line string back to a value and simply start using it. The value is the same in both processes.

This technique doesn't have the same drawbacks as the named object technique.

A working example of inheritance (error checking elided):

#include <cstddef>
#include <iostream>
#include <string>
#include <sstream>
#include <windows.h>

void DoParentWork() {
  std::wcout << L"Parent:  Creating an inheritable event..." << std::endl;
  SECURITY_ATTRIBUTES security = {
    sizeof(security), nullptr, /* bInheritHandle = */ TRUE
  };
  HANDLE hEvent = ::CreateEventW(&security, /* bManualReset = */ TRUE,
                                 /* bInitialState = */ FALSE, nullptr);

  std::wstringstream ssCommand;
  ssCommand << L"foo.exe " << reinterpret_cast<std::size_t>(hEvent);
  std::wstring strCmd = ssCommand.str();;

  std::wcout << L"Parent:  Starting child process..." << std::endl;
  STARTUPINFO start_info = {sizeof(start_info)};
  PROCESS_INFORMATION proc_info = {0};
  ::CreateProcessW(L"foo.exe", &strCmd[0], nullptr, nullptr,
                   /* bInheritHandles = */ TRUE, 0, nullptr, nullptr,
                   &start_info, &proc_info);
  ::CloseHandle(proc_info.hThread);
  ::CloseHandle(proc_info.hProcess);

  std::wcout << L"Parent:  Waiting for the child to signal the event."
             << std::endl;
  if (::WaitForSingleObject(hEvent, 10*1000) == WAIT_OBJECT_0) {
    std::wcout << L"Parent:  The event was signaled." << std::endl;
  } else {
    std::wcout << L"Parent:  Timed out waiting for the event."
               << std::endl;
  }
  ::CloseHandle(hEvent);
}

void DoChildWork(const char *pszEvent) {
  std::stringstream ss(pszEvent);
  UINT_PTR iEvent;
  ss >> iEvent;
  HANDLE hEvent = reinterpret_cast<HANDLE>(iEvent);
  std::cout << "Child:  Event handle "
            << reinterpret_cast<std::size_t>(hEvent) << std::endl;
  ::Sleep(2000);
  std::cout << "Child:  Signalling the event." << std::endl;
  ::SetEvent(hEvent);
}

int main(int cArgs, char *ppszArgs[]) {
  if (cArgs > 1) DoChildWork(ppszArgs[1]);
  else DoParentWork();
  return 0;
}
1
votes

Either create the mutex before creating the child process and make it inheritable (set bInheritHandle to TRUE in the lpMutexAttributes parameter for CreateMutex). This way you can pass the handle in the command line.

Or use DuplicateHandle and pass the handle via some other mechanism (e.g. use a pipe as STDIN for the child process).