From 495c78eb25d8a3827e1cf9ac1920166b5b0b6101 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Sun, 12 Feb 2017 00:26:20 -0800 Subject: [PATCH] tst: winfsp-tests: exec-test --- build/VStudio/testing/winfsp-tests.vcxproj | 4 + .../testing/winfsp-tests.vcxproj.filters | 8 + tst/winfsp-tests/exec-test.c | 228 ++++++++++++++++++ tst/winfsp-tests/helper/build.bat | 13 + .../helper/winfsp-tests-helper-x64.exe | Bin 0 -> 3584 bytes .../helper/winfsp-tests-helper-x86.exe | Bin 0 -> 3072 bytes tst/winfsp-tests/helper/winfsp-tests-helper.c | 104 ++++++++ .../helper/winfsp-tests-helper.rc | 2 + tst/winfsp-tests/hooks.c | 32 +++ tst/winfsp-tests/winfsp-tests.c | 1 + tst/winfsp-tests/winfsp-tests.h | 12 + 11 files changed, 404 insertions(+) create mode 100644 tst/winfsp-tests/exec-test.c create mode 100644 tst/winfsp-tests/helper/build.bat create mode 100644 tst/winfsp-tests/helper/winfsp-tests-helper-x64.exe create mode 100644 tst/winfsp-tests/helper/winfsp-tests-helper-x86.exe create mode 100644 tst/winfsp-tests/helper/winfsp-tests-helper.c create mode 100644 tst/winfsp-tests/helper/winfsp-tests-helper.rc diff --git a/build/VStudio/testing/winfsp-tests.vcxproj b/build/VStudio/testing/winfsp-tests.vcxproj index c15e3f4a..9bbe80cb 100644 --- a/build/VStudio/testing/winfsp-tests.vcxproj +++ b/build/VStudio/testing/winfsp-tests.vcxproj @@ -185,6 +185,7 @@ + @@ -213,6 +214,9 @@ {4a7c0b21-9e10-4c81-92de-1493efcf24eb} + + + diff --git a/build/VStudio/testing/winfsp-tests.vcxproj.filters b/build/VStudio/testing/winfsp-tests.vcxproj.filters index a2afe2f8..9295b644 100644 --- a/build/VStudio/testing/winfsp-tests.vcxproj.filters +++ b/build/VStudio/testing/winfsp-tests.vcxproj.filters @@ -79,6 +79,9 @@ Source + + Source + @@ -91,4 +94,9 @@ Source + + + Source + + \ No newline at end of file diff --git a/tst/winfsp-tests/exec-test.c b/tst/winfsp-tests/exec-test.c new file mode 100644 index 00000000..fbe4814f --- /dev/null +++ b/tst/winfsp-tests/exec-test.c @@ -0,0 +1,228 @@ +/** + * @file exec-test.c + * + * @copyright 2015-2017 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 +#include +#include "memfs.h" + +#include "winfsp-tests.h" + +static NTSTATUS WriteResource( + HANDLE Handle, HANDLE Module, PWSTR ResourceName, PULONG PBytesTransferred) +{ + HRSRC Resource; + HGLOBAL ResourceGlob; + PVOID ResourceData; + DWORD ResourceSize; + + if ((Resource = FindResourceW(Module, ResourceName, RT_RCDATA)) && + (ResourceGlob = LoadResource(Module, Resource)) && + (ResourceData = LockResource(ResourceGlob)) && + (ResourceSize = SizeofResource(Module, Resource)) && + (WriteFile(Handle, ResourceData, ResourceSize, PBytesTransferred, 0))) + return STATUS_SUCCESS; + else + return FspNtStatusFromWin32(GetLastError()); +} + +static NTSTATUS ExtractHelperProgram(PWSTR FileName) +{ + HANDLE Handle; + ULONG BytesTransferred; + NTSTATUS Result; + + Handle = CreateFileW(FileName, + FILE_WRITE_DATA, FILE_SHARE_WRITE, 0, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (INVALID_HANDLE_VALUE == Handle) + return FspNtStatusFromWin32(GetLastError()); + + Result = WriteResource( + Handle, + 0, +#if defined(_WIN64) + L"winfsp-tests-helper-x64.exe", +#elif defined(_WIN32) + L"winfsp-tests-helper-x86.exe", +#else +#error +#endif + &BytesTransferred); + + CloseHandle(Handle); + + return Result; +} + +static NTSTATUS CreateHelperProcess(PWSTR FileName, ULONG Timeout, PHANDLE PProcess) +{ + HANDLE Event; + SECURITY_ATTRIBUTES EventAttributes; + WCHAR CommandLine[MAX_PATH + 64]; + STARTUPINFOW StartupInfo; + PROCESS_INFORMATION ProcessInfo; + DWORD WaitResult; + NTSTATUS Result; + + memset(&EventAttributes, 0, sizeof EventAttributes); + EventAttributes.nLength = sizeof EventAttributes; + EventAttributes.bInheritHandle = TRUE; + + Event = CreateEventW(&EventAttributes, TRUE, FALSE, 0); + if (0 == Event) + return FspNtStatusFromWin32(GetLastError()); + + StringCbPrintfW(CommandLine, sizeof CommandLine, L"\"%s\" %lx %lx", + FileName, (ULONG)(UINT_PTR)Event, Timeout); + + memset(&StartupInfo, 0, sizeof StartupInfo); + StartupInfo.cb = sizeof StartupInfo; + + // !!!: need hook + if (!CreateProcessW(FileName, CommandLine, 0, 0, TRUE, 0, 0, 0, &StartupInfo, &ProcessInfo)) + { + Result = FspNtStatusFromWin32(GetLastError()); + CloseHandle(Event); + return Result; + } + + WaitResult = WaitForSingleObject(Event, 3000); + if (WaitResult == WAIT_FAILED) + Result = FspNtStatusFromWin32(GetLastError()); + else if (WaitResult == WAIT_TIMEOUT) + Result = STATUS_UNSUCCESSFUL; + else + Result = STATUS_SUCCESS; + + CloseHandle(Event); + CloseHandle(ProcessInfo.hThread); + + if (!NT_SUCCESS(Result)) + CloseHandle(ProcessInfo.hProcess); + else + *PProcess = ProcessInfo.hProcess; + + return Result; +} + +static VOID ExecHelper(PWSTR FileName, ULONG Timeout, PHANDLE PProcess) +{ + NTSTATUS Result; + + Result = ExtractHelperProgram(FileName); + ASSERT(NT_SUCCESS(Result)); + + Result = CreateHelperProcess(FileName, Timeout, PProcess); + ASSERT(NT_SUCCESS(Result)); +} + +static VOID WaitHelper(HANDLE Process, ULONG Timeout) +{ + DWORD ExitCode; + + ASSERT(WAIT_OBJECT_0 == WaitForSingleObject(Process, Timeout + 1000)); + + ASSERT(GetExitCodeProcess(Process, &ExitCode)); + ASSERT(0 == ExitCode); + + ASSERT(CloseHandle(Process)); +} + +static void exec_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout) +{ + void *memfs = memfs_start_ex(Flags, FileInfoTimeout); + + WCHAR FilePath[MAX_PATH]; + HANDLE Process; + + StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\helper.exe", + Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs)); + + ExecHelper(FilePath, 0, &Process); + WaitHelper(Process, 0); + + ASSERT(DeleteFileW(FilePath)); + + memfs_stop(memfs); +} + +static void exec_test(void) +{ + if (NtfsTests) + { + WCHAR DirBuf[MAX_PATH]; + GetTestDirectory(DirBuf); + exec_dotest(-1, DirBuf, 0); + } + if (WinFspDiskTests) + { + exec_dotest(MemfsDisk, 0, 0); + exec_dotest(MemfsDisk, 0, 1000); + } + if (WinFspNetTests) + { + exec_dotest(MemfsNet, L"\\\\memfs\\share", 0); + exec_dotest(MemfsNet, L"\\\\memfs\\share", 1000); + } +} + +static void exec_delete_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout) +{ + void *memfs = memfs_start_ex(Flags, FileInfoTimeout); + + WCHAR FilePath[MAX_PATH]; + HANDLE Process; + + StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\helper.exe", + Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs)); + + ExecHelper(FilePath, 1000, &Process); + ASSERT(!DeleteFileW(FilePath)); + ASSERT(ERROR_ACCESS_DENIED == GetLastError()); + WaitHelper(Process, 1000); + + ASSERT(DeleteFileW(FilePath)); + + memfs_stop(memfs); +} + +static void exec_delete_test(void) +{ + if (NtfsTests) + { + WCHAR DirBuf[MAX_PATH]; + GetTestDirectory(DirBuf); + exec_delete_dotest(-1, DirBuf, 0); + } + if (WinFspDiskTests) + { + exec_delete_dotest(MemfsDisk, 0, 0); + exec_delete_dotest(MemfsDisk, 0, 1000); + } + if (WinFspNetTests) + { + exec_delete_dotest(MemfsNet, L"\\\\memfs\\share", 0); + exec_delete_dotest(MemfsNet, L"\\\\memfs\\share", 1000); + } +} + +void exec_tests(void) +{ + TEST(exec_test); + TEST(exec_delete_test); +} diff --git a/tst/winfsp-tests/helper/build.bat b/tst/winfsp-tests/helper/build.bat new file mode 100644 index 00000000..d0d0a287 --- /dev/null +++ b/tst/winfsp-tests/helper/build.bat @@ -0,0 +1,13 @@ +@echo off + +setlocal + +cd %~dp0 + +call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" x64 +cl /Fewinfsp-tests-helper-x64.exe /MT /W2 winfsp-tests-helper.c kernel32.lib shell32.lib /link /subsystem:console /nodefaultlib +del *.obj + +call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" x86 +cl /Fewinfsp-tests-helper-x86.exe /MT /W2 winfsp-tests-helper.c kernel32.lib shell32.lib /link /subsystem:console +del *.obj diff --git a/tst/winfsp-tests/helper/winfsp-tests-helper-x64.exe b/tst/winfsp-tests/helper/winfsp-tests-helper-x64.exe new file mode 100644 index 0000000000000000000000000000000000000000..b512fdf46a493ae27fc8980133897bf2d21730d2 GIT binary patch literal 3584 zcmeHJU5Fc16h4z=ZOkTVTsE?Z=_dDM? z_uO;uaPq>d?~|8^e0T-}qHRbXDd&CbR}bd!{pZ5;*`1eXx3%o$+5GWxQ*T)HRjW|d zi-lUPZtE+iZnbK9xu&OITGXrck{J($0)`vM`2_hy;pGDM|!y|fzr=$PVMqdA)Ngykmhkm&LhWW>=^8VlAvM6UU| zbPB=6!SK@Z+seuH1uBCm!8{jXmBcL35l3@h2_m)kQ8=d)-8%~WoeqBP7M!?kuGz4k z#h#pmcn|JAl$%bp9JfjZyFj$SJOB>I4>>YYxDN4#j*y_HoZmRMH~W8A zAibG3W;XLiL~Ldazi3~LeVsOf8j@~r7%8$-qLVff`#-1luMf8(&P24k9s##R|AC?L zk=EVgMh-K;K$s-8ULP_Ot>?y>L(`fa8cvS2X2yAlnB-5Z?`MtgsMG>7*<|2k00!S- zHcTSxWV?G1Y5Ji0AS0Yf;ABWzUIyZK{GH1V&<|uaYGyNwz;9u0GS7GBJculjHexp}` zz0Rcl0qN)IPwduFNu~v5aM8XH`|6v&8iLQ#J<22>q1WEG&Bxgc_}0uCrTd&LIPA44(#)Gkzj`XKr(wD~TwORDT}qmqN@ zhfF?`XXlHO@2n<}V2oPfLG(0-fawD!cJfAy2TVY^yhj=1TD&vF z9%qaavR|wIr%h=z^)!(d(kQe7>C?yu$??>fn}enkbw{vgfF*(5Z1CDV{_Q#Rv}aBG zXuVo3)JoZM&0L}lI$EhWO#z@{(vk=EY@umqEURu2O-?MDcIJdx!=Hu5#A3xX8?>Zl z*2;Fysu#^>lb+8kyqL+(ABvYM6{3AK5d==L literal 0 HcmV?d00001 diff --git a/tst/winfsp-tests/helper/winfsp-tests-helper-x86.exe b/tst/winfsp-tests/helper/winfsp-tests-helper-x86.exe new file mode 100644 index 0000000000000000000000000000000000000000..45805f49bf4b614992bf7505032cf5ce16a5c4dc GIT binary patch literal 3072 zcmeHJUuaup6hBEid)uZ>wly$V!CT0~@J~!rC)4erZu@k@M4Mz;ONVRI=GtZC&$zi6 zr8G{w?&0zw?scHxLm%sl3|f6^yFtsapiZm!l*)ui`Y=YJ5#r)GUviUJqCWYc^uYPf z`F`im_nq_Ia1t211vUU^L#|W+mQWH6iS_T7uhHD|^p`zwr(>gk$>QJWzi=gh}d9Yf#EIrjCsZb>O5H3zq zkf~bItpHEa7Ri*N5w#c_4BZrtjm#^+xp?hMj&rw9~RGJgnnN(aLtvYb0^T_BrDwT?n!X4IYCq;&{sP3O{k@@77zS7 zhTY@rQS-S!;SDeIU*5j^6_I!!NzX|(t$m4}sCelrTy-wdPkSW~*aO~c2^Ee%!B@Cv zH(0rD{U&c3kC;YmUwOFVvdcplSPoWPZKOp?p^D3i+Te2iSaEja{0~_P;{bh7^r66m zuy)9HS6osR?L|RJDP7?;`Y7&6=qzBf7);2|x+U&+JG<6#wP!nU-?qE8>V)v_7XOi~ zyD@jKt*UL=9$Z4xKK*+gnCJ&kk>5kUh5Rw{JTlR8O;&e})ts%}2+bq=Wn^=P;B(Oo z67$HNOo=G8)9muZY4*5}6K2joa~@HSJLDtglY4e{Ha0m;j(CS-gjZvI1RX=Hw}A~3 zb_y|f1ACD$s_p#-_7Y)xiQ-K9oOBsrv + +/* based on src/dll/fuse/fuse_opt.c */ +static long long wcstoint(const wchar_t *p, int base, int is_signed) +{ + long long v; + int maxdig, maxalp, sign = +1; + + if (is_signed) + { + if ('+' == *p) + p++; + else if ('-' == *p) + p++, sign = -1; + } + + if (0 == base) + { + if ('0' == *p) + { + p++; + if ('x' == *p || 'X' == *p) + { + p++; + base = 16; + } + else + base = 8; + } + else + { + base = 10; + } + } + + maxdig = 10 < base ? '9' : (base - 1) + '0'; + maxalp = 10 < base ? (base - 1 - 10) + 'a' : 0; + + for (v = 0; *p; p++) + { + int c = *p; + + if ('0' <= c && c <= maxdig) + v = base * v + (c - '0'); + else + { + c |= 0x20; + if ('a' <= c && c <= maxalp) + v = base * v + (c - 'a') + 10; + else + break; + } + } + + return sign * v; +} + +int wmain(int argc, wchar_t **argv) +{ + HANDLE Event; + ULONG Timeout; + + if (argc != 3) + return 1; + + Event = (HANDLE)(UINT_PTR)wcstoint(argv[1], 16, 0); + Timeout = wcstoint(argv[2], 16, 0); + + SetEvent(Event); + CloseHandle(Event); + + Sleep(Timeout); + + return 0; +} + +void wmainCRTStartup(void) +{ + DWORD Argc; + PWSTR *Argv; + + Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); + if (0 == Argv) + ExitProcess(GetLastError()); + + ExitProcess(wmain(Argc, Argv)); +} diff --git a/tst/winfsp-tests/helper/winfsp-tests-helper.rc b/tst/winfsp-tests/helper/winfsp-tests-helper.rc new file mode 100644 index 00000000..afe77f60 --- /dev/null +++ b/tst/winfsp-tests/helper/winfsp-tests-helper.rc @@ -0,0 +1,2 @@ +winfsp-tests-helper-x64.exe RCDATA "winfsp-tests-helper-x64.exe" +winfsp-tests-helper-x86.exe RCDATA "winfsp-tests-helper-x86.exe" diff --git a/tst/winfsp-tests/hooks.c b/tst/winfsp-tests/hooks.c index ec32c59c..ed736999 100644 --- a/tst/winfsp-tests/hooks.c +++ b/tst/winfsp-tests/hooks.c @@ -427,3 +427,35 @@ BOOL WINAPI HookSetCurrentDirectoryW( MaybeAdjustTraversePrivilege(TRUE); return Success; } + +BOOL WINAPI HookCreateProcessW( + LPCWSTR lpApplicationName, + LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCWSTR lpCurrentDirectory, + LPSTARTUPINFOW lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation) +{ + WCHAR FileNameBuf[FILENAMEBUF_SIZE]; + BOOL Success; + + PrepareFileName(lpApplicationName, FileNameBuf); + + MaybeAdjustTraversePrivilege(FALSE); + Success = CreateProcessW(FileNameBuf, + lpCommandLine, /* we should probably change this as well */ + lpProcessAttributes, + lpThreadAttributes, + bInheritHandles, + dwCreationFlags, + lpEnvironment, + lpCurrentDirectory, + lpStartupInfo, + lpProcessInformation); + MaybeAdjustTraversePrivilege(TRUE); + return Success; +} diff --git a/tst/winfsp-tests/winfsp-tests.c b/tst/winfsp-tests/winfsp-tests.c index 1c296089..b5053caa 100644 --- a/tst/winfsp-tests/winfsp-tests.c +++ b/tst/winfsp-tests/winfsp-tests.c @@ -194,6 +194,7 @@ int main(int argc, char *argv[]) TESTSUITE(flush_tests); TESTSUITE(lock_tests); TESTSUITE(dirctl_tests); + TESTSUITE(exec_tests); TESTSUITE(reparse_tests); TESTSUITE(stream_tests); TESTSUITE(oplock_tests); diff --git a/tst/winfsp-tests/winfsp-tests.h b/tst/winfsp-tests/winfsp-tests.h index fe5e1ad9..67aa7cdc 100644 --- a/tst/winfsp-tests/winfsp-tests.h +++ b/tst/winfsp-tests/winfsp-tests.h @@ -85,6 +85,17 @@ static inline BOOL RealSetCurrentDirectoryW( { return SetCurrentDirectoryW(lpPathName); } +BOOL WINAPI HookCreateProcessW( + LPCWSTR lpApplicationName, + LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCWSTR lpCurrentDirectory, + LPSTARTUPINFOW lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation); #if !defined(WINFSP_TESTS_NO_HOOKS) #define CreateFileW HookCreateFileW #define CloseHandle HookCloseHandle @@ -99,6 +110,7 @@ static inline BOOL RealSetCurrentDirectoryW( #define GetVolumeInformationW HookGetVolumeInformationW #define SetVolumeLabelW HookSetVolumeLabelW #define SetCurrentDirectoryW HookSetCurrentDirectoryW +#define CreateProcessW HookCreateProcessW #endif HANDLE WINAPI ResilientCreateFileW(