2020-07-03 16:49:47 +02:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0
|
|
|
|
*
|
2021-01-30 16:45:26 +01:00
|
|
|
* Copyright (C) 2018-2021 WireGuard LLC. All Rights Reserved.
|
2020-07-03 16:49:47 +02:00
|
|
|
*/
|
|
|
|
|
2020-10-31 11:55:26 +01:00
|
|
|
#include "logger.h"
|
2021-07-28 13:50:40 +02:00
|
|
|
#include "main.h"
|
2020-10-31 11:55:26 +01:00
|
|
|
#include "namespace.h"
|
|
|
|
|
|
|
|
#include <Windows.h>
|
2020-11-04 01:08:41 +01:00
|
|
|
#include <winternl.h>
|
2020-10-31 11:55:26 +01:00
|
|
|
#include <bcrypt.h>
|
2021-07-23 18:19:00 +02:00
|
|
|
#include <winefs.h>
|
2020-10-31 13:03:14 +01:00
|
|
|
#include <wchar.h>
|
2021-07-23 18:19:00 +02:00
|
|
|
#include <stdlib.h>
|
2020-07-03 16:49:47 +02:00
|
|
|
|
2020-12-17 19:00:25 +01:00
|
|
|
static HANDLE PrivateNamespace = NULL;
|
|
|
|
static HANDLE BoundaryDescriptor = NULL;
|
2020-07-03 16:49:47 +02:00
|
|
|
static CRITICAL_SECTION Initializing;
|
|
|
|
static BCRYPT_ALG_HANDLE AlgProvider;
|
|
|
|
|
2021-07-28 20:20:09 +02:00
|
|
|
_Must_inspect_result_
|
|
|
|
static _Return_type_success_(return != NULL)
|
|
|
|
_Post_maybenull_
|
|
|
|
LPWSTR
|
|
|
|
NormalizeStringAlloc(_In_ NORM_FORM NormForm, _In_z_ LPCWSTR Source)
|
2020-07-03 16:49:47 +02:00
|
|
|
{
|
|
|
|
int Len = NormalizeString(NormForm, Source, -1, NULL, 0);
|
2020-10-15 12:38:05 +02:00
|
|
|
for (;;)
|
2020-07-03 16:49:47 +02:00
|
|
|
{
|
2021-07-28 20:20:09 +02:00
|
|
|
LPWSTR Str = AllocArray(Len, sizeof(*Str));
|
2020-10-15 12:38:05 +02:00
|
|
|
if (!Str)
|
2020-11-03 12:29:34 +01:00
|
|
|
return NULL;
|
2020-10-15 12:38:05 +02:00
|
|
|
Len = NormalizeString(NormForm, Source, -1, Str, Len);
|
2020-07-03 16:49:47 +02:00
|
|
|
if (Len > 0)
|
2020-10-15 12:38:05 +02:00
|
|
|
return Str;
|
2020-11-04 12:55:25 +01:00
|
|
|
Free(Str);
|
|
|
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
2020-11-03 12:29:34 +01:00
|
|
|
{
|
2021-02-02 13:12:45 +01:00
|
|
|
LOG_LAST_ERROR(L"Failed: %s", Source);
|
2020-11-03 12:29:34 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
2020-07-03 16:49:47 +02:00
|
|
|
Len = -Len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-28 20:20:09 +02:00
|
|
|
static _Return_type_success_(return != FALSE)
|
|
|
|
BOOL NamespaceRuntimeInit(VOID)
|
2020-07-03 16:49:47 +02:00
|
|
|
{
|
2020-11-03 12:29:34 +01:00
|
|
|
DWORD LastError;
|
2020-07-03 16:49:47 +02:00
|
|
|
|
|
|
|
EnterCriticalSection(&Initializing);
|
2020-12-17 19:00:25 +01:00
|
|
|
if (PrivateNamespace)
|
2020-07-03 16:49:47 +02:00
|
|
|
{
|
|
|
|
LeaveCriticalSection(&Initializing);
|
2020-11-03 12:29:34 +01:00
|
|
|
return TRUE;
|
2020-07-03 16:49:47 +02:00
|
|
|
}
|
|
|
|
|
2020-11-04 01:08:41 +01:00
|
|
|
NTSTATUS Status;
|
|
|
|
if (!BCRYPT_SUCCESS(Status = BCryptOpenAlgorithmProvider(&AlgProvider, BCRYPT_SHA256_ALGORITHM, NULL, 0)))
|
2020-07-03 16:49:47 +02:00
|
|
|
{
|
2021-02-02 13:12:45 +01:00
|
|
|
LOG(WINTUN_LOG_ERR, L"Failed to open algorithm provider (status: 0x%x)", Status);
|
2020-11-04 01:08:41 +01:00
|
|
|
LastError = RtlNtStatusToDosError(Status);
|
2020-07-03 16:49:47 +02:00
|
|
|
goto cleanupLeaveCriticalSection;
|
|
|
|
}
|
|
|
|
|
|
|
|
BYTE Sid[MAX_SID_SIZE];
|
2021-06-24 12:12:13 +02:00
|
|
|
DWORD SidSize = sizeof(Sid);
|
|
|
|
if (!CreateWellKnownSid(IsLocalSystem ? WinLocalSystemSid : WinBuiltinAdministratorsSid, NULL, Sid, &SidSize))
|
2020-07-03 16:49:47 +02:00
|
|
|
{
|
2020-11-03 12:29:34 +01:00
|
|
|
LastError = LOG_LAST_ERROR(L"Failed to create SID");
|
2020-10-15 15:34:31 +02:00
|
|
|
goto cleanupBCryptCloseAlgorithmProvider;
|
2020-07-03 16:49:47 +02:00
|
|
|
}
|
|
|
|
|
2020-12-17 19:00:25 +01:00
|
|
|
BoundaryDescriptor = CreateBoundaryDescriptorW(L"Wintun", 0);
|
|
|
|
if (!BoundaryDescriptor)
|
2020-07-03 16:49:47 +02:00
|
|
|
{
|
2020-11-03 12:29:34 +01:00
|
|
|
LastError = LOG_LAST_ERROR(L"Failed to create boundary descriptor");
|
2020-10-15 15:34:31 +02:00
|
|
|
goto cleanupBCryptCloseAlgorithmProvider;
|
2020-07-03 16:49:47 +02:00
|
|
|
}
|
2020-12-17 19:00:25 +01:00
|
|
|
if (!AddSIDToBoundaryDescriptor(&BoundaryDescriptor, Sid))
|
2020-07-03 16:49:47 +02:00
|
|
|
{
|
2020-11-03 12:29:34 +01:00
|
|
|
LastError = LOG_LAST_ERROR(L"Failed to add SID to boundary descriptor");
|
2020-12-17 19:00:25 +01:00
|
|
|
goto cleanupBoundaryDescriptor;
|
2020-07-03 16:49:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
2020-12-17 19:00:25 +01:00
|
|
|
if ((PrivateNamespace = CreatePrivateNamespaceW(&SecurityAttributes, BoundaryDescriptor, L"Wintun")) != NULL)
|
2020-07-03 16:49:47 +02:00
|
|
|
break;
|
2020-11-03 12:29:34 +01:00
|
|
|
if ((LastError = GetLastError()) == ERROR_ALREADY_EXISTS)
|
2020-07-03 16:49:47 +02:00
|
|
|
{
|
2020-12-17 19:00:25 +01:00
|
|
|
if ((PrivateNamespace = OpenPrivateNamespaceW(BoundaryDescriptor, L"Wintun")) != NULL)
|
2020-07-03 16:49:47 +02:00
|
|
|
break;
|
2020-11-03 12:29:34 +01:00
|
|
|
if ((LastError = GetLastError()) == ERROR_PATH_NOT_FOUND)
|
2020-07-03 16:49:47 +02:00
|
|
|
continue;
|
2021-02-02 13:12:45 +01:00
|
|
|
LOG_ERROR(LastError, L"Failed to open private namespace");
|
2020-07-03 16:49:47 +02:00
|
|
|
}
|
2020-11-03 12:29:34 +01:00
|
|
|
else
|
2021-02-02 13:12:45 +01:00
|
|
|
LOG_ERROR(LastError, L"Failed to create private namespace");
|
2020-12-17 19:00:25 +01:00
|
|
|
goto cleanupBoundaryDescriptor;
|
2020-07-03 16:49:47 +02:00
|
|
|
}
|
|
|
|
|
2020-11-03 12:29:34 +01:00
|
|
|
LeaveCriticalSection(&Initializing);
|
|
|
|
return TRUE;
|
2020-07-03 16:49:47 +02:00
|
|
|
|
2020-12-17 19:00:25 +01:00
|
|
|
cleanupBoundaryDescriptor:
|
|
|
|
DeleteBoundaryDescriptor(BoundaryDescriptor);
|
2020-07-03 16:49:47 +02:00
|
|
|
cleanupBCryptCloseAlgorithmProvider:
|
|
|
|
BCryptCloseAlgorithmProvider(AlgProvider, 0);
|
|
|
|
cleanupLeaveCriticalSection:
|
|
|
|
LeaveCriticalSection(&Initializing);
|
2020-11-03 12:29:34 +01:00
|
|
|
SetLastError(LastError);
|
|
|
|
return FALSE;
|
2020-07-03 16:49:47 +02:00
|
|
|
}
|
|
|
|
|
2021-07-28 20:20:09 +02:00
|
|
|
_Use_decl_annotations_
|
|
|
|
HANDLE
|
|
|
|
NamespaceTakePoolMutex(LPCWSTR Pool)
|
2020-07-03 16:49:47 +02:00
|
|
|
{
|
2020-11-03 12:29:34 +01:00
|
|
|
if (!NamespaceRuntimeInit())
|
2020-07-03 16:49:47 +02:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
BCRYPT_HASH_HANDLE Sha256 = NULL;
|
2020-11-04 01:08:41 +01:00
|
|
|
NTSTATUS Status;
|
|
|
|
if (!BCRYPT_SUCCESS(Status = BCryptCreateHash(AlgProvider, &Sha256, NULL, 0, NULL, 0, 0)))
|
2020-11-03 12:29:34 +01:00
|
|
|
{
|
2021-02-02 13:12:45 +01:00
|
|
|
LOG(WINTUN_LOG_ERR, L"Failed to create hash (status: 0x%x)", Status);
|
2020-11-04 01:08:41 +01:00
|
|
|
SetLastError(RtlNtStatusToDosError(Status));
|
2020-07-03 16:49:47 +02:00
|
|
|
return NULL;
|
2020-11-03 12:29:34 +01:00
|
|
|
}
|
|
|
|
DWORD LastError;
|
2020-10-30 16:31:41 +01:00
|
|
|
static const WCHAR mutex_label[] = L"Wintun Adapter Name Mutex Stable Suffix v1 jason@zx2c4.com";
|
2020-11-03 12:29:34 +01:00
|
|
|
if (!BCRYPT_SUCCESS(
|
2020-11-04 01:08:41 +01:00
|
|
|
Status = BCryptHashData(Sha256, (PUCHAR)mutex_label, sizeof(mutex_label) /* Including NULL 2 bytes */, 0)))
|
2020-11-03 12:29:34 +01:00
|
|
|
{
|
2021-02-02 13:12:45 +01:00
|
|
|
LOG(WINTUN_LOG_ERR, L"Failed to hash data (status: 0x%x)", Status);
|
2020-11-04 01:08:41 +01:00
|
|
|
LastError = RtlNtStatusToDosError(Status);
|
2020-07-03 16:49:47 +02:00
|
|
|
goto cleanupSha256;
|
2020-11-03 12:29:34 +01:00
|
|
|
}
|
2021-07-28 20:20:09 +02:00
|
|
|
LPWSTR PoolNorm = NormalizeStringAlloc(NormalizationC, Pool);
|
2020-07-03 16:49:47 +02:00
|
|
|
if (!PoolNorm)
|
2020-11-03 12:29:34 +01:00
|
|
|
{
|
|
|
|
LastError = GetLastError();
|
2020-07-03 16:49:47 +02:00
|
|
|
goto cleanupSha256;
|
2020-11-03 12:29:34 +01:00
|
|
|
}
|
|
|
|
if (!BCRYPT_SUCCESS(
|
2020-11-04 01:08:41 +01:00
|
|
|
Status = BCryptHashData(Sha256, (PUCHAR)PoolNorm, (int)wcslen(PoolNorm) + 2 /* Add in NULL 2 bytes */, 0)))
|
2020-11-03 12:29:34 +01:00
|
|
|
{
|
2021-02-02 13:12:45 +01:00
|
|
|
LOG(WINTUN_LOG_ERR, L"Failed to hash data (status: 0x%x)", Status);
|
2020-11-04 01:08:41 +01:00
|
|
|
LastError = RtlNtStatusToDosError(Status);
|
2020-07-03 16:49:47 +02:00
|
|
|
goto cleanupPoolNorm;
|
2020-11-03 12:29:34 +01:00
|
|
|
}
|
2020-07-03 16:49:47 +02:00
|
|
|
BYTE Hash[32];
|
2020-11-04 01:08:41 +01:00
|
|
|
if (!BCRYPT_SUCCESS(Status = BCryptFinishHash(Sha256, Hash, sizeof(Hash), 0)))
|
2020-11-03 12:29:34 +01:00
|
|
|
{
|
2021-02-02 13:12:45 +01:00
|
|
|
LOG(WINTUN_LOG_ERR, L"Failed to calculate hash (status: 0x%x)", Status);
|
2020-11-04 01:08:41 +01:00
|
|
|
LastError = RtlNtStatusToDosError(Status);
|
2020-07-03 16:49:47 +02:00
|
|
|
goto cleanupPoolNorm;
|
2020-11-03 12:29:34 +01:00
|
|
|
}
|
2020-07-03 16:49:47 +02:00
|
|
|
static const WCHAR MutexNamePrefix[] = L"Wintun\\Wintun-Name-Mutex-";
|
2020-10-31 13:03:14 +01:00
|
|
|
WCHAR MutexName[_countof(MutexNamePrefix) + sizeof(Hash) * 2];
|
|
|
|
memcpy(MutexName, MutexNamePrefix, sizeof(MutexNamePrefix));
|
|
|
|
for (size_t i = 0; i < sizeof(Hash); ++i)
|
|
|
|
swprintf_s(&MutexName[_countof(MutexNamePrefix) - 1 + i * 2], 3, L"%02x", Hash[i]);
|
2020-11-03 12:29:34 +01:00
|
|
|
HANDLE Mutex = CreateMutexW(&SecurityAttributes, FALSE, MutexName);
|
2020-07-03 16:49:47 +02:00
|
|
|
if (!Mutex)
|
2020-11-03 12:29:34 +01:00
|
|
|
{
|
2021-02-02 13:12:45 +01:00
|
|
|
LastError = LOG_LAST_ERROR(L"Failed to create mutex %s", MutexName);
|
2020-07-03 16:49:47 +02:00
|
|
|
goto cleanupPoolNorm;
|
2020-11-03 12:29:34 +01:00
|
|
|
}
|
2021-02-02 13:12:45 +01:00
|
|
|
DWORD Result = WaitForSingleObject(Mutex, INFINITE);
|
|
|
|
switch (Result)
|
2020-07-03 16:49:47 +02:00
|
|
|
{
|
|
|
|
case WAIT_OBJECT_0:
|
|
|
|
case WAIT_ABANDONED:
|
2020-11-04 12:55:25 +01:00
|
|
|
Free(PoolNorm);
|
2020-11-03 12:29:34 +01:00
|
|
|
BCryptDestroyHash(Sha256);
|
|
|
|
return Mutex;
|
2020-07-03 16:49:47 +02:00
|
|
|
}
|
2021-02-02 13:12:45 +01:00
|
|
|
LOG(WINTUN_LOG_ERR, L"Failed to get mutex %s (status: 0x%x)", MutexName, Result);
|
2020-11-03 12:29:34 +01:00
|
|
|
LastError = ERROR_GEN_FAILURE;
|
2020-07-03 16:49:47 +02:00
|
|
|
CloseHandle(Mutex);
|
|
|
|
cleanupPoolNorm:
|
2020-11-04 12:55:25 +01:00
|
|
|
Free(PoolNorm);
|
2020-07-03 16:49:47 +02:00
|
|
|
cleanupSha256:
|
|
|
|
BCryptDestroyHash(Sha256);
|
2020-11-03 12:29:34 +01:00
|
|
|
SetLastError(LastError);
|
|
|
|
return NULL;
|
2020-07-03 16:49:47 +02:00
|
|
|
}
|
|
|
|
|
2021-07-28 20:20:09 +02:00
|
|
|
_Use_decl_annotations_
|
|
|
|
HANDLE
|
|
|
|
NamespaceTakeDriverInstallationMutex(VOID)
|
2020-11-02 12:07:05 +01:00
|
|
|
{
|
2020-11-03 12:29:34 +01:00
|
|
|
if (!NamespaceRuntimeInit())
|
2020-11-02 12:07:05 +01:00
|
|
|
return NULL;
|
2020-11-03 12:29:34 +01:00
|
|
|
HANDLE Mutex = CreateMutexW(&SecurityAttributes, FALSE, L"Wintun\\Wintun-Driver-Installation-Mutex");
|
2020-11-02 12:07:05 +01:00
|
|
|
if (!Mutex)
|
2020-11-03 12:29:34 +01:00
|
|
|
{
|
|
|
|
LOG_LAST_ERROR(L"Failed to create mutex");
|
2020-11-02 12:07:05 +01:00
|
|
|
return NULL;
|
2020-11-03 12:29:34 +01:00
|
|
|
}
|
2021-02-02 13:12:45 +01:00
|
|
|
DWORD Result = WaitForSingleObject(Mutex, INFINITE);
|
|
|
|
switch (Result)
|
2020-11-02 12:07:05 +01:00
|
|
|
{
|
|
|
|
case WAIT_OBJECT_0:
|
|
|
|
case WAIT_ABANDONED:
|
2020-11-03 12:29:34 +01:00
|
|
|
return Mutex;
|
2020-11-02 12:07:05 +01:00
|
|
|
}
|
2021-02-02 13:12:45 +01:00
|
|
|
LOG(WINTUN_LOG_ERR, L"Failed to get mutex (status: 0x%x)", Result);
|
2020-11-02 12:07:05 +01:00
|
|
|
CloseHandle(Mutex);
|
2020-11-03 12:29:34 +01:00
|
|
|
SetLastError(ERROR_GEN_FAILURE);
|
|
|
|
return NULL;
|
2020-11-02 12:07:05 +01:00
|
|
|
}
|
|
|
|
|
2021-07-28 20:20:09 +02:00
|
|
|
_Use_decl_annotations_
|
|
|
|
VOID
|
|
|
|
NamespaceReleaseMutex(HANDLE Mutex)
|
2020-07-03 16:49:47 +02:00
|
|
|
{
|
|
|
|
ReleaseMutex(Mutex);
|
|
|
|
CloseHandle(Mutex);
|
|
|
|
}
|
|
|
|
|
2021-07-28 20:20:09 +02:00
|
|
|
VOID NamespaceInit(VOID)
|
2020-07-03 16:49:47 +02:00
|
|
|
{
|
|
|
|
InitializeCriticalSection(&Initializing);
|
|
|
|
}
|
|
|
|
|
2021-07-28 20:20:09 +02:00
|
|
|
VOID NamespaceDone(VOID)
|
2020-07-03 16:49:47 +02:00
|
|
|
{
|
|
|
|
EnterCriticalSection(&Initializing);
|
2020-12-17 19:00:25 +01:00
|
|
|
if (PrivateNamespace)
|
2020-07-03 16:49:47 +02:00
|
|
|
{
|
|
|
|
BCryptCloseAlgorithmProvider(AlgProvider, 0);
|
2020-12-17 19:00:25 +01:00
|
|
|
ClosePrivateNamespace(PrivateNamespace, 0);
|
|
|
|
DeleteBoundaryDescriptor(BoundaryDescriptor);
|
|
|
|
PrivateNamespace = NULL;
|
2020-07-03 16:49:47 +02:00
|
|
|
}
|
|
|
|
LeaveCriticalSection(&Initializing);
|
|
|
|
DeleteCriticalSection(&Initializing);
|
|
|
|
}
|