-
Notifications
You must be signed in to change notification settings - Fork 6.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Fuzz] Add Fuzz testing for RegistryPreview #37607
base: main
Are you sure you want to change the base?
Changes from 13 commits
b205794
8aefd45
88f5e65
5e28035
330e292
6ee7dba
d1b4fee
63724c8
a6a9f92
16c2c2b
f0951bb
11471bd
8ca1c2f
a7b8a27
ad15dd1
136b7ca
e8269b8
0438b20
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
// Copyright (c) Microsoft Corporation | ||
// The Microsoft Corporation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
using System; | ||
using System.Diagnostics; | ||
using System.Globalization; | ||
using System.Resources; | ||
using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
using Microsoft.Win32; | ||
using RegistryPreviewUILib; | ||
|
||
namespace RegistryPreview.FuzzTests | ||
{ | ||
public class FuzzTests | ||
{ | ||
private const string REGISTRYHEADER4 = "regedit4"; | ||
private const string REGISTRYHEADER5 = "windows registry editor version 5.00"; | ||
private const string KEYIMAGE = "ms-appx:///Assets/RegistryPreview/folder32.png"; | ||
private const string DELETEDKEYIMAGE = "ms-appx:///Assets/RegistryPreview/deleted-folder32.png"; | ||
|
||
// Case 1: Fuzz test for CheckKeyLineForBrackets | ||
public static void FuzzCheckKeyLineForBrackets(ReadOnlySpan<byte> input) | ||
{ | ||
string registryLine; | ||
|
||
// Simulate registry file content as filenameText | ||
var filenameText = GenerateRegistryHeader(input); | ||
|
||
string[] registryLines = filenameText.Split("\r"); | ||
|
||
if (registryLines.Length <= 1) | ||
{ | ||
return; | ||
} | ||
|
||
// REG files have to start with one of two headers and it's case-insensitive | ||
// The header in the registry file is either REGISTRYHEADER4 or REGISTRYHEADER5 | ||
registryLine = registryLines[0]; | ||
|
||
// Check if the registry header is valid | ||
if (!IsValidRegistryHeader(registryLine)) | ||
{ | ||
return; | ||
} | ||
|
||
int index = 1; | ||
registryLine = registryLines[index]; // Extract content after the header | ||
|
||
ParseHelper.ProcessRegistryLine(registryLine); | ||
if (registryLine.StartsWith("[-", StringComparison.InvariantCulture)) | ||
{ | ||
// remove the - as we won't need it but it will get special treatment in the UI | ||
registryLine = registryLine.Remove(1, 1); | ||
|
||
string imageName = DELETEDKEYIMAGE; | ||
|
||
// Fuzz test for the CheckKeyLineForBrackets method | ||
ParseHelper.CheckKeyLineForBrackets(ref registryLine, ref imageName); | ||
} | ||
else if (registryLine.StartsWith('[')) | ||
{ | ||
string imageName = KEYIMAGE; | ||
|
||
// Fuzz test for the CheckKeyLineForBrackets method | ||
ParseHelper.CheckKeyLineForBrackets(ref registryLine, ref imageName); | ||
} | ||
else | ||
{ | ||
return; | ||
} | ||
} | ||
|
||
// Case 2: Fuzz test for StripFirstAndLast | ||
public static void FuzzStripFirstAndLast(ReadOnlySpan<byte> input) | ||
{ | ||
string registryLine; | ||
|
||
var filenameText = GenerateRegistryHeader(input); | ||
|
||
filenameText = filenameText.Replace("\r\n", "\r"); | ||
string[] registryLines = filenameText.Split("\r"); | ||
|
||
if (registryLines.Length <= 1) | ||
{ | ||
return; | ||
} | ||
|
||
// REG files have to start with one of two headers and it's case-insensitive | ||
registryLine = registryLines[0]; | ||
|
||
if (!IsValidRegistryHeader(registryLine)) | ||
{ | ||
return; | ||
} | ||
|
||
int index = 1; | ||
registryLine = registryLines[index]; | ||
|
||
ParseHelper.ProcessRegistryLine(registryLine); | ||
|
||
if (registryLine.StartsWith("[-", StringComparison.InvariantCulture)) | ||
{ | ||
// remove the - as we won't need it but it will get special treatment in the UI | ||
registryLine = registryLine.Remove(1, 1); | ||
|
||
string imageName = DELETEDKEYIMAGE; | ||
ParseHelper.CheckKeyLineForBrackets(ref registryLine, ref imageName); | ||
|
||
// Fuzz test for the StripFirstAndLast method | ||
registryLine = ParseHelper.StripFirstAndLast(registryLine); | ||
} | ||
else if (registryLine.StartsWith('[')) | ||
{ | ||
string imageName = KEYIMAGE; | ||
ParseHelper.CheckKeyLineForBrackets(ref registryLine, ref imageName); | ||
|
||
// Fuzz test for the StripFirstAndLast method | ||
registryLine = ParseHelper.StripFirstAndLast(registryLine); | ||
} | ||
else if (registryLine.StartsWith('"') && registryLine.EndsWith("=-", StringComparison.InvariantCulture)) | ||
{ | ||
registryLine = registryLine.Replace("=-", string.Empty); | ||
|
||
// remove the "'s without removing all of them | ||
// Fuzz test for the StripFirstAndLast method | ||
registryLine = ParseHelper.StripFirstAndLast(registryLine); | ||
} | ||
else if (registryLine.StartsWith('"')) | ||
{ | ||
int equal = registryLine.IndexOf('='); | ||
if ((equal < 0) || (equal > registryLine.Length - 1)) | ||
{ | ||
// something is very wrong | ||
return; | ||
} | ||
|
||
// set the name and the value | ||
string name = registryLine.Substring(0, equal); | ||
|
||
// trim the whitespace and quotes from the name | ||
name = name.Trim(); | ||
|
||
// Fuzz test for the StripFirstAndLast method | ||
name = ParseHelper.StripFirstAndLast(name); | ||
} | ||
else | ||
{ | ||
return; | ||
} | ||
} | ||
|
||
public static string GenerateRegistryHeader(ReadOnlySpan<byte> input) | ||
{ | ||
string header = new Random().Next(2) == 0 ? REGISTRYHEADER4 : REGISTRYHEADER5; | ||
|
||
string inputText = System.Text.Encoding.UTF8.GetString(input); | ||
string filenameText = header + "\r\n" + inputText; | ||
|
||
return filenameText.Replace("\r\n", "\r"); | ||
} | ||
|
||
private static bool IsValidRegistryHeader(string line) | ||
{ | ||
// Convert the line to lowercase once for comparison | ||
var lineLower = line.ToLowerInvariant(); | ||
|
||
switch (line) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I noticed that you're using switch (line), which relies on the original line, but you convert lineLower to lowercase for comparison. Which one do you actually intend to use? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I intend to use the line, and the lineLower needs to be removed. |
||
{ | ||
case REGISTRYHEADER4: | ||
case REGISTRYHEADER5: | ||
return true; | ||
default: | ||
return false; | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
// Copyright (c) Microsoft Corporation | ||
// The Microsoft Corporation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
// Copyright (c) Microsoft Corporation | ||
// The Microsoft Corporation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
{ | ||
"configVersion": 3, | ||
"entries": [ | ||
{ | ||
"fuzzer": { | ||
"$type": "libfuzzerDotNet", | ||
"dll": "RegistryPreview.FuzzTests.dll", | ||
"class": "RegistryPreview.FuzzTests.FuzzTests", | ||
"method": "FuzzCheckKeyLineForBrackets", | ||
"FuzzingTargetBinaries": [ | ||
"PowerToys.RegistryPreview.dll" | ||
] | ||
}, | ||
"adoTemplate": { | ||
// supply the values appropriate to your | ||
// project, where bugs will be filed | ||
"org": "microsoft", | ||
"project": "OS", | ||
"AssignedTo": "mengyuanchen@microsoft.com", | ||
"AreaPath": "OS\\Windows Client and Services\\WinPD\\DEEP-Developer Experience, Ecosystem and Partnerships\\SHINE\\PowerToys", | ||
"IterationPath": "OS\\Future" | ||
}, | ||
"jobNotificationEmail": "mengyuanchen@microsoft.com", | ||
"skip": false, | ||
"rebootAfterSetup": false, | ||
"oneFuzzJobs": [ | ||
// at least one job is required | ||
{ | ||
"projectName": "RegistryPreview", | ||
"targetName": "RegistryPreview-dotnet-CheckKeyLineForBrackets-fuzzer" | ||
} | ||
], | ||
"jobDependencies": [ | ||
// this should contain, at minimum, | ||
// the DLL and PDB files | ||
// you will need to add any other files required | ||
// (globs are supported) | ||
"RegistryPreview.FuzzTests.dll", | ||
"RegistryPreview.FuzzTests.pdb", | ||
"Microsoft.Windows.SDK.NET.dll", | ||
"WinRT.Runtime.dll" | ||
], | ||
"SdlWorkItemId": 49911822 | ||
}, | ||
{ | ||
"fuzzer": { | ||
"$type": "libfuzzerDotNet", | ||
"dll": "RegistryPreview.FuzzTests.dll", | ||
"class": "RegistryPreview.FuzzTests.FuzzTests", | ||
"method": "FuzzStripFirstAndLast", | ||
"FuzzingTargetBinaries": [ | ||
"PowerToys.RegistryPreview.dll" | ||
] | ||
}, | ||
"adoTemplate": { | ||
// supply the values appropriate to your | ||
// project, where bugs will be filed | ||
"org": "microsoft", | ||
"project": "OS", | ||
"AssignedTo": "mengyuanchen@microsoft.com", | ||
"AreaPath": "OS\\Windows Client and Services\\WinPD\\DEEP-Developer Experience, Ecosystem and Partnerships\\SHINE\\PowerToys", | ||
"IterationPath": "OS\\Future" | ||
}, | ||
"jobNotificationEmail": "mengyuanchen@microsoft.com", | ||
"skip": false, | ||
"rebootAfterSetup": false, | ||
"oneFuzzJobs": [ | ||
// at least one job is required | ||
{ | ||
"projectName": "RegistryPreview", | ||
"targetName": "RegistryPreview-dotnet-StripFirstAndLasts-fuzzer" | ||
} | ||
], | ||
"jobDependencies": [ | ||
// this should contain, at minimum, | ||
// the DLL and PDB files | ||
// you will need to add any other files required | ||
// (globs are supported) | ||
"RegistryPreview.FuzzTests.dll", | ||
"RegistryPreview.FuzzTests.pdb", | ||
"Microsoft.Windows.SDK.NET.dll", | ||
"WinRT.Runtime.dll" | ||
], | ||
"SdlWorkItemId": 49911822 | ||
} | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework> | ||
chenmy77 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<Platforms>x64;ARM64</Platforms> | ||
<LangVersion>latest</LangVersion> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<PropertyGroup> | ||
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\tests\RegistryPreview.FuzzTests\</OutputPath> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<Compile Include="..\RegistryPreviewUILib\ParseHelper.cs" Link="ParseHelper.cs" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<Content Include="OneFuzzConfig.json"> | ||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> | ||
</Content> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="MSTest" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" /> | ||
</ItemGroup> | ||
|
||
</Project> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on the comments, the result represents registry file content, so the name filenameText might be confusing. Would registryContent be a better choice?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I also think so,registryContent would be a better choice than filenameText. I will modify it.