aboutsummaryrefslogtreecommitdiffstats
path: root/api/driver.c
diff options
context:
space:
mode:
authorSimon Rozman <simon@rozman.si>2020-10-15 15:54:37 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2020-10-30 16:51:00 +0100
commitd04721dee692ea5ad481419e9104111084d3431c (patch)
tree79d7dcc370d34d3a9984a6c95a8d9eb85eb3cdcc /api/driver.c
parentapi: unify security descriptors and disable for _DEBUG (diff)
downloadwintun-d04721dee692ea5ad481419e9104111084d3431c.tar.xz
wintun-d04721dee692ea5ad481419e9104111084d3431c.zip
api: test the temporary driver idea
1. Add driver to the store: SetupCopyOEMInfW() 2. Create the adapter using explicit path to .inf file: DI_ENUMSINGLEINF 3. Delete all Wintun drivers from the store. This is a subject of further research: - It appears those adapters survive a reboot. So, Windows must store the driver somewhere on the disk and the driver removal is not completed. If the driver removal is not completed until there are existing adapters, this is excellent, as it will provide a self-cleanup. - Test multiple adapters with different driver versions. Which driver wins? - Are other Wintun adapters interrupted when adding a new one? - Test Windows 7 behaviour. Signed-off-by: Simon Rozman <simon@rozman.si>
Diffstat (limited to 'api/driver.c')
-rw-r--r--api/driver.c378
1 files changed, 1 insertions, 377 deletions
diff --git a/api/driver.c b/api/driver.c
index fffd445..f57c36b 100644
--- a/api/driver.c
+++ b/api/driver.c
@@ -26,330 +26,7 @@ DriverIsOurDrvInfoDetail(_In_ const SP_DRVINFO_DETAIL_DATA_W *DrvInfoDetailData)
#if defined(HAVE_EV) || defined(HAVE_WHQL)
-/* We can't use RtlGetVersion, because appcompat's aclayers.dll shims it to report Vista
- * when run from legacy contexts. So, we instead use the undocumented RtlGetNtVersionNumbers.
- *
- * Another way would be reading from the PEB directly:
- * ((DWORD *)NtCurrentTeb()->ProcessEnvironmentBlock)[sizeof(void *) == 8 ? 70 : 41]
- * Or just read from KUSER_SHARED_DATA the same way on 32-bit and 64-bit:
- * *(DWORD *)0x7FFE026C
- */
-extern VOID NTAPI
-RtlGetNtVersionNumbers(_Out_opt_ DWORD *MajorVersion, _Out_opt_ DWORD *MinorVersion, _Out_opt_ DWORD *BuildNumber);
-
-static BOOL
-HaveWHQL()
-{
-# if defined(HAVE_EV) && defined(HAVE_WHQL)
- DWORD MajorVersion;
- RtlGetNtVersionNumbers(&MajorVersion, NULL, NULL);
- return MajorVersion >= 10;
-# elif defined(HAVE_EV)
- return FALSE;
-# elif defined(HAVE_WHQL)
- return TRUE;
-# endif
-}
-
-static const CHAR *
-SkipWSpace(_In_ const CHAR *Beg, _In_ const CHAR *End)
-{
- for (; Beg < End && iswspace(*Beg); ++Beg)
- ;
- return Beg;
-}
-
-static const CHAR *
-SkipNonLF(_In_ const CHAR *Beg, _In_ const CHAR *End)
-{
- for (; Beg < End && *Beg != '\n'; ++Beg)
- ;
- return Beg;
-}
-
-WINTUN_STATUS
-DriverGetVersion(_Out_ FILETIME *DriverDate, _Out_ DWORDLONG *DriverVersion)
-{
- const VOID *LockedResource;
- DWORD SizeResource;
- DWORD Result = ResourceGetAddress(HaveWHQL() ? L"wintun-whql.inf" : L"wintun.inf", &LockedResource, &SizeResource);
- if (Result != ERROR_SUCCESS)
- return LOG(WINTUN_LOG_ERR, L"Failed to locate resource"), Result;
- enum
- {
- SectNone,
- SectUnknown,
- SectVersion
- } Section = SectNone;
- for (const CHAR *Inf = (const CHAR *)LockedResource, *InfEnd = Inf + SizeResource; Inf < InfEnd; ++Inf)
- {
- if (*Inf == ';')
- {
- Inf = SkipNonLF(Inf + 1, InfEnd);
- continue;
- }
- Inf = SkipWSpace(Inf, InfEnd);
- if (*Inf == '[')
- {
- Section = Inf + 9 <= InfEnd && !_strnicmp(Inf, "[Version]", 9) ? SectVersion : SectUnknown;
- }
- else if (Section == SectVersion)
- {
- if (Inf + 9 <= InfEnd && !_strnicmp(Inf, "DriverVer", 9))
- {
- Inf = SkipWSpace(Inf + 9, InfEnd);
- if (Inf < InfEnd && *Inf == '=')
- {
- Inf = SkipWSpace(Inf + 1, InfEnd);
- /* Duplicate buffer, as RT_RCDATA resource is not guaranteed to be zero-terminated. */
- CHAR buf[0x100];
- size_t n = InfEnd - Inf;
- if (n >= _countof(buf))
- n = _countof(buf) - 1;
- strncpy_s(buf, _countof(buf), Inf, n);
- buf[n] = 0;
- const CHAR *p = buf;
- CHAR *p_next;
- unsigned long date[3] = { 0, 0, 0 };
- for (size_t i = 0;; ++i, ++p)
- {
- date[i] = strtoul(p, &p_next, 10);
- p = p_next;
- if (i >= _countof(date) - 1)
- break;
- if (*p != '/' && *p != '-')
- {
- LOG(WINTUN_LOG_ERR, L"Unexpected date delimiter");
- return ERROR_INVALID_DATA;
- }
- }
- if (date[0] < 1 || date[0] > 12 || date[1] < 1 || date[1] > 31 || date[2] < 1601 || date[2] > 30827)
- {
- LOG(WINTUN_LOG_ERR, L"Invalid date");
- return ERROR_INVALID_DATA;
- }
- const SYSTEMTIME st = { .wYear = (WORD)date[2], .wMonth = (WORD)date[0], .wDay = (WORD)date[1] };
- SystemTimeToFileTime(&st, DriverDate);
- p = SkipWSpace(p, buf + n);
- ULONGLONG version[4] = { 0, 0, 0, 0 };
- if (*p == ',')
- {
- p = SkipWSpace(p + 1, buf + n);
- for (size_t i = 0;; ++i, ++p)
- {
- version[i] = strtoul(p, &p_next, 10);
- if (version[i] > 0xffff)
- {
- LOG(WINTUN_LOG_ERR, L"Version field may not exceed 65535");
- return ERROR_INVALID_DATA;
- }
- p = p_next;
- if (i >= _countof(version) - 1 || !*p || *p == ';' || iswspace(*p))
- break;
- if (*p != '.')
- {
- LOG(WINTUN_LOG_ERR, L"Unexpected version delimiter");
- return ERROR_INVALID_DATA;
- }
- }
- }
- *DriverVersion = (version[0] << 48) | (version[1] << 32) | (version[2] << 16) | version[3];
- return ERROR_SUCCESS;
- }
- }
- }
- Inf = SkipNonLF(Inf, InfEnd);
- }
- LOG(WINTUN_LOG_ERR, L"DriverVer not found in INF resource");
- return ERROR_FILE_NOT_FOUND;
-}
-
-/* This function does not log any errors, not to flood the log when called from the EnsureDriverUnloaded() loop. */
-static BOOL IsDriverLoaded(VOID)
-{
- VOID *StackBuffer[0x80];
- VOID **Drivers = StackBuffer;
- DWORD Size = 0;
- if (!EnumDeviceDrivers(Drivers, sizeof(StackBuffer), &Size))
- return FALSE;
- if (Size > sizeof(StackBuffer))
- {
- HANDLE Heap = GetProcessHeap();
- Drivers = HeapAlloc(Heap, 0, Size);
- if (!Drivers)
- {
- SetLastError(ERROR_OUTOFMEMORY);
- return FALSE;
- }
- if (!EnumDeviceDrivers(Drivers, Size, &Size))
- {
- DWORD Result = GetLastError();
- HeapFree(Heap, 0, Drivers);
- SetLastError(Result);
- return FALSE;
- }
- }
- BOOL Found = FALSE;
- for (DWORD i = Size / sizeof(Drivers[0]); i-- > 0;)
- {
- WCHAR MaybeWintun[11];
- if (GetDeviceDriverBaseNameW(Drivers[i], MaybeWintun, _countof(MaybeWintun)) == 10 &&
- !_wcsicmp(MaybeWintun, L"wintun.sys"))
- {
- Found = TRUE;
- break;
- }
- }
- if (Drivers != StackBuffer)
- HeapFree(GetProcessHeap(), 0, Drivers);
- SetLastError(ERROR_SUCCESS);
- return Found;
-}
-
-static BOOL EnsureDriverUnloaded(VOID)
-{
- BOOL Loaded;
- for (int i = 0; (Loaded = IsDriverLoaded()) != 0 && i < 300; ++i)
- Sleep(50);
- return !Loaded;
-}
-
-static WINTUN_STATUS
-InstallCertificate(_In_z_ const WCHAR *SignedResource)
-{
- LOG(WINTUN_LOG_INFO, L"Trusting code signing certificate");
- const VOID *LockedResource;
- DWORD SizeResource;
- DWORD Result = ResourceGetAddress(SignedResource, &LockedResource, &SizeResource);
- if (Result != ERROR_SUCCESS)
- return LOG(WINTUN_LOG_ERR, L"Failed to locate resource"), Result;
- const CERT_BLOB CertBlob = { .cbData = SizeResource, .pbData = (BYTE *)LockedResource };
- HCERTSTORE QueriedStore;
- if (!CryptQueryObject(
- CERT_QUERY_OBJECT_BLOB,
- &CertBlob,
- CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
- CERT_QUERY_FORMAT_FLAG_ALL,
- 0,
- 0,
- 0,
- 0,
- &QueriedStore,
- 0,
- NULL))
- return LOG_LAST_ERROR(L"Failed to find certificate");
- HCERTSTORE TrustedStore =
- CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"TrustedPublisher");
- if (!TrustedStore)
- {
- Result = LOG_LAST_ERROR(L"Failed to open store");
- goto cleanupQueriedStore;
- }
- LPSTR CodeSigningOid[] = { szOID_PKIX_KP_CODE_SIGNING };
- CERT_ENHKEY_USAGE EnhancedUsage = { .cUsageIdentifier = 1, .rgpszUsageIdentifier = CodeSigningOid };
- for (const CERT_CONTEXT *CertContext = NULL; (CertContext = CertFindCertificateInStore(
- QueriedStore,
- X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
- CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
- CERT_FIND_ENHKEY_USAGE,
- &EnhancedUsage,
- CertContext)) != NULL;)
- {
- CERT_EXTENSION *Ext = CertFindExtension(
- szOID_BASIC_CONSTRAINTS2, CertContext->pCertInfo->cExtension, CertContext->pCertInfo->rgExtension);
- CERT_BASIC_CONSTRAINTS2_INFO Constraints;
- DWORD Size = sizeof(Constraints);
- if (Ext &&
- CryptDecodeObjectEx(
- X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
- szOID_BASIC_CONSTRAINTS2,
- Ext->Value.pbData,
- Ext->Value.cbData,
- 0,
- NULL,
- &Constraints,
- &Size) &&
- !Constraints.fCA)
- if (!CertAddCertificateContextToStore(TrustedStore, CertContext, CERT_STORE_ADD_REPLACE_EXISTING, NULL))
- {
- LOG_LAST_ERROR(L"Failed to add certificate to store");
- Result = Result != ERROR_SUCCESS ? Result : GetLastError();
- }
- }
- CertCloseStore(TrustedStore, 0);
-cleanupQueriedStore:
- CertCloseStore(QueriedStore, 0);
- return Result;
-}
-
-static WINTUN_STATUS
-InstallDriver(_In_ BOOL UpdateExisting)
-{
- WCHAR WindowsDirectory[MAX_PATH];
- if (!GetWindowsDirectoryW(WindowsDirectory, _countof(WindowsDirectory)))
- return LOG_LAST_ERROR(L"Failed to get Windows folder");
- WCHAR WindowsTempDirectory[MAX_PATH];
- if (!PathCombineW(WindowsTempDirectory, WindowsDirectory, L"Temp"))
- return ERROR_BUFFER_OVERFLOW;
- UCHAR RandomBytes[32] = { 0 };
-# pragma warning(suppress : 6387)
- if (!RtlGenRandom(RandomBytes, sizeof(RandomBytes)))
- return LOG_LAST_ERROR(L"Failed to generate random");
- WCHAR RandomSubDirectory[sizeof(RandomBytes) * 2 + 1];
- for (int i = 0; i < sizeof(RandomBytes); ++i)
- swprintf_s(&RandomSubDirectory[i * 2], 3, L"%02x", RandomBytes[i]);
- WCHAR RandomTempSubDirectory[MAX_PATH];
- if (!PathCombineW(RandomTempSubDirectory, WindowsTempDirectory, RandomSubDirectory))
- return ERROR_BUFFER_OVERFLOW;
- if (!CreateDirectoryW(RandomTempSubDirectory, SecurityAttributes))
- return LOG_LAST_ERROR(L"Failed to create temporary folder");
-
- DWORD Result = ERROR_SUCCESS;
- WCHAR CatPath[MAX_PATH] = { 0 };
- WCHAR SysPath[MAX_PATH] = { 0 };
- WCHAR InfPath[MAX_PATH] = { 0 };
- if (!PathCombineW(CatPath, RandomTempSubDirectory, L"wintun.cat") ||
- !PathCombineW(SysPath, RandomTempSubDirectory, L"wintun.sys") ||
- !PathCombineW(InfPath, RandomTempSubDirectory, L"wintun.inf"))
- {
- Result = ERROR_BUFFER_OVERFLOW;
- goto cleanupDirectory;
- }
-
- BOOL UseWHQL = HaveWHQL();
- if (!UseWHQL && (Result = InstallCertificate(L"wintun.sys")) != ERROR_SUCCESS)
- LOG(WINTUN_LOG_WARN, L"Unable to install code signing certificate");
-
- LOG(WINTUN_LOG_INFO, L"Copying resources to temporary path");
- if ((Result = ResourceCopyToFile(CatPath, UseWHQL ? L"wintun-whql.cat" : L"wintun.cat")) != ERROR_SUCCESS ||
- (Result = ResourceCopyToFile(SysPath, UseWHQL ? L"wintun-whql.sys" : L"wintun.sys")) != ERROR_SUCCESS ||
- (Result = ResourceCopyToFile(InfPath, UseWHQL ? L"wintun-whql.inf" : L"wintun.inf")) != ERROR_SUCCESS)
- {
- LOG(WINTUN_LOG_ERR, L"Failed to copy resources");
- goto cleanupDelete;
- }
-
- LOG(WINTUN_LOG_INFO, L"Installing driver");
- if (!SetupCopyOEMInfW(InfPath, NULL, SPOST_PATH, 0, NULL, 0, NULL, NULL))
- Result = LOG_LAST_ERROR(L"Could not install driver to store");
- BOOL RebootRequired = FALSE;
- if (UpdateExisting &&
- !UpdateDriverForPlugAndPlayDevicesW(
- NULL, WINTUN_HWID, InfPath, INSTALLFLAG_FORCE | INSTALLFLAG_NONINTERACTIVE, &RebootRequired))
- LOG_LAST_ERROR(L"Could not update existing adapters");
- if (RebootRequired)
- LOG(WINTUN_LOG_WARN, L"A reboot might be required, which really should not be the case");
-
-cleanupDelete:
- DeleteFileW(CatPath);
- DeleteFileW(SysPath);
- DeleteFileW(InfPath);
-cleanupDirectory:
- RemoveDirectoryW(RandomTempSubDirectory);
- return Result;
-}
-
-static WINTUN_STATUS RemoveDriver(VOID)
+WINTUN_STATUS DriverRemoveAllOurs(VOID)
{
HDEVINFO DevInfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_NET, NULL, NULL, 0);
if (!DevInfo)
@@ -396,57 +73,4 @@ cleanupDeviceInfoSet:
return Result;
}
-WINTUN_STATUS DriverInstallOrUpdate(VOID)
-{
- HANDLE Heap = GetProcessHeap();
- HDEVINFO DevInfo = SetupDiGetClassDevsExW(&GUID_DEVCLASS_NET, NULL, NULL, DIGCF_PRESENT, NULL, NULL, NULL);
- if (DevInfo == INVALID_HANDLE_VALUE)
- return LOG_LAST_ERROR(L"Failed to get present class devices");
- SP_DEVINFO_DATA_LIST *ExistingAdapters = NULL;
- if (IsDriverLoaded())
- {
- AdapterDisableAllOurs(DevInfo, &ExistingAdapters);
- LOG(WINTUN_LOG_INFO, L"Waiting for driver to unload from kernel");
- if (!EnsureDriverUnloaded())
- LOG(WINTUN_LOG_WARN, L"Unable to unload driver, which means a reboot will likely be required");
- }
- DWORD Result = ERROR_SUCCESS;
- if ((Result = RemoveDriver()) != ERROR_SUCCESS)
- {
- LOG(WINTUN_LOG_ERR, L"Failed to uninstall old drivers");
- goto cleanupAdapters;
- }
- if ((Result = InstallDriver(!!ExistingAdapters)) != ERROR_SUCCESS)
- {
- LOG(WINTUN_LOG_ERR, L"Failed to install driver");
- goto cleanupAdapters;
- }
- LOG(WINTUN_LOG_INFO, L"Installation successful");
-
-cleanupAdapters:;
- if (ExistingAdapters)
- {
- AdapterEnableAll(DevInfo, ExistingAdapters);
- while (ExistingAdapters)
- {
- SP_DEVINFO_DATA_LIST *Next = ExistingAdapters->Next;
- HeapFree(Heap, 0, ExistingAdapters);
- ExistingAdapters = Next;
- }
- }
- SetupDiDestroyDeviceInfoList(DevInfo);
- return Result;
-}
-
-WINTUN_STATUS DriverUninstall(VOID)
-{
- AdapterDeleteAllOurs();
- DWORD Result = RemoveDriver();
- if (Result == ERROR_SUCCESS)
- LOG(WINTUN_LOG_INFO, L"Uninstallation successful");
- else
- LOG(WINTUN_LOG_ERR, L"Failed to uninstall driver");
- return Result;
-}
-
#endif