api: add pool/driver removal for uninstaller semantics

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld 2020-11-03 12:27:42 +01:00
parent 0c85a2ebf1
commit 7dede73406
7 changed files with 71 additions and 28 deletions

View File

@ -1750,12 +1750,18 @@ cleanupToken:
} }
static WINTUN_STATUS static WINTUN_STATUS
DeleteAllOurAdapters(void) DeleteAllOurAdapters(_In_ WCHAR Pool[WINTUN_MAX_POOL], _Inout_ BOOL *RebootRequired)
{ {
HANDLE Mutex = NamespaceTakePoolMutex(Pool);
if (!Mutex)
return ERROR_INVALID_HANDLE;
DWORD Result = ERROR_SUCCESS; DWORD Result = ERROR_SUCCESS;
HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL); HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL);
if (DevInfo == INVALID_HANDLE_VALUE) if (DevInfo == INVALID_HANDLE_VALUE)
{
NamespaceReleaseMutex(Mutex);
return LOG_LAST_ERROR(L"Failed to get present adapters"); return LOG_LAST_ERROR(L"Failed to get present adapters");
}
SP_REMOVEDEVICE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER), SP_REMOVEDEVICE_PARAMS Params = { .ClassInstallHeader = { .cbSize = sizeof(SP_CLASSINSTALL_HEADER),
.InstallFunction = DIF_REMOVE }, .InstallFunction = DIF_REMOVE },
.Scope = DI_REMOVEDEVICE_GLOBAL }; .Scope = DI_REMOVEDEVICE_GLOBAL };
@ -1772,39 +1778,58 @@ DeleteAllOurAdapters(void)
BOOL IsOurs; BOOL IsOurs;
if (IsOurAdapter(DevInfo, &DevInfoData, &IsOurs) != ERROR_SUCCESS || !IsOurs) if (IsOurAdapter(DevInfo, &DevInfoData, &IsOurs) != ERROR_SUCCESS || !IsOurs)
continue; continue;
BOOL IsMember;
Result = IsPoolMember(Pool, DevInfo, &DevInfoData, &IsMember);
if (Result != ERROR_SUCCESS)
{
LOG(WINTUN_LOG_ERR, L"Failed to get pool membership");
break;
}
if (!IsMember)
continue;
LOG(WINTUN_LOG_INFO, L"Force closing all open handles for existing adapter"); LOG(WINTUN_LOG_INFO, L"Force closing all open handles for existing adapter");
if (ForceCloseWintunAdapterHandle(DevInfo, &DevInfoData) != ERROR_SUCCESS) if (ForceCloseWintunAdapterHandle(DevInfo, &DevInfoData) != ERROR_SUCCESS)
LOG(WINTUN_LOG_WARN, L"Failed to force close adapter handles"); LOG(WINTUN_LOG_WARN, L"Failed to force close adapter handles");
LOG(WINTUN_LOG_INFO, L"Removing existing adapter"); LOG(WINTUN_LOG_INFO, L"Removing existing adapter");
if (!SetupDiSetClassInstallParamsW(DevInfo, &DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) || if (SetupDiSetClassInstallParamsW(DevInfo, &DevInfoData, &Params.ClassInstallHeader, sizeof(Params)) &&
!SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, &DevInfoData)) SetupDiCallClassInstaller(DIF_REMOVE, DevInfo, &DevInfoData))
*RebootRequired = *RebootRequired || CheckReboot(DevInfo, &DevInfoData);
else
{ {
LOG_LAST_ERROR(L"Failed to remove existing adapter"); LOG_LAST_ERROR(L"Failed to remove existing adapter");
Result = Result != ERROR_SUCCESS ? Result : GetLastError(); Result = Result != ERROR_SUCCESS ? Result : GetLastError();
} }
} }
SetupDiDestroyDeviceInfoList(DevInfo); SetupDiDestroyDeviceInfoList(DevInfo);
NamespaceReleaseMutex(Mutex);
return Result; return Result;
} }
WINTUN_STATUS WINAPI WINTUN_STATUS WINAPI
WintunDeleteDriver(void) WintunDeletePoolDriver(_In_z_ WCHAR Pool[WINTUN_MAX_POOL], _Out_opt_ BOOL *RebootRequired)
{ {
if (!ElevateToSystem()) if (!ElevateToSystem())
return LOG_LAST_ERROR(L"Failed to impersonate SYSTEM user"); return LOG_LAST_ERROR(L"Failed to impersonate SYSTEM user");
DWORD Result = ERROR_SUCCESS; BOOL DummyRebootRequired;
if (!RebootRequired)
RebootRequired = &DummyRebootRequired;
*RebootRequired = FALSE;
DWORD Result;
if (MAYBE_WOW64 && NativeMachine != IMAGE_FILE_PROCESS) if (MAYBE_WOW64 && NativeMachine != IMAGE_FILE_PROCESS)
{ {
Result = DeleteDriverViaRundll32(); Result = DeletePoolDriverViaRundll32(Pool, RebootRequired);
RevertToSelf(); RevertToSelf();
return Result; return Result;
} }
/* DeleteAllOurAdapters(); */ Result = DeleteAllOurAdapters(Pool, RebootRequired);
if (Result != ERROR_SUCCESS)
goto cleanupToken;
HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex(); HANDLE DriverInstallationLock = NamespaceTakeDriverInstallationMutex();
if (!DriverInstallationLock) if (!DriverInstallationLock)
{ {
@ -1837,7 +1862,7 @@ WintunDeleteDriver(void)
if (!_wcsicmp(DriverDetail->HardwareID, WINTUN_HWID)) if (!_wcsicmp(DriverDetail->HardwareID, WINTUN_HWID))
{ {
LOG(WINTUN_LOG_INFO, TEXT("Removing existing driver")); LOG(WINTUN_LOG_INFO, TEXT("Removing existing driver"));
if (!SetupUninstallOEMInfW(PathFindFileNameW(DriverDetail->InfFileName), SUOI_FORCEDELETE, NULL)) if (!SetupUninstallOEMInfW(PathFindFileNameW(DriverDetail->InfFileName), 0, NULL))
{ {
LOG_LAST_ERROR(TEXT("Unable to remove existing driver")); LOG_LAST_ERROR(TEXT("Unable to remove existing driver"));
Result = Result != ERROR_SUCCESS ? Result : GetLastError(); Result = Result != ERROR_SUCCESS ? Result : GetLastError();

View File

@ -58,7 +58,7 @@ WINTUN_STATUS WINAPI
WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _In_ BOOL ForceCloseSessions, _Out_opt_ BOOL *RebootRequired); WintunDeleteAdapter(_In_ const WINTUN_ADAPTER *Adapter, _In_ BOOL ForceCloseSessions, _Out_opt_ BOOL *RebootRequired);
/** /**
* @copydoc WINTUN_DELETE_DRIVER_FUNC * @copydoc WINTUN_DELETE_POOL_DRIVER_FUNC
*/ */
WINTUN_STATUS WINAPI WINTUN_STATUS WINAPI
WintunDeleteDriver(void); WintunDeletePoolDriver(_In_z_ WCHAR Pool[WINTUN_MAX_POOL], _Out_opt_ BOOL *RebootRequired);

View File

@ -3,7 +3,7 @@ EXPORTS
WintunAllocateSendPacket WintunAllocateSendPacket
WintunCreateAdapter WintunCreateAdapter
WintunDeleteAdapter WintunDeleteAdapter
WintunDeleteDriver WintunDeletePoolDriver
WintunEndSession WintunEndSession
WintunEnumAdapters WintunEnumAdapters
WintunFreeAdapter WintunFreeAdapter

View File

@ -131,12 +131,19 @@ cleanup:
Done(); Done();
} }
VOID __stdcall DeleteDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) VOID __stdcall DeletePoolDriver(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{ {
# pragma EXPORT # pragma EXPORT
Init(); Init();
WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X!", WintunDeleteDriver()); if (Argc < 2)
goto cleanup;
BOOL RebootRequired;
WINTUN_STATUS Ret = WintunDeletePoolDriver(Argv[2], &RebootRequired);
WriteFormatted(STD_OUTPUT_HANDLE, L"%1!X! %2!X!", Ret, RebootRequired);
cleanup:
Done(); Done();
} }
#endif #endif

View File

@ -306,11 +306,15 @@ cleanupArgv:
} }
static WINTUN_STATUS static WINTUN_STATUS
DeleteDriverViaRundll32() DeletePoolDriverViaRundll32(_In_z_ WCHAR Pool[WINTUN_MAX_POOL], _Inout_ BOOL *RebootRequired)
{ {
LOG(WINTUN_LOG_INFO, L"Spawning native process"); LOG(WINTUN_LOG_INFO, L"Spawning native process");
WCHAR Response[8 + 1];
DWORD Result = ExecuteRunDll32(L"DeleteDriver", Response, _countof(Response)); WCHAR Arguments[17 + WINTUN_MAX_POOL + 1];
if (_snwprintf_s(Arguments, _countof(Arguments), _TRUNCATE, L"DeletePoolDriver %s", Pool) == -1)
return LOG(WINTUN_LOG_ERR, L"Command line too long"), ERROR_INVALID_PARAMETER;
WCHAR Response[8 + 1 + 8 + 1];
DWORD Result = ExecuteRunDll32(Arguments, Response, _countof(Response));
if (Result != ERROR_SUCCESS) if (Result != ERROR_SUCCESS)
{ {
LOG(WINTUN_LOG_ERR, L"Error executing worker process"); LOG(WINTUN_LOG_ERR, L"Error executing worker process");
@ -318,13 +322,15 @@ DeleteDriverViaRundll32()
} }
int Argc; int Argc;
WCHAR **Argv = CommandLineToArgvW(Response, &Argc); WCHAR **Argv = CommandLineToArgvW(Response, &Argc);
if (Argc < 1) if (Argc < 2)
{ {
LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response"); LOG(WINTUN_LOG_ERR, L"Incomplete or invalid response");
Result = ERROR_INVALID_PARAMETER; Result = ERROR_INVALID_PARAMETER;
goto cleanupArgv; goto cleanupArgv;
} }
Result = wcstoul(Argv[0], NULL, 16); Result = wcstoul(Argv[0], NULL, 16);
if (wcstoul(Argv[1], NULL, 16))
*RebootRequired = TRUE;
cleanupArgv: cleanupArgv:
LocalFree(Argv); LocalFree(Argv);
return Result; return Result;

View File

@ -33,7 +33,7 @@ typedef void *WINTUN_ADAPTER_HANDLE;
* @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1 * @param Name The requested name of the adapter. Zero-terminated string of up to MAX_ADAPTER_NAME-1
* characters. * characters.
* *
* @param RequestedGUID The GUID of the created network adapter, which then influences NLA generation * @param RequestedGUID The GUID of the created network adapter, which then influences NLA generation
* deterministically. If it is set to NULL, the GUID is chosen by the system at random, and hence * deterministically. If it is set to NULL, the GUID is chosen by the system at random, and hence
* a new NLA entry is created for each new adapter. It is called "requested" GUID because the API * a new NLA entry is created for each new adapter. It is called "requested" GUID because the API
* it uses is completely undocumented, and so there could be minor interesting complications with * it uses is completely undocumented, and so there could be minor interesting complications with
@ -72,11 +72,18 @@ typedef WINTUN_STATUS(WINAPI *WINTUN_DELETE_ADAPTER_FUNC)(
_Out_opt_ BOOL *RebootRequired); _Out_opt_ BOOL *RebootRequired);
/** /**
* Deletes all Wintun drivers from the driver store * Deletes all Wintun adapters in a pool and if there are no more adapters in any other pools, also removes Wintun
* from the driver store, usually called by uninstallers.
*
* @param Pool Name of the adapter pool. Zero-terminated string of up to WINTUN_MAX_POOL-1 characters.
*
* @param RebootRequired Optional pointer to a boolean flag to be set to TRUE in case SetupAPI suggests a reboot.
* *
* @return ERROR_SUCCESS on success; Win32 error code otherwise. * @return ERROR_SUCCESS on success; Win32 error code otherwise.
*/ */
typedef WINTUN_STATUS(WINAPI *WINTUN_DELETE_DRIVER_FUNC)(void); typedef WINTUN_STATUS(WINAPI *WINTUN_DELETE_POOL_DRIVER_FUNC)(
_In_z_ WCHAR Pool[WINTUN_MAX_POOL],
_Out_opt_ BOOL *RebootRequired);
/** /**
* Called by WintunEnumAdapters for each adapter in the pool. * Called by WintunEnumAdapters for each adapter in the pool.

View File

@ -14,7 +14,7 @@
static WINTUN_CREATE_ADAPTER_FUNC WintunCreateAdapter; static WINTUN_CREATE_ADAPTER_FUNC WintunCreateAdapter;
static WINTUN_DELETE_ADAPTER_FUNC WintunDeleteAdapter; static WINTUN_DELETE_ADAPTER_FUNC WintunDeleteAdapter;
static WINTUN_DELETE_DRIVER_FUNC WintunDeleteDriver; static WINTUN_DELETE_POOL_DRIVER_FUNC WintunDeletePoolDriver;
static WINTUN_ENUM_ADAPTERS_FUNC WintunEnumAdapters; static WINTUN_ENUM_ADAPTERS_FUNC WintunEnumAdapters;
static WINTUN_FREE_ADAPTER_FUNC WintunFreeAdapter; static WINTUN_FREE_ADAPTER_FUNC WintunFreeAdapter;
static WINTUN_GET_ADAPTER_FUNC WintunGetAdapter; static WINTUN_GET_ADAPTER_FUNC WintunGetAdapter;
@ -258,8 +258,9 @@ InitializeWintun(void)
return NULL; return NULL;
#define X(Name, Type) ((Name = (Type)GetProcAddress(Wintun, #Name)) == NULL) #define X(Name, Type) ((Name = (Type)GetProcAddress(Wintun, #Name)) == NULL)
if (X(WintunCreateAdapter, WINTUN_CREATE_ADAPTER_FUNC) || X(WintunDeleteAdapter, WINTUN_DELETE_ADAPTER_FUNC) || if (X(WintunCreateAdapter, WINTUN_CREATE_ADAPTER_FUNC) || X(WintunDeleteAdapter, WINTUN_DELETE_ADAPTER_FUNC) ||
X(WintunDeleteDriver, WINTUN_DELETE_DRIVER_FUNC) || X(WintunEnumAdapters, WINTUN_ENUM_ADAPTERS_FUNC) || X(WintunDeletePoolDriver, WINTUN_DELETE_POOL_DRIVER_FUNC) ||
X(WintunFreeAdapter, WINTUN_FREE_ADAPTER_FUNC) || X(WintunGetAdapter, WINTUN_GET_ADAPTER_FUNC) || X(WintunEnumAdapters, WINTUN_ENUM_ADAPTERS_FUNC) || X(WintunFreeAdapter, WINTUN_FREE_ADAPTER_FUNC) ||
X(WintunGetAdapter, WINTUN_GET_ADAPTER_FUNC) ||
X(WintunGetAdapterDeviceObject, WINTUN_GET_ADAPTER_DEVICE_OBJECT_FUNC) || X(WintunGetAdapterDeviceObject, WINTUN_GET_ADAPTER_DEVICE_OBJECT_FUNC) ||
X(WintunGetAdapterGUID, WINTUN_GET_ADAPTER_GUID_FUNC) || X(WintunGetAdapterGUID, WINTUN_GET_ADAPTER_GUID_FUNC) ||
X(WintunGetAdapterLUID, WINTUN_GET_ADAPTER_LUID_FUNC) || X(WintunGetAdapterLUID, WINTUN_GET_ADAPTER_LUID_FUNC) ||
@ -315,17 +316,14 @@ main(void)
} }
DWORD Version = WintunGetVersion(); DWORD Version = WintunGetVersion();
Log(WINTUN_LOG_INFO, Log(WINTUN_LOG_INFO, L"Wintun v%u.%u loaded", (Version >> 16) & 0xff, (Version >> 0) & 0xff);
L"Wintun v%u.%u loaded",
(Version >> 16) & 0xff,
(Version >> 0) & 0xff);
MIB_UNICASTIPADDRESS_ROW AddressRow; MIB_UNICASTIPADDRESS_ROW AddressRow;
InitializeUnicastIpAddressEntry(&AddressRow); InitializeUnicastIpAddressEntry(&AddressRow);
WintunGetAdapterLUID(Adapter, &AddressRow.InterfaceLuid); WintunGetAdapterLUID(Adapter, &AddressRow.InterfaceLuid);
AddressRow.Address.Ipv4.sin_family = AF_INET; AddressRow.Address.Ipv4.sin_family = AF_INET;
AddressRow.Address.Ipv4.sin_addr.S_un.S_addr = htonl((10 << 24) | (6 << 16) | (7 << 8) | (7 << 0)); /* 10.6.7.7 */ AddressRow.Address.Ipv4.sin_addr.S_un.S_addr = htonl((10 << 24) | (6 << 16) | (7 << 8) | (7 << 0)); /* 10.6.7.7 */
AddressRow.OnLinkPrefixLength = 24; /* This is a /24 network */ AddressRow.OnLinkPrefixLength = 24; /* This is a /24 network */
Result = CreateUnicastIpAddressEntry(&AddressRow); Result = CreateUnicastIpAddressEntry(&AddressRow);
if (Result != ERROR_SUCCESS) if (Result != ERROR_SUCCESS)
{ {