in Tpm2Tester/TestSubstrate/TestFuzzer.cs [651:858]
void DoFuzzDecomposedStruct(FuzzableMember[] fuzzableVals, FuzzStats cmdStat)
{
if (fuzzableVals.Length == 0)
{
return;
}
// Pick up the number of fuzzable values in the decomposed request to
// actually fuzz. Probability of fuzzing more values decreases.
int numValsToFuzz = fuzzableVals.Length < 8 ? fuzzableVals.Length : 8;
double d = Globs.GetRandomDouble();
double threshold = 0.5;
for (int i = 1; i < numValsToFuzz; ++i )
{
if (d > threshold)
{
numValsToFuzz = i;
break;
}
threshold /= 2;
}
if (numValsToFuzz == 0)
{
numValsToFuzz = fuzzableVals.Length;
}
//int numValsToFuzz = fuzzableVals.Length;
var valsToFuzz = new FuzzableMember[numValsToFuzz];
if (fuzzableVals.Length == 1)
{
valsToFuzz[0] = fuzzableVals[0];
}
else
{
// Select numValsToFuzz out of fuzzableVals.Length values
int selected = 0;
for (int i = 0;
selected < numValsToFuzz && selected < fuzzableVals.Length - i;
++i )
{
double p = 1.0 - Math.Pow(1.0 - (double)fuzzableVals[i].Item3 /
cmdStat.cmdComplexity, numValsToFuzz);
Debug.Assert(p <= 1.0);
double r = Globs.GetRandomDouble();
if (r <= p)
{
var memInfo = fuzzableVals[i];
object member = Globs.GetMember(memInfo.Item1, memInfo.Item2);
Type memType = Globs.GetMemberType(memInfo.Item1);
if (member != null || ValidStructs.ContainsKey(memType))
{
valsToFuzz[selected++] = memInfo;
}
}
}
while (selected < numValsToFuzz)
{
valsToFuzz[selected] = fuzzableVals[fuzzableVals.Length
- (numValsToFuzz - selected)];
++selected;
}
}
foreach (var memInfo in valsToFuzz)
{
Type memType = Globs.GetMemberType(memInfo.Item1);
var containingObject = memInfo.Item2;
object member = Globs.GetMember(memInfo.Item1, containingObject);
var ti = memType.GetTypeInfo();
int rnd = Globs.GetRandomInt();
if (member == null)
{
//Console.Write("'Nil' node: {0} {1} > ", memType, memInfo.Item1.Name);
if (memType == typeof(byte[]))
{
member = new byte[0];
}
else if (!ti.IsEnum && !ti.IsValueType)
{
//Console.Write("'Nil' struct: {0} {1} > ", memType, memInfo.Item1.Name);
if (ValidStructs.ContainsKey(memType))
{
//Console.WriteLine("Replacing...");
member = ValidStructs[memType];
// Use actual object type in case of members of an interface type
DoFuzzDecomposedStruct(
TraverseTpmStructure(member.GetType(), member,
FieldFilter.Any).ToArray(),
cmdStat);
++CurFuzzStats.nullStructsResurrected;
}
//else
// Console.WriteLine("No replacement...");
return;
}
else
{
member = Activator.CreateInstance(memType);
}
++CurFuzzStats.nullLeafsResurrected;
}
if (ti.IsEnum)
{
object fuzzedEnum = FuzzEnum(memType, member);
Globs.SetMember(memInfo.Item1, containingObject, fuzzedEnum);
++CurFuzzStats.enumsFuzzed;
}
else if (memType == typeof(byte[]))
{
var buf = member as byte[];
if (buf.Length > 0)
{
if (rnd % 17 != 0)
{
FuzzBuffer(ref buf, rnd);
}
else
{
buf = null;
}
}
else
{
// Pick up a random size for the fuzzed empty buffer, making
// sure that the values from various ranges are selected.
int bufSize = 0;
switch (rnd % 5)
{
case 0:
bufSize = Substrate.RandomInt(TpmCfg.MinDigestSize - 1) + 1;
break;
case 1:
bufSize = Substrate.RandomInt(TpmCfg.MaxDigestSize - TpmCfg.MinDigestSize)
+ TpmCfg.MinDigestSize;
break;
case 2:
bufSize = TpmHash.DigestSize(Substrate.Random(TpmCfg.HashAlgs));
break;
case 3:
bufSize = Substrate.RandomInt(TpmCfg.MaxNvOpSize - TpmCfg.MaxDigestSize)
+ TpmCfg.MaxDigestSize;
break;
case 4:
var keySizes = new int[] { 16, 16, 16, 24, 32, 32, 32, 48,
64, 1024, 1024, 2048, 2048 };
bufSize = keySizes[Substrate.RandomInt(keySizes.Length)];
break;
case 5:
bufSize = Substrate.RandomInt(4 * TpmCfg.MaxNvIndexSize - TpmCfg.MaxNvOpSize)
+ TpmCfg.MaxNvOpSize;
break;
}
rnd /= 5;
buf = rnd % 2 == 0 ? Substrate.RandomBytes(bufSize)
: Globs.GetZeroBytes(bufSize);
}
Globs.SetMember(memInfo.Item1, containingObject, buf);
++CurFuzzStats.buffersFuzzed;
}
else if (containingObject.GetType() == typeof(TpmHandle))
{
if (rnd % 4 == 0)
{
// Fuzz as TPM_RH
object fuzzedEnum = FuzzEnum(typeof(TpmRh), member);
Globs.SetMember(memInfo.Item1, containingObject, fuzzedEnum);
}
else if (rnd % 8 == 0)
{
// Fuzz as random value
Globs.SetMember(memInfo.Item1, containingObject,
Globs.GetRandomUInt());
}
else
{
// TODO: Fuzz to defined handle values in PCR, transient,
// persistent, NV, and session ranges
byte[] mso = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x040, 0x80, 0x81 };
rnd /= 29;
uint fuzzedVal = ((uint)mso[Globs.GetRandomInt(7)] << 24)
| (Globs.GetRandomUInt() &
(rnd % 4 == 0 ? 0x00FFFFFFu : rnd % 4 == 1 ? 0x3Fu : 0x07u));
}
++CurFuzzStats.handlesFuzzed;
}
else
{
Substrate.Assert(memType.GetTypeInfo().IsValueType);
byte[] val = null;
val = Globs.HostToNet(member);
// Select fuzzing mode that does not change buffer size to preserve
// value type
FuzzBuffer(ref val, rnd, false);
member = Globs.NetToHostValue(memType, val);
Globs.SetMember(memInfo.Item1, containingObject, member);
++CurFuzzStats.valuesFuzzed;
}
}
}