You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
569 lines
16 KiB
569 lines
16 KiB
#include "stdinc.h"
|
|
#include "st.h"
|
|
#include "stressharness.h"
|
|
#include "wfp.h"
|
|
|
|
#define WFP_INI_SECTION (L"wfp")
|
|
#define WFP_INI_KEY_VICTIM (L"Victim")
|
|
#define WFP_INI_KEY_MODE (L"Mode")
|
|
#define WFP_INI_KEY_USE_SHORTFNAME (L"UseShortnameFile")
|
|
#define WFP_INI_KEY_USE_SHORTDNAME (L"UseShortnameDir")
|
|
#define WFP_INI_KEY_INSTALL (L"InstallManifest")
|
|
#define WFP_INI_KEY_PAUSE_AFTER (L"PauseLength")
|
|
|
|
#define WFP_INI_KEY_MODE_DELETE_FILES (L"DeleteFiles")
|
|
#define WFP_INI_KEY_MODE_TOUCH_FILES (L"TouchFiles")
|
|
#define WFP_INI_KEY_MODE_DELETE_DIR (L"DeleteDirectory")
|
|
#define WFP_INI_KEY_MODE_DELETE_MAN (L"DeleteManifest")
|
|
#define WFP_INI_KEY_MODE_DELETE_CAT (L"DeleteCatalog")
|
|
#define WFP_INI_KEY_MODE_HAVOC (L"Havoc")
|
|
#define WFP_INI_KEY_MODE_DEFAULT (WFP_INI_KEY_MODE_DELETE_FILES)
|
|
|
|
BOOL
|
|
SxspGenerateSxsPath(
|
|
IN DWORD Flags,
|
|
IN ULONG PathType,
|
|
IN PCWSTR AssemblyRootDirectory OPTIONAL,
|
|
IN SIZE_T AssemblyRootDirectoryCch OPTIONAL,
|
|
IN PCASSEMBLY_IDENTITY pAssemblyIdentity,
|
|
OUT CBaseStringBuffer &PathBuffer
|
|
)
|
|
{
|
|
PROBING_ATTRIBUTE_CACHE pac = { 0 };
|
|
|
|
return SxspGenerateSxsPath(
|
|
Flags,
|
|
PathType,
|
|
AssemblyRootDirectory,
|
|
AssemblyRootDirectoryCch,
|
|
pAssemblyIdentity,
|
|
&pac,
|
|
PathBuffer);
|
|
}
|
|
|
|
CWfpJobEntry::~CWfpJobEntry()
|
|
{
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Defaulted
|
|
//
|
|
BOOL
|
|
CWfpJobEntry::SetupSelfForRun()
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CWfpJobEntry::Cleanup()
|
|
{
|
|
FN_PROLOG_WIN32
|
|
|
|
IFW32FALSE_EXIT(CStressJobEntry::Cleanup());
|
|
|
|
if ( this->m_buffManifestToInstall.Cch() != 0 )
|
|
{
|
|
//
|
|
// Uninstall the assembly that we added
|
|
//
|
|
SXS_UNINSTALLW Uninstall = { sizeof(Uninstall) };
|
|
|
|
Uninstall.dwFlags = SXS_UNINSTALL_FLAG_FORCE_DELETE;
|
|
Uninstall.lpAssemblyIdentity = this->m_buffVictimAssemblyIdentity;
|
|
IFW32FALSE_EXIT(SxsUninstallW(&Uninstall, NULL));
|
|
|
|
}
|
|
|
|
FN_EPILOG
|
|
}
|
|
|
|
|
|
BOOL
|
|
CWfpJobEntry::GenFileListFrom(
|
|
PCWSTR pcwszPath,
|
|
CFusionArray < CStringBuffer > & tgt
|
|
)
|
|
{
|
|
FN_PROLOG_WIN32
|
|
|
|
CStringBuffer buffTemp;
|
|
CFindFile ffile;
|
|
WIN32_FIND_DATAW findData;
|
|
|
|
IFW32FALSE_EXIT(tgt.Win32Reset());
|
|
IFW32FALSE_EXIT(buffTemp.Win32Assign(pcwszPath, ::wcslen(pcwszPath)));
|
|
IFW32FALSE_EXIT(buffTemp.Win32RemoveLastPathElement());
|
|
|
|
ffile.Win32FindFirstFile( pcwszPath, &findData );
|
|
if ( ffile != ffile.GetInvalidValue() ) do
|
|
{
|
|
IFW32FALSE_EXIT(buffTemp.Win32AppendPathElement(
|
|
findData.cFileName,
|
|
wcslen(findData.cFileName)));
|
|
IFW32FALSE_EXIT(tgt.Win32Append(buffTemp));
|
|
}
|
|
while ( ::FindNextFileW(ffile, &findData) );
|
|
|
|
FN_EPILOG
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
CWfpJobEntry::RunTest(
|
|
bool &rfTestSuccessful
|
|
)
|
|
{
|
|
FN_PROLOG_WIN32;
|
|
|
|
CSmartAssemblyIdentity pIdent;
|
|
CSmallStringBuffer buffAssemblyRoot;
|
|
|
|
SxspGetAssemblyRootDirectory(buffAssemblyRoot);
|
|
|
|
if ( m_buffVictimAssemblyIdentity.Cch() == 0 )
|
|
{
|
|
//
|
|
// Pick an installed assembly at random from the manifests
|
|
// directory.
|
|
//
|
|
CStringBuffer buffRootDir;
|
|
CFusionArray<CStringBuffer> arrManifestsInstalled;
|
|
|
|
SxspGetAssemblyRootDirectory(buffRootDir);
|
|
buffRootDir.Win32AppendPathElement(L"Manifests\\*.manifest", ::wcslen(L"Manifests\\*.manifest"));
|
|
this->GenFileListFrom(buffRootDir, arrManifestsInstalled);
|
|
|
|
//
|
|
// Repeatedly try getting info on different manifests
|
|
//
|
|
do
|
|
{
|
|
SIZE_T iWhich = rand() % arrManifestsInstalled.GetSize();
|
|
|
|
struct
|
|
{
|
|
SXS_MANIFEST_INFORMATION_BASIC Info;
|
|
WCHAR wchBuffer[MAX_PATH*3];
|
|
} ManifestInfo;
|
|
|
|
if ( SxsQueryManifestInformation(
|
|
0,
|
|
arrManifestsInstalled[iWhich],
|
|
SXS_QUERY_MANIFEST_INFORMATION_INFOCLASS_BASIC,
|
|
SXS_QUERY_MANIFEST_INFORMATION_INFOCLASS_BASIC_FLAG_OMIT_SHORTNAME,
|
|
sizeof(ManifestInfo),
|
|
&ManifestInfo,
|
|
NULL) )
|
|
{
|
|
m_buffVictimAssemblyIdentity.Win32Assign(
|
|
ManifestInfo.Info.lpIdentity,
|
|
wcslen(ManifestInfo.Info.lpIdentity));
|
|
break;
|
|
}
|
|
|
|
}
|
|
while ( TRUE );
|
|
|
|
}
|
|
|
|
if ( ( m_buffVictimAssemblyIdentity.Cch() != 0 ) && ( pIdent == NULL ) )
|
|
{
|
|
SxspCreateAssemblyIdentityFromTextualString(
|
|
m_buffVictimAssemblyIdentity,
|
|
&pIdent);
|
|
}
|
|
|
|
switch ( this->m_eChangeMode )
|
|
{
|
|
case eWfpChangeDeleteFile:
|
|
case eWfpChangeTouchFile:
|
|
{
|
|
int iMethod = rand() % 5;
|
|
CStringBuffer buffAssemblyPath;
|
|
CFusionArray<CStringBuffer> buffPickFileList;
|
|
|
|
//
|
|
// Pick a file
|
|
//
|
|
SxspGenerateSxsPath(
|
|
0,
|
|
SXSP_GENERATE_SXS_PATH_PATHTYPE_ASSEMBLY,
|
|
buffAssemblyRoot,
|
|
buffAssemblyRoot.Cch(),
|
|
pIdent,
|
|
buffAssemblyPath);
|
|
|
|
GenFileListFrom(buffAssemblyPath, buffPickFileList);
|
|
CStringBuffer &cbuffVictim = buffPickFileList[rand() % buffPickFileList.GetSize()];
|
|
|
|
if ( iMethod == 0 )
|
|
{
|
|
//
|
|
// Touch the timestamp
|
|
//
|
|
CFusionFile ffile;
|
|
FILETIME ft = { 0, 0 };
|
|
|
|
IFW32FALSE_EXIT(ffile.Win32CreateFile(
|
|
cbuffVictim,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
OPEN_EXISTING));
|
|
|
|
::SetFileTime(ffile, &ft, &ft, &ft );
|
|
}
|
|
else if ( iMethod == 1 )
|
|
{
|
|
//
|
|
// Read from the file
|
|
//
|
|
CFusionFile ffile;
|
|
BYTE buff[20];
|
|
DWORD dwRead;
|
|
|
|
IFW32FALSE_EXIT(ffile.Win32CreateFile(
|
|
cbuffVictim,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
OPEN_EXISTING));
|
|
|
|
::ReadFile( ffile, buff, sizeof(buff), &dwRead, NULL);
|
|
}
|
|
else if ( iMethod == 2 )
|
|
{
|
|
//
|
|
// Write to an alternate stream
|
|
//
|
|
CFusionFile ffile;
|
|
DWORD dwWrite;
|
|
static const WCHAR pcwszThing[] = L"thing";
|
|
|
|
cbuffVictim.Win32Append(L":dummy", 6);
|
|
|
|
IFW32FALSE_EXIT(ffile.Win32CreateFile(
|
|
cbuffVictim,
|
|
GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
OPEN_EXISTING));
|
|
|
|
::WriteFile( ffile, pcwszThing, sizeof(pcwszThing), &dwWrite, NULL);
|
|
}
|
|
else if ( iMethod == 3 )
|
|
{
|
|
}
|
|
else if ( iMethod == 4 )
|
|
{
|
|
}
|
|
}
|
|
break;
|
|
|
|
case eWfpChangeDeleteDirectory:
|
|
{
|
|
//
|
|
// Create a list of files to delete in the directory, then blow
|
|
// them away. This is probably more guaranteed to get everything
|
|
// deleted while WFP is running...
|
|
//
|
|
CStringBuffer buffPath;
|
|
CFusionArray<CStringBuffer> arrFilenames;
|
|
CFindFile finder;
|
|
WIN32_FIND_DATAW findData;
|
|
|
|
SxspGenerateSxsPath(
|
|
0,
|
|
SXSP_GENERATE_SXS_PATH_PATHTYPE_ASSEMBLY,
|
|
buffAssemblyRoot,
|
|
buffAssemblyRoot.Cch(),
|
|
pIdent,
|
|
buffPath);
|
|
|
|
IFW32FALSE_EXIT(arrFilenames.Win32Initialize());
|
|
IFW32FALSE_EXIT(buffPath.Win32AppendPathElement(L"*", 1));
|
|
finder.Win32FindFirstFile(buffPath, &findData);
|
|
IFW32FALSE_EXIT(buffPath.Win32RemoveLastPathElement());
|
|
|
|
if ( finder != finder.GetInvalidValue() ) do
|
|
{
|
|
buffPath.Win32AppendPathElement(findData.cFileName, ::wcslen(findData.cFileName));
|
|
arrFilenames.Win32Append(buffPath);
|
|
buffPath.Win32RemoveLastPathElement();
|
|
}
|
|
while( FindNextFileW( finder, &findData ) );
|
|
|
|
//
|
|
// Now go delete them all.
|
|
//
|
|
for ( SIZE_T ul = 0; ul < arrFilenames.GetSize(); ul++ )
|
|
{
|
|
DeleteFileW( arrFilenames[ul] );
|
|
}
|
|
|
|
//
|
|
// And delete the directory
|
|
//
|
|
RemoveDirectoryW(buffPath);
|
|
}
|
|
break;
|
|
|
|
case eWfpChangeDeleteManifest:
|
|
case eWfpChangeDeleteCatalog:
|
|
{
|
|
CStringBuffer buffTemp;
|
|
int iOperation = rand() % 2;
|
|
|
|
//
|
|
// Generate the path to this manifest
|
|
//
|
|
SxspGenerateSxsPath(
|
|
0,
|
|
SXSP_GENERATE_SXS_PATH_PATHTYPE_MANIFEST,
|
|
buffAssemblyRoot,
|
|
buffAssemblyRoot.Cch(),
|
|
pIdent,
|
|
buffTemp);
|
|
|
|
if ( this->m_eChangeMode == eWfpChangeDeleteCatalog )
|
|
{
|
|
IFW32FALSE_EXIT(buffTemp.Win32ChangePathExtension(
|
|
FILE_EXTENSION_CATALOG,
|
|
FILE_EXTENSION_CATALOG_CCH,
|
|
eErrorIfNoExtension));
|
|
}
|
|
|
|
if ( iOperation == 0 )
|
|
{
|
|
DeleteFileW(buffTemp);
|
|
}
|
|
else
|
|
{
|
|
CFusionFile ffile;
|
|
if ( ffile.Win32CreateFile( buffTemp, GENERIC_WRITE, FILE_SHARE_READ, OPEN_EXISTING ) )
|
|
{
|
|
DWORD dwWritten;
|
|
WriteFile(ffile, "boom", 4, &dwWritten, NULL);
|
|
}
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
//
|
|
// Go change everything everywhere. 50% of the time, delete the file.
|
|
// 25% of the time, change the file. 25% of the time, open the file, change it,
|
|
// then hold it open.
|
|
//
|
|
case eWfpChangeCompleteHavoc:
|
|
{
|
|
CStringBuffer buffTemp;
|
|
WIN32_FIND_DATAW data;
|
|
CFindFile finder;
|
|
|
|
SxspGetAssemblyRootDirectory(buffTemp);
|
|
|
|
buffTemp.Win32AppendPathElement(L"*", 1);
|
|
finder.Win32FindFirstFile(buffTemp, &data);
|
|
IFW32FALSE_EXIT(buffTemp.Win32RemoveLastPathElement());
|
|
|
|
if ( finder != finder.GetInvalidValue() ) do
|
|
{
|
|
//
|
|
// 1/3 chance of actually hitting the directory
|
|
//
|
|
if ( ( rand() % 3 ) != 1 ) continue;
|
|
|
|
CFindFile finder2;
|
|
WIN32_FIND_DATAW data2;
|
|
|
|
buffTemp.Win32AppendPathElement(buffTemp);
|
|
buffTemp.Win32AppendPathElement(L"*", 1);
|
|
finder2.Win32FindFirstFile(buffTemp, &data2);
|
|
buffTemp.Win32RemoveLastPathElement();
|
|
|
|
if ( finder2 != finder.GetInvalidValue() ) do
|
|
{
|
|
//
|
|
// 50% chance of hitting this file
|
|
//
|
|
if ( ( rand() % 2 ) == 1 ) continue;
|
|
|
|
CStringBuffer ActualTarget;
|
|
int iOperation = rand() % 4;
|
|
|
|
ActualTarget.Win32Assign(buffTemp);
|
|
ActualTarget.Win32AppendPathElement(data2.cFileName, ::wcslen(data2.cFileName));
|
|
|
|
//
|
|
// Most often, we'll just nuke the file
|
|
//
|
|
if ( ( iOperation == 0 ) || ( iOperation == 1 ) )
|
|
{
|
|
::DeleteFileW(ActualTarget);
|
|
}
|
|
//
|
|
// Just touch the first few bytes of the file.
|
|
//
|
|
else if ( ( iOperation == 2 ) || ( iOperation == 3 ) )
|
|
{
|
|
CFusionFile ffile;
|
|
DWORD dwWritten;
|
|
|
|
if ( ffile.Win32CreateFile(
|
|
ActualTarget,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
OPEN_EXISTING))
|
|
{
|
|
WriteFile( ffile, "boom", 4, &dwWritten, NULL );
|
|
}
|
|
|
|
//
|
|
// 20 seconds sounds good enough
|
|
//
|
|
if ( iOperation == 3 )
|
|
{
|
|
::Sleep(5000);
|
|
}
|
|
|
|
}
|
|
}
|
|
while ( FindNextFileW( finder2, &data2 ) );
|
|
|
|
buffTemp.Win32RemoveLastPathElement();
|
|
}
|
|
while ( FindNextFileW(finder, &data) );
|
|
}
|
|
break;
|
|
}
|
|
|
|
rfTestSuccessful = true;
|
|
|
|
FN_EPILOG
|
|
}
|
|
|
|
|
|
CWfpJobEntry::LoadFromSettingsFile(
|
|
PCWSTR pcwszSettingsFile
|
|
)
|
|
{
|
|
FN_PROLOG_WIN32
|
|
|
|
CSmallStringBuffer buffJunk;
|
|
INT iJunk;
|
|
|
|
//
|
|
// Are we using shortnames for files?
|
|
//
|
|
IFW32FALSE_EXIT(SxspIsPrivateProfileStringEqual(
|
|
WFP_INI_SECTION,
|
|
WFP_INI_KEY_USE_SHORTFNAME,
|
|
L"no",
|
|
this->m_fUseShortnameFile,
|
|
pcwszSettingsFile));
|
|
|
|
//
|
|
// Are we using shortnames for directories?
|
|
//
|
|
IFW32FALSE_EXIT(SxspIsPrivateProfileStringEqual(
|
|
WFP_INI_SECTION,
|
|
WFP_INI_KEY_USE_SHORTDNAME,
|
|
L"no",
|
|
this->m_fUseShortnameDirectory,
|
|
pcwszSettingsFile));
|
|
|
|
//
|
|
// How long are we to wait between twiddling and uninstalling?
|
|
//
|
|
IFW32FALSE_EXIT(SxspGetPrivateProfileIntW(
|
|
WFP_INI_SECTION,
|
|
WFP_INI_KEY_PAUSE_AFTER,
|
|
5000,
|
|
iJunk,
|
|
pcwszSettingsFile));
|
|
this->m_dwPauseBetweenTwiddleAndUninstall = iJunk;
|
|
|
|
//
|
|
// The test mode
|
|
//
|
|
IFW32FALSE_EXIT(SxspGetPrivateProfileStringW(
|
|
WFP_INI_SECTION,
|
|
WFP_INI_KEY_MODE,
|
|
WFP_INI_KEY_MODE_DEFAULT,
|
|
buffJunk,
|
|
pcwszSettingsFile));
|
|
|
|
#define TEST_MODE( mds, mdn ) if (FusionpStrCmpI((WFP_INI_KEY_MODE_##mds), buffJunk) == 0) this->m_eChangeMode = mdn
|
|
TEST_MODE(DELETE_FILES, eWfpChangeDeleteFile);
|
|
TEST_MODE(TOUCH_FILES, eWfpChangeTouchFile);
|
|
TEST_MODE(DELETE_DIR, eWfpChangeDeleteDirectory);
|
|
TEST_MODE(DELETE_MAN, eWfpChangeDeleteManifest);
|
|
TEST_MODE(DELETE_CAT, eWfpChangeDeleteCatalog);
|
|
TEST_MODE(HAVOC, eWfpChangeCompleteHavoc);
|
|
|
|
//
|
|
// The victim assembly identity
|
|
//
|
|
IFW32FALSE_EXIT(SxspGetPrivateProfileStringW(
|
|
WFP_INI_SECTION,
|
|
WFP_INI_KEY_VICTIM,
|
|
L"",
|
|
m_buffVictimAssemblyIdentity,
|
|
pcwszSettingsFile));
|
|
|
|
//
|
|
// Are we installing an assembly to do this to?
|
|
//
|
|
IFW32FALSE_EXIT(SxspGetPrivateProfileStringW(
|
|
WFP_INI_SECTION,
|
|
WFP_INI_KEY_INSTALL,
|
|
L"",
|
|
buffJunk,
|
|
pcwszSettingsFile));
|
|
|
|
if ( buffJunk.Cch() != 0 )
|
|
{
|
|
IFW32FALSE_EXIT(this->m_buffManifestToInstall.Win32Assign(this->m_buffTestDirectory));
|
|
IFW32FALSE_EXIT(this->m_buffManifestToInstall.Win32AppendPathElement( buffJunk ));
|
|
}
|
|
|
|
FN_EPILOG
|
|
}
|
|
|
|
|
|
|
|
|
|
CWfpJobManager::CWfpJobManager()
|
|
{
|
|
//
|
|
// Nothing
|
|
//
|
|
}
|
|
|
|
|
|
|
|
|
|
CWfpJobManager::~CWfpJobManager()
|
|
{
|
|
//
|
|
// Nothing
|
|
//
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
CWfpJobManager::CreateJobEntry(
|
|
CStressJobEntry* &rpJobEntry
|
|
)
|
|
{
|
|
FN_PROLOG_WIN32
|
|
rpJobEntry = NULL;
|
|
rpJobEntry = FUSION_NEW_SINGLETON(CWfpJobEntry(this));
|
|
FN_EPILOG
|
|
}
|
|
|
|
|