Geoff Chappell, Software Analyst
The EVENT_TRACE_GROUPMASK_INFORMATION structure is one of many that the ZwQuerySystemInformation (or NtQuerySystemInformation) and ZwSetSystemInformation (or NtSetSystemInformation) functions expect in their information buffer when given the information class SystemPerformanceTraceInformation (0x1F). This particular structure is selected when the first dword in the information buffer on input is EventTraceGroupMaskInformation (0x01).
At least in user mode, the EVENT_TRACE_GROUPMASK_INFORMATION structure arguably exists only to support the documented ADVAPI32 or SECHOST functions TraceQueryInformation and TraceSetInformation for their information class TraceSystemTraceEnableFlagsInfo (0x04). Well-behaved user-mode software executing above ADVAPI32 does not call NtQuerySystemInformation or NtSetSystemInformation but prefers TraceQueryInformation and TraceSetInformation and therefore has no need of this structure.
Or so might go the theory or principle. Against it is that Microsoft’s documentation of TraceQueryInformation and TraceSetInformation, as perused online today (30th November 2016), does not tell programmers what form of information to expect or provide. Indeed, what it does say is arguably misleading, for it suggests that the TraceSystemTraceEnableFlagsInfo case works just with “the setting for the EnableFlags for the system trace provider” and directs attention to the documentation of the EVENT_TRACE_PROPERTIES structure. In fact, the case provides for a significant extension of those flags.
The EVENT_TRACE_GROUPMASK_INFORMATION structure is not documented but Microsoft has published a C-language definition in a header file named NTETW.H from the Enterprise edition of the Windows Driver Kit (WDK) for Windows 10 version 1511.
Were it not for this relatively recent and possibly unintended disclosure, much would anyway be known from type information in symbol files. Curiously though, type information for this structure has never appeared in any public symbol files for the kernel or for the obvious low-level user-mode DLLs. In the whole of Microsoft’s packages of public symbol files, at least to the original Windows 10, relevant type information is unknown before Windows 8 and appears in symbol files only for AppXDeploymentClient.dll, CertEnroll.dll (before Windows 10) and Windows.Storage.ApplicationData.dll.
The EVENT_TRACE_GROUPMASK_INFORMATION is 0x30 bytes in both 32-bit and 64-bit Windows:
|input||6.0 and higher|
|input||6.0 and higher|
|output for query;
input for set
|6.0 and higher|
When the structure is built by TraceQueryInformation or TraceSetInformation, the TraceHandle is the SessionHandle argument and the EventTraceGroupMasks is copied to or from the InformationLength bytes at TraceInformation.
The EVENT_TRACE_GROUPMASK_INFORMATION structure is meaningful only as input to one case each of the ZwQuerySystemInformation and ZwSetSystemInformation functions. The behaviour is as well picked up here. This review takes as understood all the general points and shorthands that are noted in the separate attempt at documenting the functions, and takes as granted that the information class is SystemPerformanceTraceInformation and that the information buffer is exactly the size of an EVENT_TRACE_GROUPMASK_INFORMATION in which the EventTraceInformationClass is EventTraceGroupMaskInformation.
Note that although EventTraceGroupMaskInformation is valid for querying in version 6.0 and higher, versions before 6.2 reject it for setting. The returned error code is ERROR_NOT_IMPLEMENTED.
Whether to query or set, the TraceHandle selects an event logger. Specifically, the low 16 bits are the logger ID or are 0xFFFF to select the NT Kernel Logger. This interpretation of 0xFFFF is formalised by the definition of a macro KERNEL_LOGGER_ID in the NTWMI_X.H header from the 1511 edition of the Enterprise WDK for Windows 10. If the logger ID does not select an active logger to which the function can arrange exclusive access, the function returns STATUS_WMI_INSTANCE_NOT_FOUND. The function also fails, but returning STATUS_INVALID_PARAMETER, if the logger context’s logger mode does not include EVENT_TRACE_SYSTEM_LOGGER_MODE (0x02000000).
The essential work when querying is to extract the logger’s PERFINFO_GROUPMASK as the EventTraceGroupMasks member of the output. This PERFINFO_GROUPMASK that is produced as output is not necessarily exactly what the kernel keeps for the logger but may instead have been translated for compatibility with the EnableFlags that is documented for the EVENT_TRACE_PROPERTIES structure as input to the StartTrace and ControlTrace functions.
To set information, the caller must have TRACELOG_GUID_ENABLE access to the logger. Without it, the function fails, typically returning STATUS_ACCESS_DENIED.
The essential work when setting is to load the logger’s PERFINFO_GROUPMASK from the EventTraceGroupMasks member of the input. As with querying, translation may be involved for compatibility.
The given group masks specify which types of event the kernel is to generate (itself or on behalf of low-level user-mode modules such as NTDLL) for the logger. For most types of event, enabling is trivial: for others, not so much. For example, asking to enable PERF_PROFILE (0x20000002) or PERF_PMC_PROFILE (0x20000400) without SeSystemProfilePrivilege causes the function to fail, returning STATUS_PRIVILEGE_NOT_HELD. Another is that asking to enable PERF_CONTEXT_SWITCH (0x20000004) and PERF_COMPACT_CSWITCH (0x20000100) when they are not already both enabled may require the preparation of per-processor buffers to support the efficient batching of data about thread switches, and can fail such that the function returns STATUS_NO_MEMORY. There need not be an end to such examples, of course.