PRB: Zdědí podřízená nezamýšleným úchyty během volání funkce CreateProcess

Příznaky

Při vytváření podřízený proces pomocí funkce CreateProcess volání v prostředí s více podprocesy, podřízené může dědit úchyty, které nebyly určeny k být zděděna.

Příčina

Toto chování může dojít, pokud dvě vlákna současně vytvořit podřízené procesy a přesměrovat úchyty STD prostřednictvím potrubí. V tomto scénáři existuje spor při vytváření kanály a procesů, ve kterých je možné pro jednu podřízenou dědit popisovače souborů, které jsou určeny pro jiné dítě. Jeden podproces vytvoří potrubí a toto vlákno je při procesu vytváření, ostatní podproces také vytváření podřízený proces. Všechny popisovače, které jsou v aplikaci během volání funkce CreateProcess dědičná jsou duplikovány napříč na podřízený proces.

Řešení

Chcete-li tento problém vyřešit, uveďte kód pro vytvoření podřízené v kritické sekce. Tím se zabrání jakékoli náhodným dědičnosti. Pro tuto metodu pracovat správně, vytvořte kanály jako noninheritable nastavením popisovač zabezpečení na hodnotu NULL. Potom nastavte konce trubky, která má podřízený dědit jako dědičná pomocí volání SetHandleInformation funkce, jak je ukázáno v následujícím ukázkovém kódu:

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);

Poznámka: předchozím řešení se nepochází bez nákladů. Vytvoření kritické části kódu je někdy komplikované a pochází za cenu ke zhoršení výkonu. Existuje jiné řešení tohoto problému a vyžaduje vytvoření zprostředkující aplikace spustit podřízené. Toto řešení má však také jeho nevýhodou. Hlavní nevýhodou této metody je nadřazený v podstatě ztratí jednoduchost, s jakou získá ID procesu dítěte Pokud nadřazený potřebuje ID procesu, pomocného procesu musí předat jej zpět nějakým způsobem.

Pomocí této metody aplikace zabránit jakékoli náhodným dědičnosti pomocí systému Windows pro práci pro vás. Všechny omylem zděděné popisovače zprostředkující procesu nebude jednoznačně duplikuje u na dítě. Tím je zaručeno, pokud zadáte hodnotu FALSE pro parametr bInheritHandles ve volání funkce CreateProcess zprostředkující aplikace. Obslužné rutiny budou duplikovány stále, protože systém Windows bude vždy duplicitní úchyty STD, i když bInheritHandles je nastavena na FALSE.

Nadřazenou aplikaci

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);


Aplikace

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
}

Vlastnosti

ID článku: 315939 - Poslední kontrola: 20. 1. 2017 - Revize: 1

Váš názor