From 7c41ffd64e94260259ed66d9c845389bbf8022d7 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Thu, 3 Nov 2016 16:15:32 -0700 Subject: [PATCH] tst: fscrash: initial commit --- build/VStudio/testing/fscrash.vcxproj | 185 ++++++++++++++++++ build/VStudio/testing/fscrash.vcxproj.filters | 28 +++ build/VStudio/winfsp.sln | 25 ++- tst/fscrash/fscrash-main.c | 90 +++++++++ tst/fscrash/fscrash.c | 132 +++++++++++++ tst/fscrash/fscrash.h | 43 ++++ 6 files changed, 502 insertions(+), 1 deletion(-) create mode 100644 build/VStudio/testing/fscrash.vcxproj create mode 100644 build/VStudio/testing/fscrash.vcxproj.filters create mode 100644 tst/fscrash/fscrash-main.c create mode 100644 tst/fscrash/fscrash.c create mode 100644 tst/fscrash/fscrash.h diff --git a/build/VStudio/testing/fscrash.vcxproj b/build/VStudio/testing/fscrash.vcxproj new file mode 100644 index 00000000..0ebd1b87 --- /dev/null +++ b/build/VStudio/testing/fscrash.vcxproj @@ -0,0 +1,185 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {10757011-749D-4954-873B-AE38D8145472} + Win32Proj + fscrash + 8.1 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)build\$(Configuration)\ + $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\ + $(ProjectName)-$(PlatformTarget) + + + true + $(SolutionDir)build\$(Configuration)\ + $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\ + $(ProjectName)-$(PlatformTarget) + + + false + $(SolutionDir)build\$(Configuration)\ + $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\ + $(ProjectName)-$(PlatformTarget) + + + false + $(SolutionDir)build\$(Configuration)\ + $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\ + $(ProjectName)-$(PlatformTarget) + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + ..\..\..\tst\memfs;..\..\..\inc + + + Console + true + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + ..\..\..\tst\memfs;..\..\..\inc + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + ..\..\..\tst\memfs;..\..\..\inc + + + Console + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + MultiThreaded + ..\..\..\tst\memfs;..\..\..\inc + + + Console + true + true + true + + + + + + + + + + + + + + {4a7c0b21-9e10-4c81-92de-1493efcf24eb} + + + + + + \ No newline at end of file diff --git a/build/VStudio/testing/fscrash.vcxproj.filters b/build/VStudio/testing/fscrash.vcxproj.filters new file mode 100644 index 00000000..5f5dfd53 --- /dev/null +++ b/build/VStudio/testing/fscrash.vcxproj.filters @@ -0,0 +1,28 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source + + + Source + + + Source + + + + + Source + + + Source + + + \ No newline at end of file diff --git a/build/VStudio/winfsp.sln b/build/VStudio/winfsp.sln index efed5384..79b70563 100644 --- a/build/VStudio/winfsp.sln +++ b/build/VStudio/winfsp.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winfsp.dll", "winfsp_dll.vcxproj", "{4A7C0B21-9E10-4C81-92DE-1493EFCF24EB}" ProjectSection(ProjectDependencies) = postProject @@ -45,6 +45,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "launchctl", "launcher\launc {A5EFD487-0140-4184-8C54-FFAEC2F85E35} = {A5EFD487-0140-4184-8C54-FFAEC2F85E35} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fscrash", "testing\fscrash.vcxproj", "{10757011-749D-4954-873B-AE38D8145472}" + ProjectSection(ProjectDependencies) = postProject + {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB} = {4A7C0B21-9E10-4C81-92DE-1493EFCF24EB} + {C85C26BA-8C22-4D30-83DA-46C3548E6332} = {C85C26BA-8C22-4D30-83DA-46C3548E6332} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -153,6 +159,22 @@ Global {73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x64.Build.0 = Release|x64 {73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.ActiveCfg = Release|Win32 {73EAAEDA-557B-48D5-A137-328934720FB4}.Release|x86.Build.0 = Release|Win32 + {10757011-749D-4954-873B-AE38D8145472}.Debug|x64.ActiveCfg = Debug|x64 + {10757011-749D-4954-873B-AE38D8145472}.Debug|x64.Build.0 = Debug|x64 + {10757011-749D-4954-873B-AE38D8145472}.Debug|x86.ActiveCfg = Debug|Win32 + {10757011-749D-4954-873B-AE38D8145472}.Debug|x86.Build.0 = Debug|Win32 + {10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x64.ActiveCfg = Debug|x64 + {10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x64.Build.0 = Debug|x64 + {10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x86.ActiveCfg = Debug|Win32 + {10757011-749D-4954-873B-AE38D8145472}.Installer.Debug|x86.Build.0 = Debug|Win32 + {10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x64.ActiveCfg = Release|x64 + {10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x64.Build.0 = Release|x64 + {10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x86.ActiveCfg = Release|Win32 + {10757011-749D-4954-873B-AE38D8145472}.Installer.Release|x86.Build.0 = Release|Win32 + {10757011-749D-4954-873B-AE38D8145472}.Release|x64.ActiveCfg = Release|x64 + {10757011-749D-4954-873B-AE38D8145472}.Release|x64.Build.0 = Release|x64 + {10757011-749D-4954-873B-AE38D8145472}.Release|x86.ActiveCfg = Release|Win32 + {10757011-749D-4954-873B-AE38D8145472}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -164,5 +186,6 @@ Global {95C223E6-B5F1-4FD0-9376-41CDBC824445} = {B464EF06-42AE-4674-81BB-FDDE80204822} {A5EFD487-0140-4184-8C54-FFAEC2F85E35} = {FD28A504-431E-49B9-BB8C-DCA0E7019F66} {73EAAEDA-557B-48D5-A137-328934720FB4} = {FD28A504-431E-49B9-BB8C-DCA0E7019F66} + {10757011-749D-4954-873B-AE38D8145472} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49} EndGlobalSection EndGlobal diff --git a/tst/fscrash/fscrash-main.c b/tst/fscrash/fscrash-main.c new file mode 100644 index 00000000..588e4c50 --- /dev/null +++ b/tst/fscrash/fscrash-main.c @@ -0,0 +1,90 @@ +/** + * @file fscrash-main.c + * + * @copyright 2015-2016 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the GNU + * General Public License version 3 as published by the Free Software + * Foundation. + * + * Licensees holding a valid commercial license may use this file in + * accordance with the commercial license agreement provided with the + * software. + */ + +#include + +#include "fscrash.h" +#include "memfs.h" + +#define fail(format, ...) fprintf(stderr, format, __VA_ARGS__) + +ULONG OptCrashMask = -1, OptCrashFlags = FspCrashInterceptAccessViolation, OptCrashPercent = 10; +ULONG OptMemfsFlags = MemfsDisk; + +int wmain(int argc, wchar_t **argv) +{ + for (int argi = 1; argc > argi; argi++) + { + const wchar_t *a = argv[argi]; + if ('-' == a[0]) + { + if (0 == wcsncmp(L"--mask=", a, sizeof "--mask=" - 1)) + OptCrashMask = wcstoul(a + sizeof "--mask=" - 1, 0, 0); + else if (0 == wcsncmp(L"--percent=", a, sizeof "--percent=" - 1)) + OptCrashPercent = wcstoul(a + sizeof "--percent=" - 1, 0, 10); + else if (0 == wcscmp(L"--crash", a)) + { + OptCrashFlags &= ~FspCrashInterceptTerminate; + OptCrashFlags |= FspCrashInterceptAccessViolation; + } + else if (0 == wcscmp(L"--terminate", a)) + { + OptCrashFlags &= ~FspCrashInterceptAccessViolation; + OptCrashFlags |= FspCrashInterceptTerminate; + } + else if (0 == wcscmp(L"--enter", a)) + OptCrashFlags |= FspCrashInterceptEnter; + else if (0 == wcscmp(L"--leave", a)) + OptCrashFlags |= FspCrashInterceptLeave; + else if (0 == wcscmp(L"--disk", a)) + OptMemfsFlags = MemfsDisk; + else if (0 == wcscmp(L"--n", a)) + OptMemfsFlags = MemfsDisk; + } + } + + MEMFS *Memfs; + NTSTATUS Result; + + Result = MemfsCreate( + OptMemfsFlags, + -1, + 1024, + 1024 * 1024, + (MemfsNet & OptMemfsFlags) ? L"\\memfs\\share" : 0, + 0, + &Memfs); + if (!NT_SUCCESS(Result)) + { + fail("cannot create MEMFS file system: (Status=%lx)", Result); + exit(1); + } + + FspCrashIntercept(MemfsFileSystem(Memfs), OptCrashMask, OptCrashFlags, OptCrashPercent); + + Result = MemfsStart(Memfs); + if (!NT_SUCCESS(Result)) + { + fail("cannot start MEMFS file system: (Status=%lx)", Result); + exit(1); + } + + MemfsStop(Memfs); + MemfsDelete(Memfs); + + return 0; +} diff --git a/tst/fscrash/fscrash.c b/tst/fscrash/fscrash.c new file mode 100644 index 00000000..57990bf4 --- /dev/null +++ b/tst/fscrash/fscrash.c @@ -0,0 +1,132 @@ +/** + * @file fscrash.c + * + * @copyright 2015-2016 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the GNU + * General Public License version 3 as published by the Free Software + * Foundation. + * + * Licensees holding a valid commercial license may use this file in + * accordance with the commercial license agreement provided with the + * software. + */ + +#include "fscrash.h" + +static SRWLOCK FspCrashLock = SRWLOCK_INIT; +static FSP_FILE_SYSTEM *FspCrashFileSystem; +static ULONG FspCrashPercent; +static FSP_FILE_SYSTEM_OPERATION *FspCrashInterceptedOperations + [ARRAYSIZE(((FSP_FILE_SYSTEM *)0)->Operations)]; +static volatile PULONG FspCrashNullPointer; + +static unsigned FspCrashRandSeed = 1; +static int FspCrashRand(void) +{ + /* + * This mimics MSVCRT rand(); we need our own version + * as to not interfere with the program's rand(). + */ + + FspCrashRandSeed = FspCrashRandSeed * 214013 + 2531011; + return (FspCrashRandSeed >> 16) & RAND_MAX; +} + +static __forceinline BOOLEAN FspCrashInterceptTest(FSP_FILE_SYSTEM *FileSystem) +{ + BOOLEAN Result; + AcquireSRWLockShared(&FspCrashLock); + Result = FileSystem == FspCrashFileSystem && + FspCrashRand() < (LONG)FspCrashPercent * 0x7fff / 100; + ReleaseSRWLockShared(&FspCrashLock); + return Result; +} + +#define DefineInterceptor(NAME, CRASH, ENTER, LEAVE)\ + static NTSTATUS NAME(FSP_FILE_SYSTEM *FileSystem,\ + FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)\ + {\ + NTSTATUS Result;\ + if (ENTER)\ + {\ + if (FspCrashInterceptTest(FileSystem))\ + {\ + if (CRASH)\ + *FspCrashNullPointer = 0x42424242;\ + else\ + TerminateProcess(GetCurrentProcess(), STATUS_UNSUCCESSFUL);\ + }\ + }\ + Result = FspCrashInterceptedOperations[Request->Kind](FileSystem, Request, Response);\ + if (LEAVE)\ + {\ + if (FspCrashInterceptTest(FileSystem))\ + {\ + if (CRASH)\ + *FspCrashNullPointer = 0x42424242;\ + else\ + TerminateProcess(GetCurrentProcess(), STATUS_UNSUCCESSFUL);\ + }\ + }\ + return Result;\ + } + +DefineInterceptor(FspCrashInterceptorCE, TRUE, TRUE, FALSE) +DefineInterceptor(FspCrashInterceptorCL, TRUE, FALSE, TRUE) +DefineInterceptor(FspCrashInterceptorCB, TRUE, TRUE, TRUE) +DefineInterceptor(FspCrashInterceptorTE, FALSE, TRUE, FALSE) +DefineInterceptor(FspCrashInterceptorTL, FALSE, FALSE, TRUE) +DefineInterceptor(FspCrashInterceptorTB, FALSE, TRUE, TRUE) + +VOID FspCrashIntercept(FSP_FILE_SYSTEM *FileSystem, + ULONG CrashMask, ULONG CrashFlags, ULONG CrashPercent) +{ + FSP_FILE_SYSTEM_OPERATION *Interceptor = 0; + + if (CrashFlags & FspCrashInterceptAccessViolation) + { + if (FspCrashInterceptEnter == (CrashFlags & FspCrashInterceptEnter)) + Interceptor = FspCrashInterceptorCE; + else + if (FspCrashInterceptLeave == (CrashFlags & FspCrashInterceptLeave)) + Interceptor = FspCrashInterceptorCL; + else + Interceptor = FspCrashInterceptorCB; + } + else + { + if (FspCrashInterceptEnter == (CrashFlags & FspCrashInterceptEnter)) + Interceptor = FspCrashInterceptorTE; + else + if (FspCrashInterceptLeave == (CrashFlags & FspCrashInterceptLeave)) + Interceptor = FspCrashInterceptorTL; + else + Interceptor = FspCrashInterceptorTB; + } + + RtlCopyMemory(FspCrashInterceptedOperations, + FileSystem->Operations, sizeof FileSystem->Operations); + + for (ULONG Index = 0; ARRAYSIZE(FileSystem->Operations) > Index; Index++) + if (0 != ((1 << Index) & CrashMask) && 0 != FileSystem->Operations[Index]) + FileSystem->Operations[Index] = Interceptor; + + FspCrashPercent = CrashPercent; + + FspCrashRandSeed = GetTickCount(); + if (0 == FspCrashRandSeed) + FspCrashRandSeed = 1; + + MemoryBarrier(); +} + +VOID FspCrash(FSP_FILE_SYSTEM *FileSystem) +{ + AcquireSRWLockExclusive(&FspCrashLock); + FspCrashFileSystem = FileSystem; + ReleaseSRWLockExclusive(&FspCrashLock); +} diff --git a/tst/fscrash/fscrash.h b/tst/fscrash/fscrash.h new file mode 100644 index 00000000..feeec606 --- /dev/null +++ b/tst/fscrash/fscrash.h @@ -0,0 +1,43 @@ +/** + * @file fscrash.h + * + * @copyright 2015-2016 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the GNU + * General Public License version 3 as published by the Free Software + * Foundation. + * + * Licensees holding a valid commercial license may use this file in + * accordance with the commercial license agreement provided with the + * software. + */ + +#ifndef FSCRASH_H_INCLUDED +#define FSCRASH_H_INCLUDED + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum +{ + FspCrashInterceptAccessViolation = 0x01, + FspCrashInterceptTerminate = 0x02, + FspCrashInterceptEnter = 0x10, + FspCrashInterceptLeave = 0x20, +}; + +VOID FspCrashIntercept(FSP_FILE_SYSTEM *FileSystem, + ULONG CrashMask, ULONG CrashFlags, ULONG CrashPercent); +VOID FspCrash(FSP_FILE_SYSTEM *FileSystem); + +#ifdef __cplusplus +} +#endif + +#endif