diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2020-10-30 12:25:24 +0100 |
---|---|---|
committer | Simon Rozman <simon@rozman.si> | 2020-10-31 10:41:49 +0100 |
commit | 7964694e1e43cac99b51b1c8c7908fb3d90df76a (patch) | |
tree | 929fa790a547cf73fdd6d403bfc5c90e2aa3cb55 /api | |
parent | api: simplify driver selection by always including EV driver (diff) | |
download | wintun-7964694e1e43cac99b51b1c8c7908fb3d90df76a.tar.xz wintun-7964694e1e43cac99b51b1c8c7908fb3d90df76a.zip |
api: elevate only when needed for system operations
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'api')
-rw-r--r-- | api/adapter.c | 51 | ||||
-rw-r--r-- | api/api.vcxproj | 2 | ||||
-rw-r--r-- | api/api.vcxproj.filters | 6 | ||||
-rw-r--r-- | api/elevate.c | 101 | ||||
-rw-r--r-- | api/elevate.h | 9 | ||||
-rw-r--r-- | api/pch.h | 1 | ||||
-rw-r--r-- | api/rundll32.c | 97 | ||||
-rw-r--r-- | api/session.c | 27 |
8 files changed, 179 insertions, 115 deletions
diff --git a/api/adapter.c b/api/adapter.c index 8ace66c..1006384 100644 --- a/api/adapter.c +++ b/api/adapter.c @@ -597,10 +597,16 @@ WintunGetAdapter( _In_z_count_c_(MAX_ADAPTER_NAME) const WCHAR *Name, _Out_ WINTUN_ADAPTER **Adapter) { + if (!ElevateToSystem()) + return LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"), ERROR_ACCESS_DENIED; + DWORD Result; HANDLE Mutex = NamespaceTakeMutex(Pool); if (!Mutex) - return ERROR_INVALID_HANDLE; + { + Result = ERROR_INVALID_HANDLE; + goto cleanupToken; + } HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); if (DevInfo == INVALID_HANDLE_VALUE) @@ -675,6 +681,8 @@ cleanupDevInfo: SetupDiDestroyDeviceInfoList(DevInfo); cleanupMutex: NamespaceReleaseMutex(Mutex); +cleanupToken: + RevertToSelf(); return Result; } @@ -1562,15 +1570,25 @@ WintunCreateAdapter( _Out_ WINTUN_ADAPTER **Adapter, _Inout_ BOOL *RebootRequired) { + if (!ElevateToSystem()) + return LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"), ERROR_ACCESS_DENIED; + + DWORD Result = ERROR_SUCCESS; #ifdef MAYBE_WOW64 if (NativeMachine != IMAGE_FILE_PROCESS) - return CreateAdapterNatively(Pool, Name, RequestedGUID, Adapter, RebootRequired); + { + Result = CreateAdapterNatively(Pool, Name, RequestedGUID, Adapter, RebootRequired); + RevertToSelf(); + return Result; + } #endif - DWORD Result = ERROR_SUCCESS; WCHAR RandomTempSubDirectory[MAX_PATH]; if ((Result = CreateTemporaryDirectory(RandomTempSubDirectory)) != ERROR_SUCCESS) - return LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder"), Result; + { + LOG(WINTUN_LOG_ERR, L"Failed to create temporary folder"); + goto cleanupToken; + } WCHAR CatPath[MAX_PATH] = { 0 }; WCHAR SysPath[MAX_PATH] = { 0 }; @@ -1619,6 +1637,8 @@ cleanupDelete: DeleteFileW(InfPath); cleanupDirectory: RemoveDirectoryW(RandomTempSubDirectory); +cleanupToken: + RevertToSelf(); return Result; } @@ -1663,20 +1683,31 @@ cleanupArgv: WINTUN_STATUS WINAPI WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _Inout_ BOOL *RebootRequired) { + if (!ElevateToSystem()) + return LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"), ERROR_ACCESS_DENIED; + + DWORD Result; #ifdef MAYBE_WOW64 if (NativeMachine != IMAGE_FILE_PROCESS) - return DeleteAdapterNatively(Adapter, RebootRequired); + { + Result = DeleteAdapterNatively(Adapter, RebootRequired); + RevertToSelf(); + return Result; + } #endif HDEVINFO DevInfo; SP_DEVINFO_DATA DevInfoData; - DWORD Result = GetDevInfoData(&Adapter->CfgInstanceID, &DevInfo, &DevInfoData); + Result = GetDevInfoData(&Adapter->CfgInstanceID, &DevInfo, &DevInfoData); if (Result == ERROR_FILE_NOT_FOUND) - return ERROR_SUCCESS; - if (Result != ERROR_SUCCESS) + { + Result = ERROR_SUCCESS; + goto cleanupToken; + } + else if (Result != ERROR_SUCCESS) { LOG(WINTUN_LOG_ERR, L"Failed to get device info data"); - return Result; + goto cleanupToken; } SetQuietInstall(DevInfo, &DevInfoData); SP_REMOVEDEVICE_PARAMS RemoveDeviceParams = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), @@ -1689,6 +1720,8 @@ WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _Inout_ BOOL *RebootRequ else Result = LOG_LAST_ERROR(L"Unable to remove existing adapter"); SetupDiDestroyDeviceInfoList(DevInfo); +cleanupToken: + RevertToSelf(); return Result; } diff --git a/api/api.vcxproj b/api/api.vcxproj index 3c7dca7..12ae6ca 100644 --- a/api/api.vcxproj +++ b/api/api.vcxproj @@ -195,6 +195,7 @@ <ClInclude Include="api.h" /> <ClInclude Include="adapter.h" /> <ClInclude Include="atomic.h" /> + <ClInclude Include="elevate.h" /> <ClInclude Include="logger.h" /> <ClInclude Include="namespace.h" /> <ClInclude Include="nci.h" /> @@ -206,6 +207,7 @@ <ItemGroup> <ClCompile Include="api.c" /> <ClCompile Include="adapter.c" /> + <ClCompile Include="elevate.c" /> <ClCompile Include="logger.c" /> <ClCompile Include="namespace.c" /> <ClCompile Include="nci.c" /> diff --git a/api/api.vcxproj.filters b/api/api.vcxproj.filters index e59284e..090a1ef 100644 --- a/api/api.vcxproj.filters +++ b/api/api.vcxproj.filters @@ -55,6 +55,9 @@ <ClInclude Include="atomic.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="elevate.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="api.c"> @@ -87,5 +90,8 @@ <ClCompile Include="session.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="elevate.c"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> </Project>
\ No newline at end of file diff --git a/api/elevate.c b/api/elevate.c new file mode 100644 index 0000000..9baaa97 --- /dev/null +++ b/api/elevate.c @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2018-2020 WireGuard LLC. All Rights Reserved. + */ + +#include "pch.h" + +BOOL +ElevateToSystem(void) +{ + HANDLE CurrentProcessToken, ThreadToken, ProcessSnapshot, WinlogonProcess, WinlogonToken, DuplicatedToken; + PROCESSENTRY32W ProcessEntry = { .dwSize = sizeof(PROCESSENTRY32W) }; + BOOL Ret; + DWORD LastError = ERROR_SUCCESS; + TOKEN_PRIVILEGES Privileges = { .PrivilegeCount = 1, .Privileges = { { .Attributes = SE_PRIVILEGE_ENABLED } } }; + CHAR LocalSystemSid[0x400]; + DWORD RequiredBytes = sizeof(LocalSystemSid); + struct + { + TOKEN_USER MaybeLocalSystem; + CHAR LargeEnoughForLocalSystem[0x400]; + } TokenUserBuffer; + + Ret = CreateWellKnownSid(WinLocalSystemSid, NULL, &LocalSystemSid, &RequiredBytes); + LastError = GetLastError(); + if (!Ret) + goto cleanup; + Ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &CurrentProcessToken); + LastError = GetLastError(); + if (!Ret) + goto cleanup; + Ret = + GetTokenInformation(CurrentProcessToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes); + LastError = GetLastError(); + CloseHandle(CurrentProcessToken); + if (!Ret) + goto cleanup; + if (EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid)) + return TRUE; + Ret = LookupPrivilegeValueW(NULL, SE_DEBUG_NAME, &Privileges.Privileges[0].Luid); + LastError = GetLastError(); + if (!Ret) + goto cleanup; + ProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + LastError = GetLastError(); + if (ProcessSnapshot == INVALID_HANDLE_VALUE) + goto cleanup; + for (Ret = Process32FirstW(ProcessSnapshot, &ProcessEntry); Ret; + Ret = Process32NextW(ProcessSnapshot, &ProcessEntry)) + { + if (_wcsicmp(ProcessEntry.szExeFile, L"winlogon.exe")) + continue; + RevertToSelf(); + Ret = ImpersonateSelf(SecurityImpersonation); + LastError = GetLastError(); + if (!Ret) + continue; + Ret = OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &ThreadToken); + LastError = GetLastError(); + if (!Ret) + continue; + Ret = AdjustTokenPrivileges(ThreadToken, FALSE, &Privileges, sizeof(Privileges), NULL, NULL); + LastError = GetLastError(); + CloseHandle(ThreadToken); + if (!Ret) + continue; + + WinlogonProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ProcessEntry.th32ProcessID); + LastError = GetLastError(); + if (!WinlogonProcess) + continue; + Ret = OpenProcessToken(WinlogonProcess, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &WinlogonToken); + LastError = GetLastError(); + CloseHandle(WinlogonProcess); + if (!Ret) + continue; + Ret = DuplicateToken(WinlogonToken, SecurityImpersonation, &DuplicatedToken); + LastError = GetLastError(); + CloseHandle(WinlogonToken); + if (!Ret) + continue; + if (!GetTokenInformation(DuplicatedToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes)) + goto next; + if (SetLastError(ERROR_ACCESS_DENIED), !EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid)) + goto next; + if (!SetThreadToken(NULL, DuplicatedToken)) + goto next; + CloseHandle(DuplicatedToken); + CloseHandle(ProcessSnapshot); + SetLastError(ERROR_SUCCESS); + return TRUE; + next: + LastError = GetLastError(); + CloseHandle(DuplicatedToken); + } + RevertToSelf(); + CloseHandle(ProcessSnapshot); +cleanup: + SetLastError(LastError); + return FALSE; +} diff --git a/api/elevate.h b/api/elevate.h new file mode 100644 index 0000000..5a3b70c --- /dev/null +++ b/api/elevate.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2018-2020 WireGuard LLC. All Rights Reserved. + */ + +#pragma once + +BOOL +ElevateToSystem(void); @@ -8,6 +8,7 @@ #include "adapter.h" #include "atomic.h" #include "api.h" +#include "elevate.h" #include "logger.h" #include "namespace.h" #include "nci.h" diff --git a/api/rundll32.c b/api/rundll32.c index ae722b5..ac678a5 100644 --- a/api/rundll32.c +++ b/api/rundll32.c @@ -56,101 +56,6 @@ ConsoleLogger(_In_ WINTUN_LOGGER_LEVEL Level, _In_ const WCHAR *LogLine) return TRUE; } -static BOOL -ElevateToSystem(void) -{ - HANDLE CurrentProcessToken, ThreadToken, ProcessSnapshot, WinlogonProcess, WinlogonToken, DuplicatedToken; - PROCESSENTRY32W ProcessEntry = { .dwSize = sizeof(PROCESSENTRY32W) }; - BOOL Ret; - DWORD LastError = ERROR_SUCCESS; - TOKEN_PRIVILEGES Privileges = { .PrivilegeCount = 1, .Privileges = { { .Attributes = SE_PRIVILEGE_ENABLED } } }; - CHAR LocalSystemSid[0x400]; - DWORD RequiredBytes = sizeof(LocalSystemSid); - struct - { - TOKEN_USER MaybeLocalSystem; - CHAR LargeEnoughForLocalSystem[0x400]; - } TokenUserBuffer; - - Ret = CreateWellKnownSid(WinLocalSystemSid, NULL, &LocalSystemSid, &RequiredBytes); - LastError = GetLastError(); - if (!Ret) - goto cleanup; - Ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &CurrentProcessToken); - LastError = GetLastError(); - if (!Ret) - goto cleanup; - Ret = - GetTokenInformation(CurrentProcessToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes); - LastError = GetLastError(); - CloseHandle(CurrentProcessToken); - if (!Ret) - goto cleanup; - if (EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid)) - return TRUE; - Ret = LookupPrivilegeValueW(NULL, SE_DEBUG_NAME, &Privileges.Privileges[0].Luid); - LastError = GetLastError(); - if (!Ret) - goto cleanup; - ProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - LastError = GetLastError(); - if (ProcessSnapshot == INVALID_HANDLE_VALUE) - goto cleanup; - for (Ret = Process32FirstW(ProcessSnapshot, &ProcessEntry); Ret; - Ret = Process32NextW(ProcessSnapshot, &ProcessEntry)) - { - if (_wcsicmp(ProcessEntry.szExeFile, L"winlogon.exe")) - continue; - RevertToSelf(); - Ret = ImpersonateSelf(SecurityImpersonation); - LastError = GetLastError(); - if (!Ret) - continue; - Ret = OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, FALSE, &ThreadToken); - LastError = GetLastError(); - if (!Ret) - continue; - Ret = AdjustTokenPrivileges(ThreadToken, FALSE, &Privileges, sizeof(Privileges), NULL, NULL); - LastError = GetLastError(); - CloseHandle(ThreadToken); - if (!Ret) - continue; - - WinlogonProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ProcessEntry.th32ProcessID); - LastError = GetLastError(); - if (!WinlogonProcess) - continue; - Ret = OpenProcessToken(WinlogonProcess, TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &WinlogonToken); - LastError = GetLastError(); - CloseHandle(WinlogonProcess); - if (!Ret) - continue; - Ret = DuplicateToken(WinlogonToken, SecurityImpersonation, &DuplicatedToken); - LastError = GetLastError(); - CloseHandle(WinlogonToken); - if (!Ret) - continue; - if (!GetTokenInformation(DuplicatedToken, TokenUser, &TokenUserBuffer, sizeof(TokenUserBuffer), &RequiredBytes)) - goto next; - if (SetLastError(ERROR_ACCESS_DENIED), !EqualSid(TokenUserBuffer.MaybeLocalSystem.User.Sid, LocalSystemSid)) - goto next; - if (!SetThreadToken(NULL, DuplicatedToken)) - goto next; - CloseHandle(DuplicatedToken); - CloseHandle(ProcessSnapshot); - SetLastError(ERROR_SUCCESS); - return TRUE; - next: - LastError = GetLastError(); - CloseHandle(DuplicatedToken); - } - RevertToSelf(); - CloseHandle(ProcessSnapshot); -cleanup: - SetLastError(LastError); - return FALSE; -} - static int Argc; static WCHAR **Argv; @@ -159,13 +64,11 @@ Init(void) { WintunSetLogger(ConsoleLogger); Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); - ElevateToSystem(); } static void Done(void) { - RevertToSelf(); LocalFree(Argv); } diff --git a/api/session.c b/api/session.c index 259b1f5..f850c44 100644 --- a/api/session.c +++ b/api/session.c @@ -78,13 +78,19 @@ WintunStartSession(_In_ const WINTUN_ADAPTER *Adapter, _In_ DWORD Capacity, _Out Result = LOG_LAST_ERROR(L"Failed to allocate ring memory"); goto cleanupRings; } + if (!ElevateToSystem()) + { + LOG(WINTUN_LOG_ERR, L"Failed to impersonate SYSTEM user"); + Result = ERROR_ACCESS_DENIED; + goto cleanupAllocatedRegion; + } (*Session)->Descriptor.Send.RingSize = RingSize; (*Session)->Descriptor.Send.Ring = (TUN_RING *)AllocatedRegion; (*Session)->Descriptor.Send.TailMoved = CreateEventW(SecurityAttributes, FALSE, FALSE, NULL); if (!(*Session)->Descriptor.Send.TailMoved) { Result = LOG_LAST_ERROR(L"Failed to create send event"); - goto cleanupAllocatedRegion; + goto cleanupToken; } (*Session)->Descriptor.Receive.RingSize = RingSize; @@ -104,18 +110,19 @@ WintunStartSession(_In_ const WINTUN_ADAPTER *Adapter, _In_ DWORD Capacity, _Out } DWORD BytesReturned; if (!DeviceIoControl( - (*Session)->Handle, - TUN_IOCTL_REGISTER_RINGS, - &(*Session)->Descriptor, - sizeof(TUN_REGISTER_RINGS), - NULL, - 0, - &BytesReturned, + (*Session)->Handle, + TUN_IOCTL_REGISTER_RINGS, + &(*Session)->Descriptor, + sizeof(TUN_REGISTER_RINGS), + NULL, + 0, + &BytesReturned, NULL)) { Result = LOG_LAST_ERROR(L"Failed to perform ioctl"); goto cleanupHandle; } + RevertToSelf(); (*Session)->Capacity = Capacity; (void)InitializeCriticalSectionAndSpinCount(&(*Session)->Receive.Lock, LOCK_SPIN_COUNT); (void)InitializeCriticalSectionAndSpinCount(&(*Session)->Send.Lock, LOCK_SPIN_COUNT); @@ -126,6 +133,8 @@ cleanupReceiveTailMoved: CloseHandle((*Session)->Descriptor.Receive.TailMoved); cleanupSendTailMoved: CloseHandle((*Session)->Descriptor.Send.TailMoved); +cleanupToken: + RevertToSelf(); cleanupAllocatedRegion: VirtualFree(AllocatedRegion, 0, MEM_RELEASE); cleanupRings: @@ -137,7 +146,7 @@ cleanupRings: void WINAPI WintunEndSession(_In_ TUN_SESSION *Session) { - SetEvent(Session->Descriptor.Send.TailMoved); // wake the reader if it's sleeping + SetEvent(Session->Descriptor.Send.TailMoved); // Wake the reader if it's sleeping. DeleteCriticalSection(&Session->Send.Lock); DeleteCriticalSection(&Session->Receive.Lock); CloseHandle(Session->Handle); |