From: "Rémi Bernon" Subject: [PATCH v3 1/3] ntoskrnl.exe/tests: Move driver testing helpers to a separate file. Message-Id: <20210830105711.1482802-1-rbernon@codeweavers.com> Date: Mon, 30 Aug 2021 12:57:09 +0200 Signed-off-by: Rémi Bernon --- v3: Add a check that the service is started as it should be, or consider that the machine doesn't support test signed drivers. According to https://testbot.winehq.org/JobDetails.pl?Key=96764 it should be fine now. dlls/ntoskrnl.exe/tests/driver_tests.h | 577 ++++++++++++++++++++++ dlls/ntoskrnl.exe/tests/ntoskrnl.c | 632 +------------------------ 2 files changed, 595 insertions(+), 614 deletions(-) create mode 100644 dlls/ntoskrnl.exe/tests/driver_tests.h diff --git a/dlls/ntoskrnl.exe/tests/driver_tests.h b/dlls/ntoskrnl.exe/tests/driver_tests.h new file mode 100644 index 00000000000..b3a25e4d563 --- /dev/null +++ b/dlls/ntoskrnl.exe/tests/driver_tests.h @@ -0,0 +1,577 @@ +/* + * ntoskrnl.exe testing framework + * + * Copyright 2015 Sebastian Lackner + * Copyright 2015 Michael Müller + * Copyright 2015 Christian Costa + * Copyright 2020-2021 Zebediah Figura for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winioctl.h" +#include "winternl.h" +#include "winuser.h" +#include "winnls.h" +#include "winsvc.h" +#include "winreg.h" +#include "wincrypt.h" + +#include "mscat.h" +#include "newdev.h" +#include "ntsecapi.h" +#include "objbase.h" +#include "setupapi.h" + +#include "wine/mssign.h" +#include "wine/test.h" + +#include "driver.h" + +static HANDLE test_data_mapping; +static struct test_data *test_data; + +static HRESULT (WINAPI *pSignerSign)(SIGNER_SUBJECT_INFO *subject, SIGNER_CERT *cert, + SIGNER_SIGNATURE_INFO *signature, SIGNER_PROVIDER_INFO *provider, + const WCHAR *timestamp, CRYPT_ATTRIBUTES *attr, void *sip_data); + +#define load_resource (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : load_resource_ +static void load_resource_(const WCHAR *name, WCHAR *filename) +{ + static WCHAR path[MAX_PATH]; + DWORD written; + HANDLE file; + HRSRC res; + void *ptr; + + GetTempPathW(ARRAY_SIZE(path), path); + GetTempFileNameW(path, name, 0, filename); + + file = CreateFileW(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + winetest_ok(file != INVALID_HANDLE_VALUE, "failed to create %s, error %u\n", debugstr_w(filename), GetLastError()); + + res = FindResourceW(NULL, name, L"TESTDLL"); + winetest_ok( res != 0, "couldn't find resource\n" ); + ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res )); + WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL ); + winetest_ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" ); + CloseHandle( file ); +} + +struct testsign_context +{ + HCRYPTPROV provider; + const CERT_CONTEXT *cert, *root_cert, *publisher_cert; + HCERTSTORE root_store, publisher_store; +}; + +static BOOL testsign_create_cert(struct testsign_context *ctx) +{ + BYTE encoded_name[100], encoded_key_id[200], public_key_info_buffer[1000]; + WCHAR container_name[26]; + BYTE hash_buffer[16], cert_buffer[1000], provider_nameA[100], serial[16]; + CERT_PUBLIC_KEY_INFO *public_key_info = (CERT_PUBLIC_KEY_INFO *)public_key_info_buffer; + CRYPT_KEY_PROV_INFO provider_info = {0}; + CRYPT_ALGORITHM_IDENTIFIER algid = {0}; + CERT_AUTHORITY_KEY_ID_INFO key_info; + CERT_INFO cert_info = {0}; + WCHAR provider_nameW[100]; + CERT_EXTENSION extension; + HCRYPTKEY key; + DWORD size; + BOOL ret; + + memset(ctx, 0, sizeof(*ctx)); + + srand(time(NULL)); + swprintf(container_name, ARRAY_SIZE(container_name), L"wine_testsign%u", rand()); + + ret = CryptAcquireContextW(&ctx->provider, container_name, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET); + winetest_ok(ret, "Failed to create container, error %#x\n", GetLastError()); + + ret = CryptGenKey(ctx->provider, AT_SIGNATURE, CRYPT_EXPORTABLE, &key); + winetest_ok(ret, "Failed to create key, error %#x\n", GetLastError()); + ret = CryptDestroyKey(key); + winetest_ok(ret, "Failed to destroy key, error %#x\n", GetLastError()); + ret = CryptGetUserKey(ctx->provider, AT_SIGNATURE, &key); + winetest_ok(ret, "Failed to get user key, error %#x\n", GetLastError()); + ret = CryptDestroyKey(key); + winetest_ok(ret, "Failed to destroy key, error %#x\n", GetLastError()); + + size = sizeof(encoded_name); + ret = CertStrToNameA(X509_ASN_ENCODING, "CN=winetest_cert", CERT_X500_NAME_STR, NULL, encoded_name, &size, NULL); + winetest_ok(ret, "Failed to convert name, error %#x\n", GetLastError()); + key_info.CertIssuer.cbData = size; + key_info.CertIssuer.pbData = encoded_name; + + size = sizeof(public_key_info_buffer); + ret = CryptExportPublicKeyInfo(ctx->provider, AT_SIGNATURE, X509_ASN_ENCODING, public_key_info, &size); + winetest_ok(ret, "Failed to export public key, error %#x\n", GetLastError()); + cert_info.SubjectPublicKeyInfo = *public_key_info; + + size = sizeof(hash_buffer); + ret = CryptHashPublicKeyInfo(ctx->provider, CALG_MD5, 0, X509_ASN_ENCODING, public_key_info, hash_buffer, &size); + winetest_ok(ret, "Failed to hash public key, error %#x\n", GetLastError()); + + key_info.KeyId.cbData = size; + key_info.KeyId.pbData = hash_buffer; + + RtlGenRandom(serial, sizeof(serial)); + key_info.CertSerialNumber.cbData = sizeof(serial); + key_info.CertSerialNumber.pbData = serial; + + size = sizeof(encoded_key_id); + ret = CryptEncodeObject(X509_ASN_ENCODING, X509_AUTHORITY_KEY_ID, &key_info, encoded_key_id, &size); + winetest_ok(ret, "Failed to convert name, error %#x\n", GetLastError()); + + extension.pszObjId = (char *)szOID_AUTHORITY_KEY_IDENTIFIER; + extension.fCritical = TRUE; + extension.Value.cbData = size; + extension.Value.pbData = encoded_key_id; + + cert_info.dwVersion = CERT_V3; + cert_info.SerialNumber = key_info.CertSerialNumber; + cert_info.SignatureAlgorithm.pszObjId = (char *)szOID_RSA_SHA1RSA; + cert_info.Issuer = key_info.CertIssuer; + GetSystemTimeAsFileTime(&cert_info.NotBefore); + GetSystemTimeAsFileTime(&cert_info.NotAfter); + cert_info.NotAfter.dwHighDateTime += 1; + cert_info.Subject = key_info.CertIssuer; + cert_info.cExtension = 1; + cert_info.rgExtension = &extension; + algid.pszObjId = (char *)szOID_RSA_SHA1RSA; + size = sizeof(cert_buffer); + ret = CryptSignAndEncodeCertificate(ctx->provider, AT_SIGNATURE, X509_ASN_ENCODING, + X509_CERT_TO_BE_SIGNED, &cert_info, &algid, NULL, cert_buffer, &size); + winetest_ok(ret, "Failed to create certificate, error %#x\n", GetLastError()); + + ctx->cert = CertCreateCertificateContext(X509_ASN_ENCODING, cert_buffer, size); + winetest_ok(!!ctx->cert, "Failed to create context, error %#x\n", GetLastError()); + + size = sizeof(provider_nameA); + ret = CryptGetProvParam(ctx->provider, PP_NAME, provider_nameA, &size, 0); + winetest_ok(ret, "Failed to get prov param, error %#x\n", GetLastError()); + MultiByteToWideChar(CP_ACP, 0, (char *)provider_nameA, -1, provider_nameW, ARRAY_SIZE(provider_nameW)); + + provider_info.pwszContainerName = (WCHAR *)container_name; + provider_info.pwszProvName = provider_nameW; + provider_info.dwProvType = PROV_RSA_FULL; + provider_info.dwKeySpec = AT_SIGNATURE; + ret = CertSetCertificateContextProperty(ctx->cert, CERT_KEY_PROV_INFO_PROP_ID, 0, &provider_info); + winetest_ok(ret, "Failed to set provider info, error %#x\n", GetLastError()); + + ctx->root_store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_A, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, "root"); + if (!ctx->root_store && GetLastError() == ERROR_ACCESS_DENIED) + { + winetest_skip("Failed to open root store.\n"); + + ret = CertFreeCertificateContext(ctx->cert); + winetest_ok(ret, "Failed to free certificate, error %u\n", GetLastError()); + ret = CryptReleaseContext(ctx->provider, 0); + winetest_ok(ret, "failed to release context, error %u\n", GetLastError()); + + return FALSE; + } + winetest_ok(!!ctx->root_store, "Failed to open store, error %u\n", GetLastError()); + ret = CertAddCertificateContextToStore(ctx->root_store, ctx->cert, CERT_STORE_ADD_ALWAYS, &ctx->root_cert); + if (!ret && GetLastError() == ERROR_ACCESS_DENIED) + { + winetest_skip("Failed to add self-signed certificate to store.\n"); + + ret = CertFreeCertificateContext(ctx->cert); + winetest_ok(ret, "Failed to free certificate, error %u\n", GetLastError()); + ret = CertCloseStore(ctx->root_store, CERT_CLOSE_STORE_CHECK_FLAG); + winetest_ok(ret, "Failed to close store, error %u\n", GetLastError()); + ret = CryptReleaseContext(ctx->provider, 0); + winetest_ok(ret, "failed to release context, error %u\n", GetLastError()); + + return FALSE; + } + winetest_ok(ret, "Failed to add certificate, error %u\n", GetLastError()); + + ctx->publisher_store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_A, 0, 0, + CERT_SYSTEM_STORE_LOCAL_MACHINE, "trustedpublisher"); + winetest_ok(!!ctx->publisher_store, "Failed to open store, error %u\n", GetLastError()); + ret = CertAddCertificateContextToStore(ctx->publisher_store, ctx->cert, + CERT_STORE_ADD_ALWAYS, &ctx->publisher_cert); + winetest_ok(ret, "Failed to add certificate, error %u\n", GetLastError()); + + return TRUE; +} + +static void testsign_cleanup(struct testsign_context *ctx) +{ + BOOL ret; + + ret = CertFreeCertificateContext(ctx->cert); + winetest_ok(ret, "Failed to free certificate, error %u\n", GetLastError()); + + ret = CertDeleteCertificateFromStore(ctx->root_cert); + winetest_ok(ret, "Failed to remove certificate, error %u\n", GetLastError()); + ret = CertCloseStore(ctx->root_store, CERT_CLOSE_STORE_CHECK_FLAG); + winetest_ok(ret, "Failed to close store, error %u\n", GetLastError()); + + ret = CertDeleteCertificateFromStore(ctx->publisher_cert); + winetest_ok(ret, "Failed to remove certificate, error %u\n", GetLastError()); + ret = CertCloseStore(ctx->publisher_store, CERT_CLOSE_STORE_CHECK_FLAG); + winetest_ok(ret, "Failed to close store, error %u\n", GetLastError()); + + ret = CryptReleaseContext(ctx->provider, 0); + winetest_ok(ret, "failed to release context, error %u\n", GetLastError()); +} + +#define testsign_sign (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : testsign_sign_ +static void testsign_sign_(struct testsign_context *ctx, const WCHAR *filename) +{ + SIGNER_ATTR_AUTHCODE authcode = {sizeof(authcode)}; + SIGNER_SIGNATURE_INFO signature = {sizeof(signature)}; + SIGNER_SUBJECT_INFO subject = {sizeof(subject)}; + SIGNER_CERT_STORE_INFO store = {sizeof(store)}; + SIGNER_CERT cert_info = {sizeof(cert_info)}; + SIGNER_FILE_INFO file = {sizeof(file)}; + DWORD index = 0; + HRESULT hr; + + subject.dwSubjectChoice = 1; + subject.pdwIndex = &index; + subject.pSignerFileInfo = &file; + file.pwszFileName = (WCHAR *)filename; + cert_info.dwCertChoice = 2; + cert_info.pCertStoreInfo = &store; + store.pSigningCert = ctx->cert; + store.dwCertPolicy = 0; + signature.algidHash = CALG_SHA_256; + signature.dwAttrChoice = SIGNER_AUTHCODE_ATTR; + signature.pAttrAuthcode = &authcode; + authcode.pwszName = L""; + authcode.pwszInfo = L""; + hr = pSignerSign(&subject, &cert_info, &signature, NULL, NULL, NULL, NULL); + todo_wine winetest_ok(hr == S_OK || broken(hr == NTE_BAD_ALGID) /* < 7 */, "Failed to sign, hr %#x\n", hr); +} + +#define unload_driver (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : unload_driver_ +static void unload_driver_(SC_HANDLE service) +{ + SERVICE_STATUS status; + + ControlService(service, SERVICE_CONTROL_STOP, &status); + while (status.dwCurrentState == SERVICE_STOP_PENDING) + { + BOOL ret; + Sleep(100); + ret = QueryServiceStatus(service, &status); + winetest_ok(ret, "QueryServiceStatus failed: %u\n", GetLastError()); + } + winetest_ok(status.dwCurrentState == SERVICE_STOPPED, + "expected SERVICE_STOPPED, got %d\n", status.dwCurrentState); + + DeleteService(service); + CloseServiceHandle(service); +} + +static HANDLE okfile; + +static void cat_okfile(void) +{ + char buffer[512]; + DWORD size; + + SetFilePointer(okfile, 0, NULL, FILE_BEGIN); + + do + { + ReadFile(okfile, buffer, sizeof(buffer), &size, NULL); + printf("%.*s", size, buffer); + } while (size == sizeof(buffer)); + + SetFilePointer(okfile, 0, NULL, FILE_BEGIN); + SetEndOfFile(okfile); + + winetest_add_failures(InterlockedExchange(&test_data->failures, 0)); + winetest_add_failures(InterlockedExchange(&test_data->todo_failures, 0)); +} + +#ifdef __i386__ +#define EXT "x86" +#elif defined(__x86_64__) +#define EXT "amd64" +#elif defined(__arm__) +#define EXT "arm" +#elif defined(__aarch64__) +#define EXT "arm64" +#else +#define EXT +#endif + +static const char inf_text[] = + "[Version]\n" + "Signature=$Chicago$\n" + "ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318}\n" + "CatalogFile=winetest.cat\n" + "DriverVer=09/21/2006,6.0.5736.1\n" + + "[Manufacturer]\n" + "Wine=mfg_section,NT" EXT "\n" + + "[mfg_section.NT" EXT "]\n" + "Wine test root driver=device_section,test_hardware_id\n" + + "[device_section.NT" EXT "]\n" + "CopyFiles=file_section\n" + + "[device_section.NT" EXT ".Services]\n" + "AddService=winetest,0x2,svc_section\n" + + "[file_section]\n" + "winetest.sys\n" + + "[SourceDisksFiles]\n" + "winetest.sys=1\n" + + "[SourceDisksNames]\n" + "1=,winetest.sys\n" + + "[DestinationDirs]\n" + "DefaultDestDir=12\n" + + "[svc_section]\n" + "ServiceBinary=%12%\\winetest.sys\n" + "ServiceType=1\n" + "StartType=3\n" + "ErrorControl=1\n" + "LoadOrderGroup=Extended Base\n" + "DisplayName=\"winetest bus driver\"\n" + "; they don't sleep anymore, on the beach\n"; + +static void add_file_to_catalog(HANDLE catalog, const WCHAR *file) +{ + SIP_SUBJECTINFO subject_info = {sizeof(SIP_SUBJECTINFO)}; + SIP_INDIRECT_DATA *indirect_data; + const WCHAR *filepart = file; + CRYPTCATMEMBER *member; + WCHAR hash_buffer[100]; + GUID subject_guid; + unsigned int i; + DWORD size; + BOOL ret; + + ret = CryptSIPRetrieveSubjectGuidForCatalogFile(file, NULL, &subject_guid); + todo_wine winetest_ok(ret, "Failed to get subject guid, error %u\n", GetLastError()); + + size = 0; + subject_info.pgSubjectType = &subject_guid; + subject_info.pwsFileName = file; + subject_info.DigestAlgorithm.pszObjId = (char *)szOID_OIWSEC_sha1; + subject_info.dwFlags = SPC_INC_PE_RESOURCES_FLAG | SPC_INC_PE_IMPORT_ADDR_TABLE_FLAG | SPC_EXC_PE_PAGE_HASHES_FLAG | 0x10000; + ret = CryptSIPCreateIndirectData(&subject_info, &size, NULL); + todo_wine winetest_ok(ret, "Failed to get indirect data size, error %u\n", GetLastError()); + + indirect_data = malloc(size); + ret = CryptSIPCreateIndirectData(&subject_info, &size, indirect_data); + todo_wine winetest_ok(ret, "Failed to get indirect data, error %u\n", GetLastError()); + if (ret) + { + memset(hash_buffer, 0, sizeof(hash_buffer)); + for (i = 0; i < indirect_data->Digest.cbData; ++i) + swprintf(&hash_buffer[i * 2], 2, L"%02X", indirect_data->Digest.pbData[i]); + + member = CryptCATPutMemberInfo(catalog, (WCHAR *)file, + hash_buffer, &subject_guid, 0, size, (BYTE *)indirect_data); + winetest_ok(!!member, "Failed to write member, error %u\n", GetLastError()); + + if (wcsrchr(file, '\\')) + filepart = wcsrchr(file, '\\') + 1; + + ret = !!CryptCATPutAttrInfo(catalog, member, (WCHAR *)L"File", + CRYPTCAT_ATTR_NAMEASCII | CRYPTCAT_ATTR_DATAASCII | CRYPTCAT_ATTR_AUTHENTICATED, + (wcslen(filepart) + 1) * 2, (BYTE *)filepart); + winetest_ok(ret, "Failed to write attr, error %u\n", GetLastError()); + + ret = !!CryptCATPutAttrInfo(catalog, member, (WCHAR *)L"OSAttr", + CRYPTCAT_ATTR_NAMEASCII | CRYPTCAT_ATTR_DATAASCII | CRYPTCAT_ATTR_AUTHENTICATED, + sizeof(L"2:6.0"), (BYTE *)L"2:6.0"); + winetest_ok(ret, "Failed to write attr, error %u\n", GetLastError()); + } +} + +typedef void (*driver_test_callback)(void *); + +#define run_driver_test (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : run_driver_test_ +static void run_driver_test_(struct testsign_context *ctx, const WCHAR *name, + driver_test_callback callback, void *args) +{ + static const char hardware_id[] = "test_hardware_id\0"; + char path[MAX_PATH], dest[MAX_PATH], *filepart; + SP_DEVINFO_DATA device = {sizeof(device)}; + char cwd[MAX_PATH], tempdir[MAX_PATH]; + WCHAR driver_filename[MAX_PATH]; + SC_HANDLE manager, service; + BOOL ret, need_reboot; + HANDLE catalog, file; + HDEVINFO set; + FILE *f; + + GetCurrentDirectoryA(ARRAY_SIZE(cwd), cwd); + GetTempPathA(ARRAY_SIZE(tempdir), tempdir); + SetCurrentDirectoryA(tempdir); + + load_resource_(name, driver_filename); + ret = MoveFileExW(driver_filename, L"winetest.sys", MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING); + winetest_ok(ret, "failed to move file, error %u\n", GetLastError()); + + f = fopen("winetest.inf", "w"); + winetest_ok(!!f, "failed to open winetest.inf: %s\n", strerror(errno)); + fputs(inf_text, f); + fclose(f); + + /* Create the catalog file. */ + + catalog = CryptCATOpen((WCHAR *)L"winetest.cat", CRYPTCAT_OPEN_CREATENEW, 0, CRYPTCAT_VERSION_1, 0); + winetest_ok(catalog != INVALID_HANDLE_VALUE, "Failed to create catalog, error %#x\n", GetLastError()); + + add_file_to_catalog(catalog, L"winetest.sys"); + add_file_to_catalog(catalog, L"winetest.inf"); + + ret = CryptCATPersistStore(catalog); + todo_wine winetest_ok(ret, "Failed to write catalog, error %u\n", GetLastError()); + + ret = CryptCATClose(catalog); + winetest_ok(ret, "Failed to close catalog, error %u\n", GetLastError()); + + testsign_sign_(ctx, L"winetest.cat"); + + /* Install the driver. */ + + set = SetupDiCreateDeviceInfoList(NULL, NULL); + winetest_ok(set != INVALID_HANDLE_VALUE, "failed to create device list, error %#x\n", GetLastError()); + + ret = SetupDiCreateDeviceInfoA(set, "root\\winetest\\0", &GUID_NULL, NULL, NULL, 0, &device); + winetest_ok(ret, "failed to create device, error %#x\n", GetLastError()); + + ret = SetupDiSetDeviceRegistryPropertyA( set, &device, SPDRP_HARDWAREID, + (const BYTE *)hardware_id, sizeof(hardware_id) ); + winetest_ok(ret, "failed to create set hardware ID, error %#x\n", GetLastError()); + + ret = SetupDiCallClassInstaller(DIF_REGISTERDEVICE, set, &device); + winetest_ok(ret, "failed to register device, error %#x\n", GetLastError()); + + GetFullPathNameA("winetest.inf", sizeof(path), path, NULL); + ret = UpdateDriverForPlugAndPlayDevicesA(NULL, hardware_id, path, INSTALLFLAG_FORCE, &need_reboot); + winetest_ok(ret, "failed to install device, error %#x\n", GetLastError()); + winetest_ok(!need_reboot, "expected no reboot necessary\n"); + + /* Check that the service is created and started. */ + manager = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); + winetest_ok(!!manager, "failed to open service manager, error %u\n", GetLastError()); + service = OpenServiceA(manager, "winetest", SERVICE_START | SERVICE_STOP | DELETE); + winetest_ok(!!service, "failed to open service, error %u\n", GetLastError()); + + ret = StartServiceA(service, 0, NULL); + winetest_ok(!ret, "service didn't start automatically\n"); + if (ret || GetLastError() == ERROR_SERVICE_ALREADY_RUNNING) + callback(args); + else + { + /* If Secure Boot is enabled or the machine is 64-bit, it will reject an unsigned driver. */ + winetest_ok(GetLastError() == ERROR_DRIVER_BLOCKED || GetLastError() == ERROR_INVALID_IMAGE_HASH, + "unexpected error %u\n", GetLastError()); + winetest_skip("Failed to start service; probably your machine doesn't accept unsigned drivers.\n"); + } + + ret = SetupDiCallClassInstaller(DIF_REMOVE, set, &device); + winetest_ok(ret, "failed to remove device, error %#x\n", GetLastError()); + + file = CreateFileA("\\\\?\\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}", 0, 0, NULL, OPEN_EXISTING, 0, NULL); + winetest_ok(file == INVALID_HANDLE_VALUE, "expected failure\n"); + winetest_ok(GetLastError() == ERROR_FILE_NOT_FOUND, "got error %u\n", GetLastError()); + + ret = SetupDiDestroyDeviceInfoList(set); + winetest_ok(ret, "failed to destroy set, error %#x\n", GetLastError()); + + /* Windows stops the service but does not delete it. */ + unload_driver_(service); + CloseServiceHandle(manager); + + cat_okfile(); + + GetFullPathNameA("winetest.inf", sizeof(path), path, NULL); + ret = SetupCopyOEMInfA(path, NULL, 0, 0, dest, sizeof(dest), NULL, &filepart); + winetest_ok(ret, "Failed to copy INF, error %#x\n", GetLastError()); + ret = SetupUninstallOEMInfA(filepart, 0, NULL); + winetest_ok(ret, "Failed to uninstall INF, error %u\n", GetLastError()); + + ret = DeleteFileA("winetest.cat"); + winetest_ok(ret, "Failed to delete file, error %u\n", GetLastError()); + ret = DeleteFileA("winetest.inf"); + winetest_ok(ret, "Failed to delete file, error %u\n", GetLastError()); + ret = DeleteFileA("winetest.sys"); + winetest_ok(ret, "Failed to delete file, error %u\n", GetLastError()); + /* Windows 10 apparently deletes the image in SetupUninstallOEMInf(). */ + ret = DeleteFileA("C:/windows/system32/drivers/winetest.sys"); + winetest_ok(ret || GetLastError() == ERROR_FILE_NOT_FOUND, "Failed to delete file, error %u\n", GetLastError()); + + SetCurrentDirectoryA(cwd); +} + +#define driver_test_init(a) driver_test_init_(__FILE__, __LINE__, a) +static BOOL driver_test_init_(char const *file, int line, struct testsign_context *ctx) +{ + BOOL is_wow64; + + winetest_set_location(file, line); + + pSignerSign = (void *)GetProcAddress(LoadLibraryA("mssign32"), "SignerSign"); + + if (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64) + { + winetest_skip("Running in WoW64.\n"); + return FALSE; + } + + if (!testsign_create_cert(ctx)) + return FALSE; + + test_data_mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, + 0, sizeof(*test_data), "Global\\winetest_ntoskrnl_section"); + winetest_ok(!!test_data_mapping, "got error %u\n", GetLastError()); + test_data = MapViewOfFile(test_data_mapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 1024); + test_data->running_under_wine = !strcmp(winetest_platform, "wine"); + test_data->winetest_report_success = winetest_report_success; + test_data->winetest_debug = winetest_debug; + + okfile = CreateFileA("C:\\windows\\winetest_ntoskrnl_okfile", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL); + winetest_ok(okfile != INVALID_HANDLE_VALUE, "failed to create file, error %u\n", GetLastError()); + + return TRUE; +} + +#define driver_test_cleanup (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : driver_test_cleanup_ +static void driver_test_cleanup_(struct testsign_context *ctx) +{ + testsign_cleanup(ctx); + UnmapViewOfFile(test_data); + CloseHandle(test_data_mapping); + CloseHandle(okfile); + DeleteFileA("C:\\windows\\winetest_ntoskrnl_okfile"); +} diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index dc10497caee..b98c551ad4c 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -44,15 +44,12 @@ #include "ddk/hidpi.h" #include "wine/test.h" #include "wine/heap.h" -#include "wine/mssign.h" - -#include "driver.h" static const GUID GUID_NULL; -static HANDLE device; +#include "driver_tests.h" -static struct test_data *test_data; +static HANDLE device; static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)(const WCHAR *, UNICODE_STRING *, WCHAR **, CURDIR *); static BOOL (WINAPI *pRtlFreeUnicodeString)(UNICODE_STRING *); @@ -63,237 +60,6 @@ static HRESULT (WINAPI *pSignerSign)(SIGNER_SUBJECT_INFO *subject, SIGNER_CERT * SIGNER_SIGNATURE_INFO *signature, SIGNER_PROVIDER_INFO *provider, const WCHAR *timestamp, CRYPT_ATTRIBUTES *attr, void *sip_data); -static void load_resource(const WCHAR *name, WCHAR *filename) -{ - static WCHAR path[MAX_PATH]; - DWORD written; - HANDLE file; - HRSRC res; - void *ptr; - - GetTempPathW(ARRAY_SIZE(path), path); - GetTempFileNameW(path, name, 0, filename); - - file = CreateFileW(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); - ok(file != INVALID_HANDLE_VALUE, "failed to create %s, error %u\n", debugstr_w(filename), GetLastError()); - - res = FindResourceW(NULL, name, L"TESTDLL"); - ok( res != 0, "couldn't find resource\n" ); - ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res )); - WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL ); - ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" ); - CloseHandle( file ); -} - -struct testsign_context -{ - HCRYPTPROV provider; - const CERT_CONTEXT *cert, *root_cert, *publisher_cert; - HCERTSTORE root_store, publisher_store; -}; - -static BOOL testsign_create_cert(struct testsign_context *ctx) -{ - BYTE encoded_name[100], encoded_key_id[200], public_key_info_buffer[1000]; - WCHAR container_name[26]; - BYTE hash_buffer[16], cert_buffer[1000], provider_nameA[100], serial[16]; - CERT_PUBLIC_KEY_INFO *public_key_info = (CERT_PUBLIC_KEY_INFO *)public_key_info_buffer; - CRYPT_KEY_PROV_INFO provider_info = {0}; - CRYPT_ALGORITHM_IDENTIFIER algid = {0}; - CERT_AUTHORITY_KEY_ID_INFO key_info; - CERT_INFO cert_info = {0}; - WCHAR provider_nameW[100]; - CERT_EXTENSION extension; - HCRYPTKEY key; - DWORD size; - BOOL ret; - - memset(ctx, 0, sizeof(*ctx)); - - srand(time(NULL)); - swprintf(container_name, ARRAY_SIZE(container_name), L"wine_testsign%u", rand()); - - ret = CryptAcquireContextW(&ctx->provider, container_name, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET); - ok(ret, "Failed to create container, error %#x\n", GetLastError()); - - ret = CryptGenKey(ctx->provider, AT_SIGNATURE, CRYPT_EXPORTABLE, &key); - ok(ret, "Failed to create key, error %#x\n", GetLastError()); - ret = CryptDestroyKey(key); - ok(ret, "Failed to destroy key, error %#x\n", GetLastError()); - ret = CryptGetUserKey(ctx->provider, AT_SIGNATURE, &key); - ok(ret, "Failed to get user key, error %#x\n", GetLastError()); - ret = CryptDestroyKey(key); - ok(ret, "Failed to destroy key, error %#x\n", GetLastError()); - - size = sizeof(encoded_name); - ret = CertStrToNameA(X509_ASN_ENCODING, "CN=winetest_cert", CERT_X500_NAME_STR, NULL, encoded_name, &size, NULL); - ok(ret, "Failed to convert name, error %#x\n", GetLastError()); - key_info.CertIssuer.cbData = size; - key_info.CertIssuer.pbData = encoded_name; - - size = sizeof(public_key_info_buffer); - ret = CryptExportPublicKeyInfo(ctx->provider, AT_SIGNATURE, X509_ASN_ENCODING, public_key_info, &size); - ok(ret, "Failed to export public key, error %#x\n", GetLastError()); - cert_info.SubjectPublicKeyInfo = *public_key_info; - - size = sizeof(hash_buffer); - ret = CryptHashPublicKeyInfo(ctx->provider, CALG_MD5, 0, X509_ASN_ENCODING, public_key_info, hash_buffer, &size); - ok(ret, "Failed to hash public key, error %#x\n", GetLastError()); - - key_info.KeyId.cbData = size; - key_info.KeyId.pbData = hash_buffer; - - RtlGenRandom(serial, sizeof(serial)); - key_info.CertSerialNumber.cbData = sizeof(serial); - key_info.CertSerialNumber.pbData = serial; - - size = sizeof(encoded_key_id); - ret = CryptEncodeObject(X509_ASN_ENCODING, X509_AUTHORITY_KEY_ID, &key_info, encoded_key_id, &size); - ok(ret, "Failed to convert name, error %#x\n", GetLastError()); - - extension.pszObjId = (char *)szOID_AUTHORITY_KEY_IDENTIFIER; - extension.fCritical = TRUE; - extension.Value.cbData = size; - extension.Value.pbData = encoded_key_id; - - cert_info.dwVersion = CERT_V3; - cert_info.SerialNumber = key_info.CertSerialNumber; - cert_info.SignatureAlgorithm.pszObjId = (char *)szOID_RSA_SHA1RSA; - cert_info.Issuer = key_info.CertIssuer; - GetSystemTimeAsFileTime(&cert_info.NotBefore); - GetSystemTimeAsFileTime(&cert_info.NotAfter); - cert_info.NotAfter.dwHighDateTime += 1; - cert_info.Subject = key_info.CertIssuer; - cert_info.cExtension = 1; - cert_info.rgExtension = &extension; - algid.pszObjId = (char *)szOID_RSA_SHA1RSA; - size = sizeof(cert_buffer); - ret = CryptSignAndEncodeCertificate(ctx->provider, AT_SIGNATURE, X509_ASN_ENCODING, - X509_CERT_TO_BE_SIGNED, &cert_info, &algid, NULL, cert_buffer, &size); - ok(ret, "Failed to create certificate, error %#x\n", GetLastError()); - - ctx->cert = CertCreateCertificateContext(X509_ASN_ENCODING, cert_buffer, size); - ok(!!ctx->cert, "Failed to create context, error %#x\n", GetLastError()); - - size = sizeof(provider_nameA); - ret = CryptGetProvParam(ctx->provider, PP_NAME, provider_nameA, &size, 0); - ok(ret, "Failed to get prov param, error %#x\n", GetLastError()); - MultiByteToWideChar(CP_ACP, 0, (char *)provider_nameA, -1, provider_nameW, ARRAY_SIZE(provider_nameW)); - - provider_info.pwszContainerName = (WCHAR *)container_name; - provider_info.pwszProvName = provider_nameW; - provider_info.dwProvType = PROV_RSA_FULL; - provider_info.dwKeySpec = AT_SIGNATURE; - ret = CertSetCertificateContextProperty(ctx->cert, CERT_KEY_PROV_INFO_PROP_ID, 0, &provider_info); - ok(ret, "Failed to set provider info, error %#x\n", GetLastError()); - - ctx->root_store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_A, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, "root"); - if (!ctx->root_store && GetLastError() == ERROR_ACCESS_DENIED) - { - skip("Failed to open root store.\n"); - - ret = CertFreeCertificateContext(ctx->cert); - ok(ret, "Failed to free certificate, error %u\n", GetLastError()); - ret = CryptReleaseContext(ctx->provider, 0); - ok(ret, "failed to release context, error %u\n", GetLastError()); - - return FALSE; - } - ok(!!ctx->root_store, "Failed to open store, error %u\n", GetLastError()); - ret = CertAddCertificateContextToStore(ctx->root_store, ctx->cert, CERT_STORE_ADD_ALWAYS, &ctx->root_cert); - if (!ret && GetLastError() == ERROR_ACCESS_DENIED) - { - skip("Failed to add self-signed certificate to store.\n"); - - ret = CertFreeCertificateContext(ctx->cert); - ok(ret, "Failed to free certificate, error %u\n", GetLastError()); - ret = CertCloseStore(ctx->root_store, CERT_CLOSE_STORE_CHECK_FLAG); - ok(ret, "Failed to close store, error %u\n", GetLastError()); - ret = CryptReleaseContext(ctx->provider, 0); - ok(ret, "failed to release context, error %u\n", GetLastError()); - - return FALSE; - } - ok(ret, "Failed to add certificate, error %u\n", GetLastError()); - - ctx->publisher_store = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_A, 0, 0, - CERT_SYSTEM_STORE_LOCAL_MACHINE, "trustedpublisher"); - ok(!!ctx->publisher_store, "Failed to open store, error %u\n", GetLastError()); - ret = CertAddCertificateContextToStore(ctx->publisher_store, ctx->cert, - CERT_STORE_ADD_ALWAYS, &ctx->publisher_cert); - ok(ret, "Failed to add certificate, error %u\n", GetLastError()); - - return TRUE; -} - -static void testsign_cleanup(struct testsign_context *ctx) -{ - BOOL ret; - - ret = CertFreeCertificateContext(ctx->cert); - ok(ret, "Failed to free certificate, error %u\n", GetLastError()); - - ret = CertDeleteCertificateFromStore(ctx->root_cert); - ok(ret, "Failed to remove certificate, error %u\n", GetLastError()); - ret = CertCloseStore(ctx->root_store, CERT_CLOSE_STORE_CHECK_FLAG); - ok(ret, "Failed to close store, error %u\n", GetLastError()); - - ret = CertDeleteCertificateFromStore(ctx->publisher_cert); - ok(ret, "Failed to remove certificate, error %u\n", GetLastError()); - ret = CertCloseStore(ctx->publisher_store, CERT_CLOSE_STORE_CHECK_FLAG); - ok(ret, "Failed to close store, error %u\n", GetLastError()); - - ret = CryptReleaseContext(ctx->provider, 0); - ok(ret, "failed to release context, error %u\n", GetLastError()); -} - -static void testsign_sign(struct testsign_context *ctx, const WCHAR *filename) -{ - SIGNER_ATTR_AUTHCODE authcode = {sizeof(authcode)}; - SIGNER_SIGNATURE_INFO signature = {sizeof(signature)}; - SIGNER_SUBJECT_INFO subject = {sizeof(subject)}; - SIGNER_CERT_STORE_INFO store = {sizeof(store)}; - SIGNER_CERT cert_info = {sizeof(cert_info)}; - SIGNER_FILE_INFO file = {sizeof(file)}; - DWORD index = 0; - HRESULT hr; - - subject.dwSubjectChoice = 1; - subject.pdwIndex = &index; - subject.pSignerFileInfo = &file; - file.pwszFileName = (WCHAR *)filename; - cert_info.dwCertChoice = 2; - cert_info.pCertStoreInfo = &store; - store.pSigningCert = ctx->cert; - store.dwCertPolicy = 0; - signature.algidHash = CALG_SHA_256; - signature.dwAttrChoice = SIGNER_AUTHCODE_ATTR; - signature.pAttrAuthcode = &authcode; - authcode.pwszName = L""; - authcode.pwszInfo = L""; - hr = pSignerSign(&subject, &cert_info, &signature, NULL, NULL, NULL, NULL); - todo_wine ok(hr == S_OK || broken(hr == NTE_BAD_ALGID) /* < 7 */, "Failed to sign, hr %#x\n", hr); -} - -static void unload_driver(SC_HANDLE service) -{ - SERVICE_STATUS status; - - ControlService(service, SERVICE_CONTROL_STOP, &status); - while (status.dwCurrentState == SERVICE_STOP_PENDING) - { - BOOL ret; - Sleep(100); - ret = QueryServiceStatus(service, &status); - ok(ret, "QueryServiceStatus failed: %u\n", GetLastError()); - } - ok(status.dwCurrentState == SERVICE_STOPPED, - "expected SERVICE_STOPPED, got %d\n", status.dwCurrentState); - - DeleteService(service); - CloseServiceHandle(service); -} - static SC_HANDLE load_driver(struct testsign_context *ctx, WCHAR *filename, const WCHAR *resname, const WCHAR *driver_name) { @@ -367,28 +133,6 @@ static BOOL start_driver(HANDLE service, BOOL vista_plus) return TRUE; } -static HANDLE okfile; - -static void cat_okfile(void) -{ - char buffer[512]; - DWORD size; - - SetFilePointer(okfile, 0, NULL, FILE_BEGIN); - - do - { - ReadFile(okfile, buffer, sizeof(buffer), &size, NULL); - printf("%.*s", size, buffer); - } while (size == sizeof(buffer)); - - SetFilePointer(okfile, 0, NULL, FILE_BEGIN); - SetEndOfFile(okfile); - - winetest_add_failures(InterlockedExchange(&test_data->failures, 0)); - winetest_add_failures(InterlockedExchange(&test_data->todo_failures, 0)); -} - static ULONG64 modified_value; static void main_test(void) @@ -1239,109 +983,6 @@ static void test_driver_netio(struct testsign_context *ctx) cat_okfile(); } -#ifdef __i386__ -#define EXT "x86" -#elif defined(__x86_64__) -#define EXT "amd64" -#elif defined(__arm__) -#define EXT "arm" -#elif defined(__aarch64__) -#define EXT "arm64" -#else -#define EXT -#endif - -static const char inf_text[] = - "[Version]\n" - "Signature=$Chicago$\n" - "ClassGuid={4d36e97d-e325-11ce-bfc1-08002be10318}\n" - "CatalogFile=winetest.cat\n" - "DriverVer=09/21/2006,6.0.5736.1\n" - - "[Manufacturer]\n" - "Wine=mfg_section,NT" EXT "\n" - - "[mfg_section.NT" EXT "]\n" - "Wine test root driver=device_section,test_hardware_id\n" - - "[device_section.NT" EXT "]\n" - "CopyFiles=file_section\n" - - "[device_section.NT" EXT ".Services]\n" - "AddService=winetest,0x2,svc_section\n" - - "[file_section]\n" - "winetest.sys\n" - - "[SourceDisksFiles]\n" - "winetest.sys=1\n" - - "[SourceDisksNames]\n" - "1=,winetest.sys\n" - - "[DestinationDirs]\n" - "DefaultDestDir=12\n" - - "[svc_section]\n" - "ServiceBinary=%12%\\winetest.sys\n" - "ServiceType=1\n" - "StartType=3\n" - "ErrorControl=1\n" - "LoadOrderGroup=Extended Base\n" - "DisplayName=\"winetest bus driver\"\n" - "; they don't sleep anymore, on the beach\n"; - -static void add_file_to_catalog(HANDLE catalog, const WCHAR *file) -{ - SIP_SUBJECTINFO subject_info = {sizeof(SIP_SUBJECTINFO)}; - SIP_INDIRECT_DATA *indirect_data; - const WCHAR *filepart = file; - CRYPTCATMEMBER *member; - WCHAR hash_buffer[100]; - GUID subject_guid; - unsigned int i; - DWORD size; - BOOL ret; - - ret = CryptSIPRetrieveSubjectGuidForCatalogFile(file, NULL, &subject_guid); - todo_wine ok(ret, "Failed to get subject guid, error %u\n", GetLastError()); - - size = 0; - subject_info.pgSubjectType = &subject_guid; - subject_info.pwsFileName = file; - subject_info.DigestAlgorithm.pszObjId = (char *)szOID_OIWSEC_sha1; - subject_info.dwFlags = SPC_INC_PE_RESOURCES_FLAG | SPC_INC_PE_IMPORT_ADDR_TABLE_FLAG | SPC_EXC_PE_PAGE_HASHES_FLAG | 0x10000; - ret = CryptSIPCreateIndirectData(&subject_info, &size, NULL); - todo_wine ok(ret, "Failed to get indirect data size, error %u\n", GetLastError()); - - indirect_data = malloc(size); - ret = CryptSIPCreateIndirectData(&subject_info, &size, indirect_data); - todo_wine ok(ret, "Failed to get indirect data, error %u\n", GetLastError()); - if (ret) - { - memset(hash_buffer, 0, sizeof(hash_buffer)); - for (i = 0; i < indirect_data->Digest.cbData; ++i) - swprintf(&hash_buffer[i * 2], 2, L"%02X", indirect_data->Digest.pbData[i]); - - member = CryptCATPutMemberInfo(catalog, (WCHAR *)file, - hash_buffer, &subject_guid, 0, size, (BYTE *)indirect_data); - ok(!!member, "Failed to write member, error %u\n", GetLastError()); - - if (wcsrchr(file, '\\')) - filepart = wcsrchr(file, '\\') + 1; - - ret = !!CryptCATPutAttrInfo(catalog, member, (WCHAR *)L"File", - CRYPTCAT_ATTR_NAMEASCII | CRYPTCAT_ATTR_DATAASCII | CRYPTCAT_ATTR_AUTHENTICATED, - (wcslen(filepart) + 1) * 2, (BYTE *)filepart); - ok(ret, "Failed to write attr, error %u\n", GetLastError()); - - ret = !!CryptCATPutAttrInfo(catalog, member, (WCHAR *)L"OSAttr", - CRYPTCAT_ATTR_NAMEASCII | CRYPTCAT_ATTR_DATAASCII | CRYPTCAT_ATTR_AUTHENTICATED, - sizeof(L"2:6.0"), (BYTE *)L"2:6.0"); - ok(ret, "Failed to write attr, error %u\n", GetLastError()); - } -} - static const GUID bus_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc1}}; static const GUID child_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc2}}; @@ -1434,7 +1075,7 @@ static void pump_messages(void) } } -static void test_pnp_devices(void) +static void test_pnp_devices(void *args) { static const char expect_hardware_id[] = "winetest_hardware\0winetest_hardware_1\0"; static const char expect_compat_id[] = "winetest_compat\0winetest_compat_1\0"; @@ -1698,133 +1339,6 @@ static void test_pnp_devices(void) UnregisterClassA("ntoskrnl_test_wc", GetModuleHandleA(NULL)); } -static void test_pnp_driver(struct testsign_context *ctx) -{ - static const char hardware_id[] = "test_hardware_id\0"; - char path[MAX_PATH], dest[MAX_PATH], *filepart; - SP_DEVINFO_DATA device = {sizeof(device)}; - char cwd[MAX_PATH], tempdir[MAX_PATH]; - WCHAR driver_filename[MAX_PATH]; - SC_HANDLE manager, service; - BOOL ret, need_reboot; - HANDLE catalog, file; - unsigned int i; - HDEVINFO set; - FILE *f; - - GetCurrentDirectoryA(ARRAY_SIZE(cwd), cwd); - GetTempPathA(ARRAY_SIZE(tempdir), tempdir); - SetCurrentDirectoryA(tempdir); - - load_resource(L"driver_pnp.dll", driver_filename); - ret = MoveFileExW(driver_filename, L"winetest.sys", MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING); - ok(ret, "failed to move file, error %u\n", GetLastError()); - - f = fopen("winetest.inf", "w"); - ok(!!f, "failed to open winetest.inf: %s\n", strerror(errno)); - fputs(inf_text, f); - fclose(f); - - /* Create the catalog file. */ - - catalog = CryptCATOpen((WCHAR *)L"winetest.cat", CRYPTCAT_OPEN_CREATENEW, 0, CRYPTCAT_VERSION_1, 0); - ok(catalog != INVALID_HANDLE_VALUE, "Failed to create catalog, error %#x\n", GetLastError()); - - ret = !!CryptCATPutCatAttrInfo(catalog, (WCHAR *)L"HWID1", - CRYPTCAT_ATTR_NAMEASCII | CRYPTCAT_ATTR_DATAASCII | CRYPTCAT_ATTR_AUTHENTICATED, - sizeof(L"test_hardware_id"), (BYTE *)L"test_hardware_id"); - todo_wine ok(ret, "failed to add attribute, error %#x\n", GetLastError()); - - ret = !!CryptCATPutCatAttrInfo(catalog, (WCHAR *)L"OS", - CRYPTCAT_ATTR_NAMEASCII | CRYPTCAT_ATTR_DATAASCII | CRYPTCAT_ATTR_AUTHENTICATED, - sizeof(L"VistaX64"), (BYTE *)L"VistaX64"); - todo_wine ok(ret, "failed to add attribute, error %#x\n", GetLastError()); - - add_file_to_catalog(catalog, L"winetest.sys"); - add_file_to_catalog(catalog, L"winetest.inf"); - - ret = CryptCATPersistStore(catalog); - todo_wine ok(ret, "Failed to write catalog, error %u\n", GetLastError()); - - ret = CryptCATClose(catalog); - ok(ret, "Failed to close catalog, error %u\n", GetLastError()); - - testsign_sign(ctx, L"winetest.cat"); - - /* Install the driver. */ - - set = SetupDiCreateDeviceInfoList(NULL, NULL); - ok(set != INVALID_HANDLE_VALUE, "failed to create device list, error %#x\n", GetLastError()); - - ret = SetupDiCreateDeviceInfoA(set, "root\\winetest\\0", &GUID_NULL, NULL, NULL, 0, &device); - ok(ret, "failed to create device, error %#x\n", GetLastError()); - - ret = SetupDiSetDeviceRegistryPropertyA( set, &device, SPDRP_HARDWAREID, - (const BYTE *)hardware_id, sizeof(hardware_id) ); - ok(ret, "failed to create set hardware ID, error %#x\n", GetLastError()); - - ret = SetupDiCallClassInstaller(DIF_REGISTERDEVICE, set, &device); - ok(ret, "failed to register device, error %#x\n", GetLastError()); - - GetFullPathNameA("winetest.inf", sizeof(path), path, NULL); - ret = UpdateDriverForPlugAndPlayDevicesA(NULL, hardware_id, path, INSTALLFLAG_FORCE, &need_reboot); - ok(ret, "failed to install device, error %#x\n", GetLastError()); - ok(!need_reboot, "expected no reboot necessary\n"); - - /* Tests. */ - - test_pnp_devices(); - - /* Clean up. */ - - ret = SetupDiCallClassInstaller(DIF_REMOVE, set, &device); - ok(ret, "failed to remove device, error %#x\n", GetLastError()); - - file = CreateFileA("\\\\?\\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}", 0, 0, NULL, OPEN_EXISTING, 0, NULL); - ok(file == INVALID_HANDLE_VALUE, "expected failure\n"); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, "got error %u\n", GetLastError()); - - ret = SetupDiDestroyDeviceInfoList(set); - ok(ret, "failed to destroy set, error %#x\n", GetLastError()); - - set = SetupDiGetClassDevsA(NULL, "wine", NULL, DIGCF_ALLCLASSES); - ok(set != INVALID_HANDLE_VALUE, "failed to get device list, error %#x\n", GetLastError()); - - for (i = 0; SetupDiEnumDeviceInfo(set, i, &device); ++i) - { - ret = SetupDiCallClassInstaller(DIF_REMOVE, set, &device); - ok(ret, "failed to remove device, error %#x\n", GetLastError()); - } - - /* Windows stops the service but does not delete it. */ - manager = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); - ok(!!manager, "failed to open service manager, error %u\n", GetLastError()); - service = OpenServiceA(manager, "winetest", SERVICE_STOP | DELETE); - ok(!!service, "failed to open service, error %u\n", GetLastError()); - unload_driver(service); - CloseServiceHandle(manager); - - cat_okfile(); - - GetFullPathNameA("winetest.inf", sizeof(path), path, NULL); - ret = SetupCopyOEMInfA(path, NULL, 0, 0, dest, sizeof(dest), NULL, &filepart); - ok(ret, "Failed to copy INF, error %#x\n", GetLastError()); - ret = SetupUninstallOEMInfA(filepart, 0, NULL); - ok(ret, "Failed to uninstall INF, error %u\n", GetLastError()); - - ret = DeleteFileA("winetest.cat"); - ok(ret, "Failed to delete file, error %u\n", GetLastError()); - ret = DeleteFileA("winetest.inf"); - ok(ret, "Failed to delete file, error %u\n", GetLastError()); - ret = DeleteFileA("winetest.sys"); - ok(ret, "Failed to delete file, error %u\n", GetLastError()); - /* Windows 10 apparently deletes the image in SetupUninstallOEMInf(). */ - ret = DeleteFileA("C:/windows/system32/drivers/winetest.sys"); - ok(ret || GetLastError() == ERROR_FILE_NOT_FOUND, "Failed to delete file, error %u\n", GetLastError()); - - SetCurrentDirectoryA(cwd); -} - #define check_member_(file, line, val, exp, fmt, member) \ ok_(file, line)((val).member == (exp).member, \ "got " #member " " fmt ", expected " fmt "\n", \ @@ -3131,8 +2645,16 @@ static void test_hidp(HANDLE file, HANDLE async_file, int report_id, BOOL polled HidD_FreePreparsedData(preparsed_data); } -static void test_hid_device(DWORD report_id, DWORD polled) +struct test_hid_params { + BOOL report_id; + BOOL polled; +}; + +static void test_hid_device(void *args) +{ + struct test_hid_params *params = args; + BOOL report_id = params->report_id, polled = params->polled; char buffer[200]; SP_DEVICE_INTERFACE_DETAIL_DATA_A *iface_detail = (void *)buffer; SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; @@ -3297,18 +2819,11 @@ static void test_hid_device(DWORD report_id, DWORD polled) static void test_hid_driver(struct testsign_context *ctx, DWORD report_id, DWORD polled) { - static const char hardware_id[] = "test_hardware_id\0"; - char path[MAX_PATH], dest[MAX_PATH], *filepart; + struct test_hid_params params = {.report_id = report_id, .polled = polled}; SP_DEVINFO_DATA device = {sizeof(device)}; char cwd[MAX_PATH], tempdir[MAX_PATH]; - WCHAR driver_filename[MAX_PATH]; - SC_HANDLE manager, service; - BOOL ret, need_reboot; - HANDLE catalog, file; LSTATUS status; - HDEVINFO set; HKEY hkey; - FILE *f; GetCurrentDirectoryA(ARRAY_SIZE(cwd), cwd); GetTempPathA(ARRAY_SIZE(tempdir), tempdir); @@ -3323,94 +2838,7 @@ static void test_hid_driver(struct testsign_context *ctx, DWORD report_id, DWORD status = RegSetValueExW(hkey, L"PolledMode", 0, REG_DWORD, (void *)&polled, sizeof(polled)); ok(!status, "RegSetValueExW returned %#x\n", status); - load_resource(L"driver_hid.dll", driver_filename); - ret = MoveFileExW(driver_filename, L"winetest.sys", MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING); - ok(ret, "failed to move file, error %u\n", GetLastError()); - - f = fopen("winetest.inf", "w"); - ok(!!f, "failed to open winetest.inf: %s\n", strerror(errno)); - fputs(inf_text, f); - fclose(f); - - /* Create the catalog file. */ - - catalog = CryptCATOpen((WCHAR *)L"winetest.cat", CRYPTCAT_OPEN_CREATENEW, 0, CRYPTCAT_VERSION_1, 0); - ok(catalog != INVALID_HANDLE_VALUE, "Failed to create catalog, error %#x\n", GetLastError()); - - add_file_to_catalog(catalog, L"winetest.sys"); - add_file_to_catalog(catalog, L"winetest.inf"); - - ret = CryptCATPersistStore(catalog); - todo_wine ok(ret, "Failed to write catalog, error %u\n", GetLastError()); - - ret = CryptCATClose(catalog); - ok(ret, "Failed to close catalog, error %u\n", GetLastError()); - - testsign_sign(ctx, L"winetest.cat"); - - /* Install the driver. */ - - set = SetupDiCreateDeviceInfoList(NULL, NULL); - ok(set != INVALID_HANDLE_VALUE, "failed to create device list, error %#x\n", GetLastError()); - - ret = SetupDiCreateDeviceInfoA(set, "root\\winetest\\0", &GUID_NULL, NULL, NULL, 0, &device); - ok(ret, "failed to create device, error %#x\n", GetLastError()); - - ret = SetupDiSetDeviceRegistryPropertyA( set, &device, SPDRP_HARDWAREID, - (const BYTE *)hardware_id, sizeof(hardware_id) ); - ok(ret, "failed to create set hardware ID, error %#x\n", GetLastError()); - - ret = SetupDiCallClassInstaller(DIF_REGISTERDEVICE, set, &device); - ok(ret, "failed to register device, error %#x\n", GetLastError()); - - GetFullPathNameA("winetest.inf", sizeof(path), path, NULL); - ret = UpdateDriverForPlugAndPlayDevicesA(NULL, hardware_id, path, INSTALLFLAG_FORCE, &need_reboot); - ok(ret, "failed to install device, error %#x\n", GetLastError()); - ok(!need_reboot, "expected no reboot necessary\n"); - - /* Tests. */ - - test_hid_device(report_id, polled); - - /* Clean up. */ - - ret = SetupDiCallClassInstaller(DIF_REMOVE, set, &device); - ok(ret, "failed to remove device, error %#x\n", GetLastError()); - - file = CreateFileA("\\\\?\\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}", 0, 0, NULL, OPEN_EXISTING, 0, NULL); - ok(file == INVALID_HANDLE_VALUE, "expected failure\n"); - ok(GetLastError() == ERROR_FILE_NOT_FOUND, "got error %u\n", GetLastError()); - - ret = SetupDiDestroyDeviceInfoList(set); - ok(ret, "failed to destroy set, error %#x\n", GetLastError()); - - /* Windows stops the service but does not delete it. */ - manager = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); - ok(!!manager, "failed to open service manager, error %u\n", GetLastError()); - service = OpenServiceA(manager, "winetest", SERVICE_STOP | DELETE); - ok(!!service, "failed to open service, error %u\n", GetLastError()); - unload_driver(service); - CloseServiceHandle(manager); - - cat_okfile(); - - GetFullPathNameA("winetest.inf", sizeof(path), path, NULL); - ret = SetupCopyOEMInfA(path, NULL, 0, 0, dest, sizeof(dest), NULL, &filepart); - ok(ret, "Failed to copy INF, error %#x\n", GetLastError()); - ret = SetupUninstallOEMInfA(filepart, 0, NULL); - ok(ret, "Failed to uninstall INF, error %u\n", GetLastError()); - - ret = DeleteFileA("winetest.cat"); - ok(ret, "Failed to delete file, error %u\n", GetLastError()); - ret = DeleteFileA("winetest.inf"); - ok(ret, "Failed to delete file, error %u\n", GetLastError()); - ret = DeleteFileA("winetest.sys"); - ok(ret, "Failed to delete file, error %u\n", GetLastError()); - /* Windows 10 apparently deletes the image in SetupUninstallOEMInf(). */ - ret = DeleteFileA("C:/windows/system32/drivers/winetest.sys"); - ok(ret || GetLastError() == ERROR_FILE_NOT_FOUND, "Failed to delete file, error %u\n", GetLastError()); - - SetCurrentDirectoryA(cwd); + run_driver_test(ctx, L"driver_hid.dll", test_hid_device, ¶ms); } START_TEST(ntoskrnl) @@ -3418,9 +2846,8 @@ START_TEST(ntoskrnl) WCHAR filename[MAX_PATH], filename2[MAX_PATH]; struct testsign_context ctx; SC_HANDLE service, service2; - BOOL ret, is_wow64; - HANDLE mapping; DWORD written; + BOOL ret; pRtlDosPathNameToNtPathName_U = (void *)GetProcAddress(GetModuleHandleA("ntdll"), "RtlDosPathNameToNtPathName_U"); pRtlFreeUnicodeString = (void *)GetProcAddress(GetModuleHandleA("ntdll"), "RtlFreeUnicodeString"); @@ -3428,29 +2855,10 @@ START_TEST(ntoskrnl) pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process"); pSetFileCompletionNotificationModes = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "SetFileCompletionNotificationModes"); - pSignerSign = (void *)GetProcAddress(LoadLibraryA("mssign32"), "SignerSign"); - - if (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64) - { - skip("Running in WoW64.\n"); - return; - } - if (!testsign_create_cert(&ctx)) + if (!driver_test_init(&ctx)) return; - mapping = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, - 0, sizeof(*test_data), "Global\\winetest_ntoskrnl_section"); - ok(!!mapping, "got error %u\n", GetLastError()); - test_data = MapViewOfFile(mapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 1024); - test_data->running_under_wine = !strcmp(winetest_platform, "wine"); - test_data->winetest_report_success = winetest_report_success; - test_data->winetest_debug = winetest_debug; - - okfile = CreateFileA("C:\\windows\\winetest_ntoskrnl_okfile", GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL); - ok(okfile != INVALID_HANDLE_VALUE, "failed to create file, error %u\n", GetLastError()); - subtest("driver"); if (!(service = load_driver(&ctx, filename, L"driver.dll", L"WineTestDriver"))) goto out; @@ -3497,7 +2905,7 @@ START_TEST(ntoskrnl) test_driver_netio(&ctx); subtest("driver_pnp"); - test_pnp_driver(&ctx); + run_driver_test(&ctx, L"driver_pnp.dll", test_pnp_devices, NULL); subtest("driver_hid"); test_hid_driver(&ctx, 0, FALSE); @@ -3506,9 +2914,5 @@ START_TEST(ntoskrnl) test_hid_driver(&ctx, 1, TRUE); out: - testsign_cleanup(&ctx); - UnmapViewOfFile(test_data); - CloseHandle(mapping); - CloseHandle(okfile); - DeleteFileA("C:\\windows\\winetest_ntoskrnl_okfile"); + driver_test_cleanup(&ctx); } -- 2.33.0