// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// f32test\loader\security\t_fuzzldr.cpp
//
//
#define __E32TEST_EXTENSION__
#include <e32test.h>
#include <e32svr.h>
#include <e32uid.h>
#include <f32file.h>
#include <f32image.h>
#include "t_hash.h"
// Fuzzing parameters
const TInt KFuzzImages = 5;
const TInt KRandomFieldIterations = 8;
const TTimeIntervalMicroSeconds32 KDllTimeout = 10 * 1000000;
#define FUZZFIELD(OBJ, NAME) { (const TText*)(L ## #OBJ L"." L ## #NAME), sizeof(((OBJ*)8)->NAME), _FOFF(OBJ, NAME) }
#define DUMBFIELD(NAME, SIZE, OFFSET) { (const TText*)L ## NAME, SIZE, OFFSET }
#define FUZZEND { NULL, 0, 0 }
struct SFuzzField
{
const TText* name;
TInt size;
TInt offset;
};
const SFuzzField HeaderFields[] =
{
FUZZFIELD(E32ImageHeaderV, iUid1),
FUZZFIELD(E32ImageHeaderV, iUid2),
FUZZFIELD(E32ImageHeaderV, iUid3),
FUZZFIELD(E32ImageHeaderV, iUidChecksum),
FUZZFIELD(E32ImageHeaderV, iSignature),
FUZZFIELD(E32ImageHeaderV, iHeaderCrc),
FUZZFIELD(E32ImageHeaderV, iModuleVersion),
FUZZFIELD(E32ImageHeaderV, iCompressionType),
FUZZFIELD(E32ImageHeaderV, iToolsVersion.iMajor),
FUZZFIELD(E32ImageHeaderV, iToolsVersion.iMinor),
FUZZFIELD(E32ImageHeaderV, iToolsVersion.iBuild),
FUZZFIELD(E32ImageHeaderV, iTimeLo),
FUZZFIELD(E32ImageHeaderV, iTimeHi),
FUZZFIELD(E32ImageHeaderV, iFlags),
FUZZFIELD(E32ImageHeaderV, iCodeSize),
FUZZFIELD(E32ImageHeaderV, iDataSize),
FUZZFIELD(E32ImageHeaderV, iHeapSizeMin),
FUZZFIELD(E32ImageHeaderV, iHeapSizeMax),
FUZZFIELD(E32ImageHeaderV, iStackSize),
FUZZFIELD(E32ImageHeaderV, iBssSize),
FUZZFIELD(E32ImageHeaderV, iEntryPoint),
FUZZFIELD(E32ImageHeaderV, iCodeBase),
FUZZFIELD(E32ImageHeaderV, iDataBase),
FUZZFIELD(E32ImageHeaderV, iDllRefTableCount),
FUZZFIELD(E32ImageHeaderV, iExportDirOffset),
FUZZFIELD(E32ImageHeaderV, iExportDirCount),
FUZZFIELD(E32ImageHeaderV, iTextSize),
FUZZFIELD(E32ImageHeaderV, iCodeOffset),
FUZZFIELD(E32ImageHeaderV, iDataOffset),
FUZZFIELD(E32ImageHeaderV, iImportOffset),
FUZZFIELD(E32ImageHeaderV, iCodeRelocOffset),
FUZZFIELD(E32ImageHeaderV, iDataRelocOffset),
FUZZFIELD(E32ImageHeaderV, iProcessPriority),
FUZZFIELD(E32ImageHeaderV, iCpuIdentifier),
FUZZFIELD(E32ImageHeaderV, iUncompressedSize),
FUZZFIELD(E32ImageHeaderV, iS.iSecureId),
FUZZFIELD(E32ImageHeaderV, iS.iVendorId),
FUZZFIELD(E32ImageHeaderV, iS.iCaps.iCaps[0]),
FUZZFIELD(E32ImageHeaderV, iS.iCaps.iCaps[1]),
FUZZFIELD(E32ImageHeaderV, iExceptionDescriptor),
FUZZFIELD(E32ImageHeaderV, iSpare2),
FUZZFIELD(E32ImageHeaderV, iExportDescSize),
FUZZFIELD(E32ImageHeaderV, iExportDescType),
FUZZFIELD(E32ImageHeaderV, iExportDesc[0]),
FUZZEND
};
const SFuzzField ImportSectionFields[] =
{
FUZZFIELD(E32ImportSection, iSize),
FUZZEND
};
const SFuzzField ImportBlockFields[] =
{
FUZZFIELD(E32ImportBlock, iOffsetOfDllName), // we should fuzz the string also
FUZZFIELD(E32ImportBlock, iNumberOfImports),
FUZZEND
};
const SFuzzField ImportEntryFields[] =
{
DUMBFIELD("import", 4, 0),
FUZZEND
};
const SFuzzField RelocSectionFields[] =
{
FUZZFIELD(E32RelocSection, iSize),
FUZZFIELD(E32RelocSection, iNumberOfRelocs),
FUZZEND
};
const SFuzzField RelocBlockFields[] =
{
FUZZFIELD(E32RelocBlock, iPageOffset),
FUZZFIELD(E32RelocBlock, iBlockSize),
FUZZEND
};
const SFuzzField RelocEntryFields[] =
{
DUMBFIELD("reloc", 2, 0),
FUZZEND
};
const SFuzzField ExportEntryFields[] =
{
DUMBFIELD("export", 4, 0),
FUZZEND
};
const SFuzzField CompressedDataFields[] =
{
DUMBFIELD("data1", 4, 0),
DUMBFIELD("data2", 4, 4),
DUMBFIELD("data3", 4, 16),
DUMBFIELD("data4", 4, 64),
DUMBFIELD("data5", 4, 256),
DUMBFIELD("data6", 4, 1024),
DUMBFIELD("data7", 4, 4096),
FUZZEND
};
// Values to try for different sizes, signed here but can be interpreted as either
// each will also try the smaller sizes' values
const TInt8 Values8[] = { KMinTInt8, -100, -10, -2, -1, 0, 1, 2, 10, 100, KMaxTInt8 };
const TInt Values8Count = sizeof(Values8)/sizeof(TInt8);
const TInt16 Values16[] = { KMinTInt16, -10000, -256, -255, 128, 255, 256, 10000, KMaxTInt16 };
const TInt Values16Count = sizeof(Values16)/sizeof(TInt16);
const TInt32 Values32[] = { KMinTInt32, -1000000000, -65536, -65535, 32768, 65535, 65536, 268435455, 268435456, 1000000000, KMaxTInt32 };
const TInt Values32Count = sizeof(Values32)/sizeof(TInt32);
const TInt ValuesCount[] = { 0, Values8Count, Values8Count+Values16Count, 0, Values8Count+Values16Count+Values32Count };
const TInt Offsets[] = { 1, 2, 4, 16, -1, -2, -4, -16 };
const TInt OffsetsCount = sizeof(Offsets)/sizeof(TInt);
// Regular boring definitions and stuff
RTest test(_L("T_FUZZLDR"));
RFs TheFs;
CFileMan* FileMan;
_LIT(KOrigDir, "Z:\\sys\\bin\\");
_LIT(KSysBin, ":\\sys\\bin\\");
_LIT(KSysHash, ":\\sys\\hash\\");
_LIT(KImageName, "fuzzv");
_LIT(KExeExt, ".exe");
_LIT(KDllExt, ".dll");
_LIT(KMyself, "t_fuzzldr");
_LIT(KSlaveArg, "-l ");
TFileName Provided;
TFileName Original;
TFileName Current;
TFileName Hash;
TFileName HashDir;
TBool LoadDll;
RFile File;
RTimer Timer;
TUint8* Target;
E32ImageHeaderV* Header;
E32ImageHeaderV* CleanHeader;
CSHA1* Hasher;
TInt FileSize;
TInt OutFileSize;
TUint8* CleanFileData;
TPtr8 CleanFileDes(CleanFileData, 0);
TUint8* FileData;
TPtr8 FileDes(FileData, 0);
TUint8* EndOfFile;
TChar Drive = '?', InternalDrive = '?', RemovableDrive = '?';
TBool Verbose;
TBool Forever = EFalse;
TUint32 Seed = 0;
typedef void (*TFieldFuzzer)(const SFuzzField*, TInt);
enum SetMode {
ESetLiteral,
ESetOffset,
ESetRandom,
ESetXor,
};
enum ValueMode {
EValLiteral,
EValOffset,
EValRandom,
EValXor,
EValList,
EValOffsetList,
};
TUint32 Rand()
{
Seed *= 69069;
Seed += 5;
return Seed;
}
TUint32 Rand(TUint32 aLimit)
{
TUint64 temp = (TUint64)Rand() * (TUint64)aLimit;
return (TUint32)(temp>>32);
}
void PrepareName(TInt aNum, TBool aDll)
{
Original = KOrigDir;
Original += KImageName;
Original.AppendNum(aNum);
Original += aDll ? KDllExt : KExeExt;
Current.Zero();
Current.Append(Drive);
Current += KSysBin;
Current += KImageName;
Current.AppendNum(aNum);
Current += aDll ? KDllExt : KExeExt;
Hash = HashDir;
Hash += KImageName;
Hash.AppendNum(aNum);
Hash += aDll ? KDllExt : KExeExt;
}
void PrepareProvidedName()
{
Original = KOrigDir;
Original += Provided;
Current.Zero();
Current.Append(Drive);
Current += KSysBin;
Current += Provided;
Hash = HashDir;
Hash += Provided;
}
void MakeCleanCopy()
{
Mem::Copy(FileData, CleanFileData, FileSize);
}
void LoadCleanFile()
{
test_KErrNone(File.Open(TheFs, Original, EFileRead));
test_KErrNone(File.Size(FileSize));
OutFileSize = FileSize;
CleanFileData = new TUint8[FileSize];
test_NotNull(CleanFileData);
FileData = new TUint8[FileSize];
EndOfFile = FileData + FileSize;
test_NotNull(FileData);
CleanFileDes.Set(CleanFileData, 0, FileSize);
test_KErrNone(File.Read(CleanFileDes));
File.Close();
Header = (E32ImageHeaderV*)FileData;
CleanHeader = (E32ImageHeaderV*)CleanFileData;
FileDes.Set(FileData, FileSize, FileSize);
MakeCleanCopy();
test(CleanHeader->iUid1==(TUint32)KExecutableImageUidValue || CleanHeader->iUid1==(TUint32)KDynamicLibraryUidValue);
LoadDll = CleanHeader->iUid1==(TUint32)KDynamicLibraryUidValue;
}
void DoneFile()
{
delete[] FileData;
delete[] CleanFileData;
}
void RecalcChecksums()
{
if (Header->iUidChecksum == CleanHeader->iUidChecksum)
{
TUidType uids = *(const TUidType*)Header;
TCheckedUid chkuid(uids);
const TUint32* pChkUid = (const TUint32*)&chkuid;
Header->iUidChecksum = pChkUid[3];
}
if (Header->iHeaderCrc == CleanHeader->iHeaderCrc)
{
Header->iHeaderCrc = KImageCrcInitialiser;
TUint32 crc = 0;
Mem::Crc32(crc, Header, sizeof(E32ImageHeaderV));
Header->iHeaderCrc = crc;
}
}
void Load()
{
RecalcChecksums();
test_KErrNone(File.Replace(TheFs, Current, EFileWrite));
test_KErrNone(File.Write(FileDes, OutFileSize));
test_KErrNone(File.Flush());
File.Close();
if (Drive == RemovableDrive)
{
TPtrC8 data(FileData, OutFileSize);
Hasher->Reset();
Hasher->Update(data);
TBuf8<SHA1_HASH> hashVal = Hasher->Final();
test_KErrNone(File.Replace(TheFs, Hash, EFileWrite));
test_KErrNone(File.Write(hashVal));
test_KErrNone(File.Flush());
File.Close();
}
RProcess p;
TInt r;
if (LoadDll)
{
TFileName args;
args.Copy(KSlaveArg);
args.Append(Current);
test_KErrNone(p.Create(KMyself, args));
TRequestStatus logon, rendez, timeout;
p.Logon(logon);
p.Rendezvous(rendez);
p.Resume();
User::WaitForRequest(rendez);
test(rendez==KErrNone);
Timer.After(timeout, KDllTimeout);
User::WaitForRequest(logon, timeout);
if (logon == KRequestPending)
{
p.Kill(0);
User::WaitForRequest(logon);
}
else
{
Timer.Cancel();
User::WaitForRequest(timeout);
}
p.Close();
// we don't check the return code as passing it back makes the log output
// super spammy with KPANIC on - it prints for every nonzero return code.
if (Verbose) test.Printf(_L("\n"));
}
else
{
r = p.Create(Current, KNullDesC);
if (r==KErrNone)
p.Kill(0);
if (Verbose) test.Printf(_L("=> %d\n"), r);
}
p.Close();
}
template <typename T> void SetFieldTo(const SFuzzField* aField, T aSetTo, SetMode aMode)
{
T* field = (T*)(Target + aField->offset);
if ((TUint8*)field >= EndOfFile)
{
if (Verbose) test.Printf(_L("skipping, eof "));
return;
}
if (aMode == ESetOffset)
aSetTo += *field;
else if (aMode == ESetRandom)
aSetTo = (T)Rand();
else if (aMode == ESetXor)
aSetTo ^= *field;
*field = aSetTo;
if (Verbose) test.Printf(_L("%d "), aSetTo);
}
void SetField(const SFuzzField* aField, TInt aValue, ValueMode aMode)
{
if (aMode < EValList)
{
switch(aField->size)
{
case 1:
SetFieldTo<TInt8>(aField, aValue, (SetMode)aMode);
break;
case 2:
SetFieldTo<TInt16>(aField, aValue, (SetMode)aMode);
break;
case 4:
SetFieldTo<TInt32>(aField, aValue, (SetMode)aMode);
break;
}
}
else if (aMode == EValList)
{
switch(aField->size)
{
case 1:
SetFieldTo<TInt8>(aField, Values8[aValue], ESetLiteral);
break;
case 2:
if (aValue < ValuesCount[1])
SetFieldTo<TInt16>(aField, Values8[aValue], ESetLiteral);
else
SetFieldTo<TInt16>(aField, Values16[aValue-ValuesCount[1]], ESetLiteral);
break;
case 4:
if (aValue < ValuesCount[1])
SetFieldTo<TInt32>(aField, Values8[aValue], ESetLiteral);
else if (aValue < ValuesCount[2])
SetFieldTo<TInt32>(aField, Values16[aValue-ValuesCount[1]], ESetLiteral);
else
SetFieldTo<TInt32>(aField, Values32[aValue-ValuesCount[2]], ESetLiteral);
break;
}
}
else if (aMode == EValOffsetList)
{
switch(aField->size)
{
case 1:
SetFieldTo<TInt8>(aField, Offsets[aValue], ESetOffset);
break;
case 2:
SetFieldTo<TInt16>(aField, Offsets[aValue], ESetOffset);
break;
case 4:
SetFieldTo<TInt32>(aField, Offsets[aValue], ESetOffset);
break;
}
}
}
void FuzzFieldsDeterministically(const SFuzzField* aFields, TInt aOffset)
{
Target = FileData + aOffset;
TInt f = -1;
while (aFields[++f].name)
{
test.Printf(_L("FIELD: %s ...\n"), aFields[f].name);
TInt v;
if (Verbose) test.Next(_L("Using preset values"));
for (v = 0; v < ValuesCount[aFields[f].size]; ++v)
{
MakeCleanCopy();
SetField(&aFields[f], v, EValList);
Load();
}
if (Verbose) test.Next(_L("Using preset offsets"));
for (v = 0; v < OffsetsCount; ++v)
{
MakeCleanCopy();
SetField(&aFields[f], v, EValOffsetList);
Load();
}
if (Verbose) test.Next(_L("Flipping single bits"));
for (v = 0; v < aFields[f].size*8; ++v)
{
MakeCleanCopy();
SetField(&aFields[f], 1<<v, EValXor);
Load();
}
if (Verbose) test.Next(_L("Inverting"));
MakeCleanCopy();
SetField(&aFields[f], 0xffffffffu, EValXor);
Load();
// things that are offsets all go below, pointless on
// narrow fields
if (aFields[f].size == 4)
{
if (Verbose) test.Next(_L("Using filesize relative values"));
for (v = FileSize-4; v <= FileSize+4; ++v)
{
MakeCleanCopy();
SetField(&aFields[f], v, EValLiteral);
Load();
}
if (Verbose) test.Next(_L("Using code-end relative values"));
TInt codeend = CleanHeader->iCodeSize + CleanHeader->iCodeOffset;
for (v = codeend-4; v <= codeend+4; ++v)
{
MakeCleanCopy();
SetField(&aFields[f], v, EValLiteral);
Load();
}
}
}
}
void FuzzFieldsRandomly(const SFuzzField* aFields, TInt aOffset)
{
Target = FileData + aOffset;
TInt f = 0;
while (aFields[f].name)
{
test.Printf(_L("FIELD: %s ... (random)\n"), aFields[f].name);
TInt v;
for (v = 0; v < KRandomFieldIterations; ++v)
{
MakeCleanCopy();
SetField(&aFields[f], 0, EValRandom);
Load();
}
f++;
}
}
void FuzzBlockRandomly(TInt aOffset, TInt aSize)
{
SFuzzField field;
field.size = 1;
Target = FileData + aOffset;
test.Printf(_L("FIELD: random words in data\n"));
TInt v;
for (v = 0; v < KRandomFieldIterations * 4; ++v)
{
MakeCleanCopy();
field.offset = Rand(aSize);
if (Verbose) test.Printf(_L("@ %d, "), field.offset);
SetField(&field, 0, EValRandom);
Load();
}
}
void FuzzFile(TBool aRandom)
{
TTime before, after;
before.UniversalTime();
LoadCleanFile();
TFieldFuzzer FuzzFields = aRandom ? FuzzFieldsRandomly : FuzzFieldsDeterministically;
// E32ImageHeader
FuzzFields(HeaderFields, 0);
if (CleanHeader->iCompressionType == KFormatNotCompressed)
{
// import table
TInt offset = CleanHeader->iImportOffset;
if (offset != 0)
{
FuzzFields(ImportSectionFields, offset);
offset += sizeof(E32ImportSection);
FuzzFields(ImportBlockFields, offset);
offset += sizeof(E32ImportBlock);
FuzzFields(ImportEntryFields, offset);
}
// code relocations
offset = CleanHeader->iCodeRelocOffset;
if (offset != 0)
{
FuzzFields(RelocSectionFields, offset);
offset += sizeof(E32RelocSection);
FuzzFields(RelocBlockFields, offset);
offset += sizeof(E32RelocBlock);
FuzzFields(RelocEntryFields, offset);
}
// data relocations
offset = CleanHeader->iDataRelocOffset;
if (offset != 0)
{
FuzzFields(RelocSectionFields, offset);
offset += sizeof(E32RelocSection);
FuzzFields(RelocBlockFields, offset);
offset += sizeof(E32RelocBlock);
FuzzFields(RelocEntryFields, offset);
}
// export table
offset = CleanHeader->iExportDirOffset;
if (offset != 0)
{
FuzzFields(ExportEntryFields, offset);
}
}
else
{
if (aRandom)
{
// random bits of the compressed data
FuzzBlockRandomly(CleanHeader->iCodeOffset, FileSize - CleanHeader->iCodeOffset);
}
else
{
// arbitrary bits of the compressed data
FuzzFields(CompressedDataFields, CleanHeader->iCodeOffset);
}
}
DoneFile();
after.UniversalTime();
TTimeIntervalSeconds interval;
after.SecondsFrom(before, interval);
test.Printf(_L("Took %d seconds\n"), interval.Int());
}
void FuzzTruncateTo(TInt size)
{
OutFileSize = size - 4;
if (Verbose) test.Printf(_L("%d "), OutFileSize);
Load();
OutFileSize = size - 1;
if (Verbose) test.Printf(_L("%d "), OutFileSize);
Load();
if (size == FileSize)
return;
OutFileSize = size;
if (Verbose) test.Printf(_L("%d "), OutFileSize);
Load();
OutFileSize = size + 1;
if (Verbose) test.Printf(_L("%d "), OutFileSize);
Load();
OutFileSize = size + 4;
if (Verbose) test.Printf(_L("%d "), OutFileSize);
Load();
}
void FuzzTruncate()
{
TTime before, after;
before.UniversalTime();
LoadCleanFile();
FuzzTruncateTo(CleanHeader->iCodeOffset);
if (CleanHeader->iCompressionType == KFormatNotCompressed)
FuzzTruncateTo(CleanHeader->iCodeOffset+CleanHeader->iCodeSize);
FuzzTruncateTo(FileSize);
DoneFile();
after.UniversalTime();
TTimeIntervalSeconds interval;
after.SecondsFrom(before, interval);
test.Printf(_L("Took %d seconds\n"), interval.Int());
}
void FuzzAllTestImages()
{
TInt i;
Drive = InternalDrive;
test.Next(_L("Fuzzing deterministically"));
for (i=1; i<=KFuzzImages; ++i)
{
test.Next(_L("Next binary..."));
test.Printf(_L("Fuzzing exe %d\n"), i);
PrepareName(i, EFalse);
FuzzFile(EFalse);
if(i==5)
continue; // DLL 5 doesn't exist because toolchain doesn't like DLLs with no exports
test.Next(_L("Next binary..."));
test.Printf(_L("Fuzzing dll %d\n"), i);
PrepareName(i, ETrue);
FuzzFile(EFalse);
}
Drive = RemovableDrive;
test.Next(_L("Fuzzing deterministically on removable media"));
for (i=1; i<=KFuzzImages; ++i)
{
test.Next(_L("Next binary..."));
test.Printf(_L("Fuzzing exe %d\n"), i);
PrepareName(i, EFalse);
FuzzFile(EFalse);
if(i==5)
continue; // DLL 5 doesn't exist because toolchain doesn't like DLLs with no exports
test.Next(_L("Next binary..."));
test.Printf(_L("Fuzzing dll %d\n"), i);
PrepareName(i, ETrue);
FuzzFile(EFalse);
}
Drive = InternalDrive;
test.Next(_L("Fuzzing by truncation"));
for (i=1; i<=KFuzzImages; ++i)
{
test.Next(_L("Next binary..."));
test.Printf(_L("Fuzzing exe %d\n"), i);
PrepareName(i, EFalse);
FuzzTruncate();
if(i==5)
continue; // DLL 5 doesn't exist because toolchain doesn't like DLLs with no exports
test.Next(_L("Next binary..."));
test.Printf(_L("Fuzzing dll %d\n"), i);
PrepareName(i, ETrue);
FuzzTruncate();
}
Drive = RemovableDrive;
test.Next(_L("Fuzzing by truncation on removable media"));
for (i=1; i<=KFuzzImages; ++i)
{
test.Next(_L("Next binary..."));
test.Printf(_L("Fuzzing exe %d\n"), i);
PrepareName(i, EFalse);
FuzzTruncate();
if(i==5)
continue; // DLL 5 doesn't exist because toolchain doesn't like DLLs with no exports
test.Next(_L("Next binary..."));
test.Printf(_L("Fuzzing dll %d\n"), i);
PrepareName(i, ETrue);
FuzzTruncate();
}
test.Next(_L("Fuzzing randomly"));
do
{
for (i=1; i<=KFuzzImages; ++i)
{
Drive = InternalDrive;
test.Next(_L("Next binary..."));
test.Printf(_L("Fuzzing exe %d\n"), i);
PrepareName(i, EFalse);
FuzzFile(ETrue);
if(i==5)
continue; // DLL 5 doesn't exist because toolchain doesn't like DLLs with no exports
test.Next(_L("Next binary..."));
test.Printf(_L("Fuzzing dll %d\n"), i);
PrepareName(i, ETrue);
FuzzFile(ETrue);
Drive = RemovableDrive;
test.Next(_L("Next binary..."));
test.Printf(_L("Fuzzing exe %d on removable media\n"), i);
PrepareName(i, EFalse);
FuzzFile(ETrue);
if(i==5)
continue; // DLL 5 doesn't exist because toolchain doesn't like DLLs with no exports
test.Next(_L("Next binary..."));
test.Printf(_L("Fuzzing dll %d on removable media\n"), i);
PrepareName(i, ETrue);
FuzzFile(ETrue);
}
}
while (Forever);
}
void FuzzProvidedImage()
{
test.Printf(_L("Fuzzing file %S\n"), &Provided);
PrepareProvidedName();
Drive = InternalDrive;
test.Next(_L("Fuzzing deterministically"));
FuzzFile(EFalse);
Drive = RemovableDrive;
test.Next(_L("Fuzzing deterministically on removable media"));
FuzzFile(EFalse);
test.Next(_L("Fuzzing by truncation"));
FuzzTruncate();
Drive = RemovableDrive;
test.Next(_L("Fuzzing by truncation on removable media"));
FuzzTruncate();
test.Next(_L("Fuzzing randomly"));
do
{
Drive = InternalDrive;
test.Next(_L("Internal drive"));
FuzzFile(ETrue);
Drive = RemovableDrive;
test.Next(_L("Removable drive"));
FuzzFile(ETrue);
}
while (Forever);
}
GLDEF_C TInt E32Main()
{
// default to verbose unless the fasttest trace flag is on
Verbose = (UserSvr::DebugMask(2)&0x00000002) == 0;
TFileName cmd;
User::CommandLine(cmd);
TLex lex(cmd);
FOREVER
{
lex.SkipSpace();
if (lex.Eos())
break;
TChar next = lex.Peek();
if (next == '-' || next == '/')
{
// option
lex.Inc();
switch(lex.Get())
{
case 'v':
Verbose = ETrue;
break;
case 'q':
Verbose = EFalse;
break;
case 'l':
{
// being used as a slave to load a DLL
TPtrC libname(lex.NextToken());
RLibrary l;
RProcess::Rendezvous(KErrNone);
l.Load(libname);
return KErrNone;
}
case 's':
// random seed
lex.SkipSpace();
test_KErrNone(lex.Val(Seed, EHex));
test.Printf(_L("Using supplied random seed %08x\n"), Seed);
break;
case 'f':
// run forever
Forever = ETrue;
break;
}
}
else
{
// filename, at least i assume it is :)
Provided.Copy(lex.NextToken());
}
}
test.Title();
test.Next(_L("Setup"));
__UHEAP_MARK;
CTrapCleanup* cleanup;
cleanup=CTrapCleanup::New();
if (Seed == 0)
{
TTime time;
time.UniversalTime();
Seed = (TUint32)time.Int64();
test.Printf(_L("Random seed is %08x\n"), Seed);
}
test_KErrNone(TheFs.Connect());
test_TRAP(FileMan=CFileMan::NewL(TheFs));
test_KErrNone(Timer.CreateLocal());
test_TRAP(Hasher=CSHA1::NewL());
HashDir.Append(TheFs.GetSystemDriveChar());
HashDir.Append(KSysHash);
TInt r = TheFs.MkDirAll(HashDir);
test(r == KErrNone || r == KErrAlreadyExists);
// Find some interesting drives
for (TInt driveno = EDriveA; driveno <= EDriveZ; ++driveno)
{
TDriveInfo di;
test_KErrNone(TheFs.Drive(di, driveno));
if (di.iType == EMediaNotPresent)
continue;
TChar drivechar;
test_KErrNone(TheFs.DriveToChar(driveno, drivechar));
if ((di.iDriveAtt & KDriveAttInternal) && InternalDrive == '?')
InternalDrive = drivechar;
else if ((di.iDriveAtt & KDriveAttRemovable) && RemovableDrive == '?')
RemovableDrive = drivechar;
else
continue;
TFileName fn;
fn.Append(drivechar);
fn.Append(KSysBin);
TheFs.MkDirAll(fn);
test(r == KErrNone || r == KErrAlreadyExists);
}
test.Printf(_L("Using %c as internal drive, %c as removable\n"), (TUint)InternalDrive, (TUint)RemovableDrive);
// Turn off evil lazy dll unloading
RLoader l;
test_KErrNone(l.Connect());
test_KErrNone(l.CancelLazyDllUnload());
l.Close();
test.Start(_L("Fuzzing loader"));
if (Provided.Length() == 0)
FuzzAllTestImages();
else
FuzzProvidedImage();
test.End();
delete Hasher;
Timer.Close();
delete FileMan;
TheFs.Close();
test.Close();
delete cleanup;
__UHEAP_MARKEND;
return KErrNone;
}