Geoff Chappell, Software Analyst
NTSTATUS RtlSetProcessIsCritical ( BOOLEAN bNew, BOOLEAN *pbOld, BOOLEAN bNeedScb);
The bNew argument is the desired new setting for whether the current process is critical.
The pbOld argument provides the address of a variable that is to receive the old setting. This argument can be NULL to mean that the old setting is not wanted.
The bNeedScb argument specifies whether to require that system critical breaks be already enabled for the current process.
If the bNeedScb argument is non-zero but system critical breaks are not enabled, then the function fails (returning STATUS_UNSUCCESSFUL).
If the pbOld argument is not NULL, the function asks whether the current process is critical. The answer is stored at the address given by pbOld. If the query fails, the answer defaults to false, i.e., that the process is not critical.
The function then sets whether the current process is critical, according to whether the bNew argument is non-zero. Success or failure becomes the result of the function.
System critical breaks are deemed enabled if the process’s own NtGlobalFlag (as a member of the PEB) has the 0x00100000 bit set. The GFLAGS.EXE utility and the !gflag debugger command represent this bit as “scb” and describe its action as “Enable system critical breaks”.
The status of a process as being critical is set and queried through the kernel as process information, i.e., through ZwSetInformationProcess and ZwQueryInformationProcess. The class of process information is ProcessBreakOnTermination (0x1D), operating on a dword-sized boolean. The kernel explicitly requires debug privilege when setting whether a process is critical. The setting itself is the BreakOnTermination flag in the process’s EPROCESS.
The point to setting a process as critical is that if the process stops then so must the system.
Without a kernel debugger, the system simply halts with a bug check. The stop code is CRITICAL_PROCESS_DIED (0xEF) if termination was orderly (as when the process is terminated simply because its last running thread has exited), else CRITICAL_OBJECT_TERMINATION (0xF4).
If a kernel debugger is enabled, the termination is described as either of the lines
Critical process address (filename) exited
Terminating critical process address (filename)
according to whether termination was orderly or unexpected. If the debugger can take a prompt, a choice is then offered to
Break, or Ignore (bi)?
Breaking to the debugger and then continuing is effectively the same as ignoring. Any other response to the prompt leaves the kernel having to stop as if no debugger is enabled, except that now the bug check code is CRITICAL_OBJECT_TERMINATION no matter how the process terminated.
The RtlSetProcessIsCritical function is exported from NTDLL in version 5.1 and higher. The notes above are from inspection of the version from Windows Vista.
As with many NTDLL functions, Microsoft does not document RtlSetProcessIsCritical. Unlike many, no KERNEL32 function corresponds roughly to it.
The closest that RtlSetProcessIsCritical seems to have come to being documented is in the Debugging Tools for Windows, specifically in documentation of the GFLAGS.EXE tool. The “Enable system critical breaks” flag is there said to be “effective only when the process calls the RtlSetProcessBreakOnExit and RtlSetThreadBreakOnExit interfaces.” Neither of these seems to exist in any Windows release, but perhaps the former is an early name for RtlSetProcessIsCritical.
The only known users of this function are the following handful:
Of these, only CSRSS asks to be treated as critical even without the “Enable system critical breaks” configuration.