Skip to content

Commit

Permalink
api: upgrade logging
Browse files Browse the repository at this point in the history
Log runtime information to quickly check whether the values are sane
when analyzing error logs sent in by users.

Signed-off-by: Simon Rozman <[email protected]>
  • Loading branch information
rozmansi committed Feb 5, 2021
1 parent 542a281 commit 728d676
Show file tree
Hide file tree
Showing 10 changed files with 430 additions and 177 deletions.
289 changes: 177 additions & 112 deletions api/adapter.c

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion api/elevate.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ _Return_type_success_(return != FALSE) BOOL ElevateToSystem(void)
CloseHandle(CurrentProcessToken);
if (!Ret)
{
LOG_ERROR(L"Failed to get token information", LastError);
LOG_ERROR(LastError, L"Failed to get token information");
goto cleanup;
}
if (EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid))
Expand Down
75 changes: 70 additions & 5 deletions api/logger.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
*/

#include "logger.h"
#include "ntdll.h"
#include <Windows.h>
#include <winternl.h>
#include <wchar.h>

static BOOL CALLBACK
Expand All @@ -25,6 +27,13 @@ WintunSetLogger(_In_ WINTUN_LOGGER_CALLBACK NewLogger)
Logger = NewLogger;
}

static VOID
StrTruncate(_Inout_count_(StrChars) WCHAR *Str, _In_ SIZE_T StrChars)
{
Str[StrChars - 2] = L'\u2026'; /* Horizontal Ellipsis */
Str[StrChars - 1] = 0;
}

_Post_equals_last_error_ DWORD
LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *LogLine)
{
Expand All @@ -33,10 +42,7 @@ LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Function, _In_z_ c
{
WCHAR Combined[0x400];
if (_snwprintf_s(Combined, _countof(Combined), _TRUNCATE, L"%s: %s", Function, LogLine) == -1)
{
Combined[_countof(Combined) - 2] = L'\u2026'; /* Horizontal Ellipsis */
Combined[_countof(Combined) - 1] = 0;
}
StrTruncate(Combined, _countof(Combined));
Logger(Level, Combined);
}
else
Expand All @@ -46,7 +52,26 @@ LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Function, _In_z_ c
}

_Post_equals_last_error_ DWORD
LoggerError(_In_z_ const WCHAR *Function, _In_z_ const WCHAR *Prefix, _In_ DWORD Error)
LoggerLogV(
_In_ WINTUN_LOGGER_LEVEL Level,
_In_z_ const WCHAR *Function,
_In_z_ _Printf_format_string_ const WCHAR *Format,
_In_ va_list Args)
{
DWORD LastError = GetLastError();
WCHAR LogLine[0x400];
if (_vsnwprintf_s(LogLine, _countof(LogLine), _TRUNCATE, Format, Args) == -1)
StrTruncate(LogLine, _countof(LogLine));
if (Function)
LoggerLog(Level, Function, LogLine);
else
Logger(Level, LogLine);
SetLastError(LastError);
return LastError;
}

_Post_equals_last_error_ DWORD
LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *Prefix)
{
WCHAR *SystemMessage = NULL, *FormattedMessage = NULL;
FormatMessageW(
Expand All @@ -72,3 +97,43 @@ LoggerError(_In_z_ const WCHAR *Function, _In_z_ const WCHAR *Prefix, _In_ DWORD
LocalFree(SystemMessage);
return Error;
}

_Post_equals_last_error_ DWORD
LoggerErrorV(
_In_ DWORD Error,
_In_z_ const WCHAR *Function,
_In_z_ _Printf_format_string_ const WCHAR *Format,
_In_ va_list Args)
{
WCHAR Prefix[0x400];
if (_vsnwprintf_s(Prefix, _countof(Prefix), _TRUNCATE, Format, Args) == -1)
StrTruncate(Prefix, _countof(Prefix));
return LoggerError(Error, Function, Prefix);
}

VOID
LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path)
{
DWORD LastError = GetLastError();
if (Key == NULL)
{
wcscpy_s(Path, MAX_REG_PATH, L"<null>");
goto out;
}
if (_snwprintf_s(Path, MAX_REG_PATH, _TRUNCATE, L"0x%p", Key) == -1)
StrTruncate(Path, MAX_REG_PATH);
union
{
KEY_NAME_INFORMATION KeyNameInfo;
WCHAR Data[offsetof(KEY_NAME_INFORMATION, Name) + MAX_REG_PATH];
} Buffer;
DWORD Size;
if (!NT_SUCCESS(NtQueryKey(Key, 3, &Buffer, sizeof(Buffer), &Size)) ||
Size < offsetof(KEY_NAME_INFORMATION, Name) || Buffer.KeyNameInfo.NameLength >= MAX_REG_PATH * sizeof(WCHAR))
goto out;
Buffer.KeyNameInfo.NameLength /= sizeof(WCHAR);
wmemcpy_s(Path, MAX_REG_PATH, Buffer.KeyNameInfo.Name, Buffer.KeyNameInfo.NameLength);
Path[Buffer.KeyNameInfo.NameLength] = L'\0';
out:
SetLastError(LastError);
}
69 changes: 62 additions & 7 deletions api/logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@

#include "wintun.h"
#include "entry.h"
#include "registry.h"
#include <Windows.h>
#include <stdarg.h>
#include <wchar.h>

extern WINTUN_LOGGER_CALLBACK Logger;

Expand All @@ -21,22 +24,73 @@ _Post_equals_last_error_ DWORD
LoggerLog(_In_ WINTUN_LOGGER_LEVEL Level, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *LogLine);

_Post_equals_last_error_ DWORD
LoggerError(_In_z_ const WCHAR *Function, _In_z_ const WCHAR *Prefix, _In_ DWORD Error);
LoggerLogV(
_In_ WINTUN_LOGGER_LEVEL Level,
_In_z_ const WCHAR *Function,
_In_z_ _Printf_format_string_ const WCHAR *Format,
_In_ va_list Args);

static inline _Post_equals_last_error_ DWORD
LoggerLastError(_In_z_ const WCHAR *Function, _In_z_ const WCHAR *Prefix)
LoggerLogFmt(
_In_ WINTUN_LOGGER_LEVEL Level,
_In_z_ const WCHAR *Function,
_In_z_ _Printf_format_string_ const WCHAR *Format,
...)
{
va_list Args;
va_start(Args, Format);
DWORD LastError = LoggerLogV(Level, Function, Format, Args);
va_end(Args);
return LastError;
}

_Post_equals_last_error_ DWORD
LoggerError(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ const WCHAR *Prefix);

_Post_equals_last_error_ DWORD
LoggerErrorV(
_In_ DWORD Error,
_In_z_ const WCHAR *Function,
_In_z_ _Printf_format_string_ const WCHAR *Format,
_In_ va_list Args);

static inline _Post_equals_last_error_ DWORD
LoggerErrorFmt(_In_ DWORD Error, _In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ const WCHAR *Format, ...)
{
va_list Args;
va_start(Args, Format);
DWORD LastError = LoggerErrorV(Error, Function, Format, Args);
va_end(Args);
return LastError;
}

static inline _Post_equals_last_error_ DWORD
LoggerLastErrorV(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ const WCHAR *Format, _In_ va_list Args)
{
DWORD LastError = GetLastError();
LoggerError(Function, Prefix, LastError);
LoggerErrorV(LastError, Function, Format, Args);
SetLastError(LastError);
return LastError;
}

static inline _Post_equals_last_error_ DWORD
LoggerLastErrorFmt(_In_z_ const WCHAR *Function, _In_z_ _Printf_format_string_ const WCHAR *Format, ...)
{
va_list Args;
va_start(Args, Format);
DWORD LastError = LoggerLastErrorV(Function, Format, Args);
va_end(Args);
return LastError;
}

VOID
LoggerGetRegistryKeyPath(_In_ HKEY Key, _Out_cap_c_(MAX_REG_PATH) WCHAR *Path);

#define __L(x) L##x
#define _L(x) __L(x)
#define LOG(lvl, msg) (LoggerLog((lvl), _L(__FUNCTION__), msg))
#define LOG_ERROR(msg, err) (LoggerError(_L(__FUNCTION__), msg, (err)))
#define LOG_LAST_ERROR(msg) (LoggerLastError(_L(__FUNCTION__), msg))
#define LOG(lvl, msg, ...) (LoggerLogFmt((lvl), _L(__FUNCTION__), msg, __VA_ARGS__))
#define LOG_ERROR(err, msg, ...) (LoggerErrorFmt((err), _L(__FUNCTION__), msg, __VA_ARGS__))
#define LOG_LAST_ERROR(msg, ...) (LoggerLastErrorFmt(_L(__FUNCTION__), msg, __VA_ARGS__))

#define RET_ERROR(Ret, Error) ((Error) == ERROR_SUCCESS ? (Ret) : (SetLastError(Error), 0))

Expand All @@ -46,13 +100,14 @@ static inline _Return_type_success_(return != NULL) _Ret_maybenull_
void *Data = HeapAlloc(ModuleHeap, Flags, Size);
if (!Data)
{
LoggerLog(WINTUN_LOG_ERR, Function, L"Out of memory");
LoggerLogFmt(WINTUN_LOG_ERR, Function, L"Out of memory (flags: 0x%x, requested size: 0x%zx)", Flags, Size);
SetLastError(ERROR_OUTOFMEMORY);
}
return Data;
}
#define Alloc(Size) LoggerAlloc(_L(__FUNCTION__), 0, Size)
#define Zalloc(Size) LoggerAlloc(_L(__FUNCTION__), HEAP_ZERO_MEMORY, Size)

static inline void
Free(void *Ptr)
{
Expand Down
28 changes: 15 additions & 13 deletions api/namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ static _Return_type_success_(
Free(Str);
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
LOG_LAST_ERROR(L"Failed");
LOG_LAST_ERROR(L"Failed: %s", Source);
return NULL;
}
Len = -Len;
Expand All @@ -53,7 +53,7 @@ static _Return_type_success_(return != FALSE) BOOL NamespaceRuntimeInit(void)
NTSTATUS Status;
if (!BCRYPT_SUCCESS(Status = BCryptOpenAlgorithmProvider(&AlgProvider, BCRYPT_SHA256_ALGORITHM, NULL, 0)))
{
LOG(WINTUN_LOG_ERR, L"Failed to open algorithm provider");
LOG(WINTUN_LOG_ERR, L"Failed to open algorithm provider (status: 0x%x)", Status);
LastError = RtlNtStatusToDosError(Status);
goto cleanupLeaveCriticalSection;
}
Expand Down Expand Up @@ -88,10 +88,10 @@ static _Return_type_success_(return != FALSE) BOOL NamespaceRuntimeInit(void)
break;
if ((LastError = GetLastError()) == ERROR_PATH_NOT_FOUND)
continue;
LOG_ERROR(L"Failed to open private namespace", LastError);
LOG_ERROR(LastError, L"Failed to open private namespace");
}
else
LOG_ERROR(L"Failed to create private namespace", LastError);
LOG_ERROR(LastError, L"Failed to create private namespace");
goto cleanupBoundaryDescriptor;
}

Expand All @@ -118,7 +118,7 @@ _Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const
NTSTATUS Status;
if (!BCRYPT_SUCCESS(Status = BCryptCreateHash(AlgProvider, &Sha256, NULL, 0, NULL, 0, 0)))
{
LOG(WINTUN_LOG_ERR, L"Failed to create hash");
LOG(WINTUN_LOG_ERR, L"Failed to create hash (status: 0x%x)", Status);
SetLastError(RtlNtStatusToDosError(Status));
return NULL;
}
Expand All @@ -127,7 +127,7 @@ _Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const
if (!BCRYPT_SUCCESS(
Status = BCryptHashData(Sha256, (PUCHAR)mutex_label, sizeof(mutex_label) /* Including NULL 2 bytes */, 0)))
{
LOG(WINTUN_LOG_ERR, L"Failed to hash data");
LOG(WINTUN_LOG_ERR, L"Failed to hash data (status: 0x%x)", Status);
LastError = RtlNtStatusToDosError(Status);
goto cleanupSha256;
}
Expand All @@ -140,14 +140,14 @@ _Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const
if (!BCRYPT_SUCCESS(
Status = BCryptHashData(Sha256, (PUCHAR)PoolNorm, (int)wcslen(PoolNorm) + 2 /* Add in NULL 2 bytes */, 0)))
{
LOG(WINTUN_LOG_ERR, L"Failed to hash data");
LOG(WINTUN_LOG_ERR, L"Failed to hash data (status: 0x%x)", Status);
LastError = RtlNtStatusToDosError(Status);
goto cleanupPoolNorm;
}
BYTE Hash[32];
if (!BCRYPT_SUCCESS(Status = BCryptFinishHash(Sha256, Hash, sizeof(Hash), 0)))
{
LOG(WINTUN_LOG_ERR, L"Failed to calculate hash");
LOG(WINTUN_LOG_ERR, L"Failed to calculate hash (status: 0x%x)", Status);
LastError = RtlNtStatusToDosError(Status);
goto cleanupPoolNorm;
}
Expand All @@ -159,18 +159,19 @@ _Return_type_success_(return != NULL) HANDLE NamespaceTakePoolMutex(_In_z_ const
HANDLE Mutex = CreateMutexW(&SecurityAttributes, FALSE, MutexName);
if (!Mutex)
{
LastError = LOG_LAST_ERROR(L"Failed to create mutex");
LastError = LOG_LAST_ERROR(L"Failed to create mutex %s", MutexName);
goto cleanupPoolNorm;
}
switch (WaitForSingleObject(Mutex, INFINITE))
DWORD Result = WaitForSingleObject(Mutex, INFINITE);
switch (Result)
{
case WAIT_OBJECT_0:
case WAIT_ABANDONED:
Free(PoolNorm);
BCryptDestroyHash(Sha256);
return Mutex;
}
LOG(WINTUN_LOG_ERR, L"Failed to get mutex");
LOG(WINTUN_LOG_ERR, L"Failed to get mutex %s (status: 0x%x)", MutexName, Result);
LastError = ERROR_GEN_FAILURE;
CloseHandle(Mutex);
cleanupPoolNorm:
Expand All @@ -192,13 +193,14 @@ _Return_type_success_(return != NULL) HANDLE NamespaceTakeDriverInstallationMute
LOG_LAST_ERROR(L"Failed to create mutex");
return NULL;
}
switch (WaitForSingleObject(Mutex, INFINITE))
DWORD Result = WaitForSingleObject(Mutex, INFINITE);
switch (Result)
{
case WAIT_OBJECT_0:
case WAIT_ABANDONED:
return Mutex;
}
LOG(WINTUN_LOG_ERR, L"Failed to get mutex");
LOG(WINTUN_LOG_ERR, L"Failed to get mutex (status: 0x%x)", Result);
CloseHandle(Mutex);
SetLastError(ERROR_GEN_FAILURE);
return NULL;
Expand Down
15 changes: 15 additions & 0 deletions api/ntdll.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ typedef struct _RTL_PROCESS_MODULES
RTL_PROCESS_MODULE_INFORMATION Modules[1];
} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;

typedef struct _KEY_NAME_INFORMATION
{
ULONG NameLength;
WCHAR Name[1];
} KEY_NAME_INFORMATION, *PKEY_NAME_INFORMATION;

#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) // TODO: #include <ntstatus.h> instead of this
#define STATUS_PNP_DEVICE_CONFIGURATION_PENDING ((NTSTATUS)0xC0000495L)

Expand All @@ -46,3 +52,12 @@ typedef struct _RTL_PROCESS_MODULES
EXTERN_C
DECLSPEC_IMPORT VOID NTAPI
RtlGetNtVersionNumbers(_Out_opt_ DWORD *MajorVersion, _Out_opt_ DWORD *MinorVersion, _Out_opt_ DWORD *BuildNumber);

EXTERN_C
DECLSPEC_IMPORT DWORD NTAPI
NtQueryKey(
_In_ HANDLE KeyHandle,
_In_ int KeyInformationClass,
_Out_bytecap_post_bytecount_(Length, *ResultLength) PVOID KeyInformation,
_In_ ULONG Length,
_Out_ PULONG ResultLength);
Loading

0 comments on commit 728d676

Please sign in to comment.