I recently noticed that an unnamed event created by CreateEvent received a security descriptor with a NULL DACL. The call to CreateEvent passed nullptr as the lpEventAttributes parameter.
I expected the event to receive a security descriptor based on the default dacl contained in the process token. After all, the documentation says "If lpEventAttributes is NULL, the event gets a default security descriptor. The ACLs in the default security descriptor for an event come from the primary or impersonation token of the creator." But this was not the case. The NULL DACL could also be observed using Process Explorer.
So is the documentation incorrect?
Sample code to see this result is -
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <AclAPI.h>
#include <sddl.h>
#include <stdio.h>
#include <tchar.h>
void PrintDefaultDACL();
void PrintDACL(HANDLE h);
int main()
{
_tprintf(_T("\nPrint Default DACL from process token\n"));
PrintDefaultDACL();
// Named event receives default security descriptor base on primary or impersonation token
_tprintf(_T("\nPrint DACL for named kernel object\n"));
HANDLE h1 = CreateEvent(nullptr, FALSE, FALSE, _T("Test"));
PrintDACL(h1);
CloseHandle(h1);
// Unnamed event receives security descriptor with a NULL DACL
_tprintf(_T("\nPrint DACL for unnamed kernel object\n"));
HANDLE h2 = CreateEvent(nullptr, FALSE, FALSE, nullptr);
PrintDACL(h2);
CloseHandle(h2);
return 0;
}
void PrintDefaultDACL()
{
HANDLE hToken = NULL;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
{
DWORD dwBytes = 0;
PTOKEN_DEFAULT_DACL pDefaultDacl = nullptr;
if (!GetTokenInformation(hToken, TokenDefaultDacl, pDefaultDacl, 0, &dwBytes) && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
pDefaultDacl = (PTOKEN_DEFAULT_DACL)LocalAlloc(LPTR, dwBytes);
if (GetTokenInformation(hToken, TokenDefaultDacl, pDefaultDacl, dwBytes, &dwBytes))
{
PSECURITY_DESCRIPTOR pSD = LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
if (InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
{
if (SetSecurityDescriptorDacl(pSD, TRUE, pDefaultDacl->DefaultDacl, FALSE))
{
LPTSTR pszSD = nullptr;
ULONG uLen = 0;
if (ConvertSecurityDescriptorToStringSecurityDescriptor(pSD, SDDL_REVISION_1, DACL_SECURITY_INFORMATION, &pszSD, &uLen))
{
_tprintf_s(_T("%s\n"), pszSD);
LocalFree(pszSD);
}
}
}
LocalFree(pSD);
}
LocalFree(pDefaultDacl);
}
CloseHandle(hToken);
}
}
void PrintDACL(HANDLE h)
{
PSECURITY_DESCRIPTOR pSD = nullptr;
PACL pDacl = nullptr;
if (GetSecurityInfo(h, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, nullptr, nullptr, &pDacl, nullptr, &pSD) == ERROR_SUCCESS)
{
LPTSTR pszSD = nullptr;
ULONG ulen = 0;
_tprintf_s(_T("Pointer to DACL in security descriptor is 0x%p\n"), pDacl);
if (ConvertSecurityDescriptorToStringSecurityDescriptor(pSD, SDDL_REVISION_1, DACL_SECURITY_INFORMATION, &pszSD, &ulen))
{
_tprintf_s(_T("DACL: %s\n"), pszSD);
LocalFree(pszSD);
}
LocalFree(pSD);
}
}