PRB: Secundario hereda controles imprevistos durante la llamada a CreateProcess

Síntomas

Cuando se crea un proceso secundario mediante la función CreateProcess llamar en un entorno multiproceso, el niño puede heredar controladores que no se han pensado para heredarse.

Causa

Este comportamiento puede producirse si dos subprocesos simultáneamente crean procesos secundarios y redirección los controladores estándar a través de canalizaciones. En este escenario, hay una condición de carrera durante la creación de las canalizaciones y los procesos, en el que es posible que un elemento secundario herede destinados al otro niño de identificadores de archivo. Un subproceso crea las canalizaciones y mientras ese subproceso está en el proceso de creación del proceso, el otro subproceso también está creando un proceso secundario. Todos los identificadores que son heredables en la solicitud durante la llamada de CreateProcess se repiten en el proceso secundario.

Solución

Para evitar este problema, incluya el código de creación de secundarios en una sección crítica. Esto evita que cualquier herencia accidental. Para que este método funcione correctamente, cree las tuberías como estableciendo el descriptor de seguridad NULL. A continuación, establezca los extremos de la canalización que deseas que el hijo pueda heredar como heredables utilizando la llamada a la función SetHandleInformation , como se muestra en el siguiente código de ejemplo:

CRITICAL_SECTION    cs;HANDLE              hReadIn, hWriteIn;
HANDLE hReadOut, hWriteOut;
HANDLE hReadErr, hWriteErr;

InitializeCriticalSection(&cs);

EnterCriticalSection(&cs);

if ( !CreatePipe(&hReadIn, &hWriteIn, NULL, 0) )
{
// an error occurred
}

if ( !CreatePipe(&hReadOut, &hWriteOut, NULL, 0) )
{
// an error occurred
}

if ( !CreatePipe(&hReadErr, &hWriteErr, NULL, 0) )
{
// an error occurred
}

if ( !SetHandleInformation(hReadIn, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) )
{
// an error occurred
}

if ( !SetHandleInformation(hWriteOut, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) )
{
// an error occurred
}

if ( !SetHandleInformation(hWriteErr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) )
{
// an error occurred
}

STARTUP_INFO si;
PROCESS_INFORMATION pi;

si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = hReadIn;
si.hStdOutput = hWriteOut;
si.hStdError = hWriteErr;

if ( !CreateProcess( "child.exe",
NULL,
NULL, NULL,
TRUE,
NORMAL_PRIORITY_CLASS,
lpEnvironment,
&si, &pi) )
{
// an error occurred
}

CloseHandle(hReadIn);
CloseHandle(hWriteOut);
CloseHandle(hWriteErr);

LeaveCriticalSection(&cs);

Tenga en cuenta que la solución anterior no viene sin costos. La creación de secciones críticas de código a veces es complicada y tiene un precio de degradación del performance. Hay otra solución para este problema y requiere la creación de una aplicación intermedia para iniciar al secundario. Sin embargo, esta solución también tiene su lado negativo. El principal inconveniente de este método es que el primario pierde básicamente la facilidad con la que obtiene el identificador de proceso. del niño Si el padre tiene el identificador de proceso, el proceso intermedio debe pasarle detrás de alguna manera.

Mediante este método de aplicación intermedia, es evitar cualquier herencia accidental si dependía de Windows para hacer el trabajo por usted. Los identificadores heredados accidentalmente en el proceso intermedio definitivamente no se duplicarán al niño. Esto queda garantizado si se especifica FALSE para el parámetro bInheritHandles en la llamada a CreateProcess en la aplicación intermedia. Todavía se duplicarán los identificadores de canalización porque Windows siempre duplica los identificadores estándar, incluso cuando bInheritHandles está establecido en FALSE.

Aplicación padre

HANDLE              hReadIn, hWriteIn;HANDLE              hReadOut, hWriteOut;
HANDLE hReadErr, hWriteErr;

if ( !CreatePipe(&hReadIn, &hWriteIn, NULL, 0) )
{
// an error occurred
}

if ( !CreatePipe(&hReadOut, &hWriteOut, NULL, 0) )
{
// an error occurred
}

if ( !CreatePipe(&hReadErr, &hWriteErr, NULL, 0) )
{
// an error occurred
}

STARTUP_INFO si;
PROCESS_INFORMATION pi;

si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = hReadIn;
si.hStdOutput = hWriteOut;
si.hStdError = hWriteErr;

if ( !CreateProcess( "Intermediate.exe",
NULL,
NULL, NULL,
TRUE,
NORMAL_PRIORITY_CLASS,
lpEnvironment,
&si, &pi) )
{
// an error occurred
}

CloseHandle(hReadIn);
CloseHandle(hWriteOut);
CloseHandle(hWriteErr);


Aplicación intermedia

STARTUP_INFO        si;PROCESS_INFORMATION pi;

si.cb = sizeof(si);

if ( !CreateProcess( "child.exe",
NULL,
NULL, NULL,
FALSE,
NORMAL_PRIORITY_CLASS,
lpEnvironment,
&si, &pi) )
{
// an error occurred
}

Propiedades

Id. de artículo: 315939 - Última revisión: 17 ene. 2017 - Revisión: 1

Comentarios