diff --git a/.github/actions/spell-check/allow/code.txt b/.github/actions/spell-check/allow/code.txt index b9a7ad1d6349..8c53e5282757 100644 --- a/.github/actions/spell-check/allow/code.txt +++ b/.github/actions/spell-check/allow/code.txt @@ -78,7 +78,14 @@ sinclairinat stylecop uipi yinwang - +myaccess +onmicrosoft +aep +epsf +howto +onefuzzconfig +oip +onefuzzingestionpreparationtool # KEYS @@ -246,3 +253,12 @@ pwa AOT Aot + +# YML +onefuzz + +# NameInCode +leilzh + +#Tools +OIP diff --git a/.pipelines/v2/oneFuzz.yml b/.pipelines/v2/oneFuzz.yml new file mode 100644 index 000000000000..2bcbf360503b --- /dev/null +++ b/.pipelines/v2/oneFuzz.yml @@ -0,0 +1,55 @@ +pr: none +trigger: none + +schedules: + - cron: "0 0 * * 1" + displayName: Weekly fuzzing submission + branches: + include: + - main + always: true +name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr) + +parameters: + - name: platform + type: string + default: x64 # for fuzzing, we only use x64 for now + - name: enableMsBuildCaching + type: boolean + displayName: "Enable MSBuild Caching" + default: false + - name: useVSPreview + type: boolean + displayName: "Build Using Visual Studio Preview" + default: false + +stages: + - stage: Build_${{ parameters.platform }} + displayName: Build ${{ parameters.platform }} + jobs: + - template: templates/job-build-project.yml + parameters: + pool: + ${{ if eq(variables['System.CollectionId'], 'cb55739e-4afe-46a3-970f-1b49d8ee7564') }}: + name: SHINE-INT-L + ${{ else }}: + name: SHINE-OSS-L + ${{ if eq(parameters.useVSPreview, true) }}: + demands: ImageOverride -equals SHINE-VS17-Preview + buildPlatforms: + - ${{ parameters.platform }} + buildConfigurations: [Release] + enablePackageCaching: true + enableMsBuildCaching: ${{ parameters.enableMsBuildCaching }} + runTests: true + useVSPreview: ${{ parameters.useVSPreview }} + + - stage: OneFuzz + displayName: Fuzz ${{ parameters.platform }} + dependsOn: + - Build_${{parameters.platform}} + jobs: + - template: templates/job-fuzz.yml + parameters: + platform: ${{ parameters.platform }} + configuration: Release diff --git a/.pipelines/v2/templates/job-build-project.yml b/.pipelines/v2/templates/job-build-project.yml index 1933b74e8de9..ff082d35379b 100644 --- a/.pipelines/v2/templates/job-build-project.yml +++ b/.pipelines/v2/templates/job-build-project.yml @@ -134,6 +134,11 @@ jobs: sdk: true version: '6.0' + - template: steps-ensure-dotnet-version.yml + parameters: + sdk: true + version: '8.0' + - template: steps-ensure-dotnet-version.yml parameters: sdk: true diff --git a/.pipelines/v2/templates/job-fuzz.yml b/.pipelines/v2/templates/job-fuzz.yml new file mode 100644 index 000000000000..b4e380194e65 --- /dev/null +++ b/.pipelines/v2/templates/job-fuzz.yml @@ -0,0 +1,36 @@ +parameters: + - name: configuration + type: string + default: "Release" + - name: platform + type: string + default: "" + - name: inputArtifactStem + type: string + default: "" + +jobs: + - job: OneFuzz + pool: + vmImage: windows-2022 + variables: + ArtifactName: build-${{ parameters.platform }}-${{ parameters.configuration }}${{ parameters.inputArtifactStem }} + steps: + - checkout: self + submodules: false + clean: true + fetchDepth: 1 + fetchTags: false + + - download: current + displayName: Download artifacts + artifact: $(ArtifactName) + patterns: |- + **/tests/*.FuzzTests/** + + - task: onefuzz-task@0 + inputs: + onefuzzOSes: Windows + env: + onefuzzDropDirectory: $(Pipeline.Workspace)\$(ArtifactName)\x64\Release\x64\Release\tests + SYSTEM_ACCESSTOKEN: $(System.AccessToken) diff --git a/.pipelines/verifyDepsJsonLibraryVersions.ps1 b/.pipelines/verifyDepsJsonLibraryVersions.ps1 index 7d5fc02c1095..3837514b4667 100644 --- a/.pipelines/verifyDepsJsonLibraryVersions.ps1 +++ b/.pipelines/verifyDepsJsonLibraryVersions.ps1 @@ -15,7 +15,7 @@ Param( $referencedFileVersionsPerDll = @{} $totalFailures = 0 -Get-ChildItem $targetDir -Recurse -Filter *.deps.json -Exclude UITests-FancyZones*,MouseJump.Common.UnitTests* | ForEach-Object { +Get-ChildItem $targetDir -Recurse -Filter *.deps.json -Exclude UITests-FancyZones*,MouseJump.Common.UnitTests*,AdvancedPaste.FuzzTests* | ForEach-Object { # Temporarily exclude FancyZones UI tests because of Appium.WebDriver dependencies $depsJsonFullFileName = $_.FullName $depsJsonFileName = $_.Name diff --git a/PowerToys.sln b/PowerToys.sln index 1e0926876f74..a3101d8fac5c 100644 --- a/PowerToys.sln +++ b/PowerToys.sln @@ -637,6 +637,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NewPlus.ShellExtension.win1 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdvancedPaste.UnitTests", "src\modules\AdvancedPaste\AdvancedPaste.UnitTests\AdvancedPaste.UnitTests.csproj", "{D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdvancedPaste.FuzzTests", "src\modules\AdvancedPaste\AdvancedPaste.FuzzTests\AdvancedPaste.FuzzTests.csproj", "{7F5B9557-5878-4438-A721-3E28296BA193}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM64 = Debug|ARM64 @@ -2821,6 +2823,18 @@ Global {D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Release|x64.Build.0 = Release|x64 {D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Release|x86.ActiveCfg = Release|x64 {D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE}.Release|x86.Build.0 = Release|x64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Debug|ARM64.Build.0 = Debug|ARM64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Debug|x64.ActiveCfg = Debug|x64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Debug|x64.Build.0 = Debug|x64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Debug|x86.ActiveCfg = Debug|x64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Debug|x86.Build.0 = Debug|x64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Release|ARM64.ActiveCfg = Release|ARM64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Release|ARM64.Build.0 = Release|ARM64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Release|x64.ActiveCfg = Release|x64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Release|x64.Build.0 = Release|x64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Release|x86.ActiveCfg = Release|x64 + {7F5B9557-5878-4438-A721-3E28296BA193}.Release|x86.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -3055,6 +3069,7 @@ Global {89D0E199-B17A-418C-B2F8-7375B6708357} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF} {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E} = {CA716AE6-FE5C-40AC-BB8F-2C87912687AC} {D5E5F5EA-1B6C-4A73-88BE-304F36C9E4EE} = {9873BA05-4C41-4819-9283-CF45D795431B} + {7F5B9557-5878-4438-A721-3E28296BA193} = {9873BA05-4C41-4819-9283-CF45D795431B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0} diff --git a/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/AdvancedPaste.FuzzTests.csproj b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/AdvancedPaste.FuzzTests.csproj new file mode 100644 index 000000000000..f22ee39381d4 --- /dev/null +++ b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/AdvancedPaste.FuzzTests.csproj @@ -0,0 +1,26 @@ + + + net8.0-windows10.0.19041.0 + latest + enable + enable + + + ..\..\..\..\$(Platform)\$(Configuration)\tests\AdvancedPaste.FuzzTests\ + + + + + + + + + + + + + + PreserveNewest + + + diff --git a/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/Fuzz.md b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/Fuzz.md new file mode 100644 index 000000000000..7e83a77b8fa5 --- /dev/null +++ b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/Fuzz.md @@ -0,0 +1,45 @@ +# Fuzzing .NET Code with OneFuzz + +This document explains the purpose of the project, the rationale for using specific technologies, and key instructions for fuzz testing .NET code using OneFuzz. + +## Overview + +This project demonstrates fuzz testing for .NET applications. It uses a `.NET 8 (Windows)` project where a code file is linked to the project. The linked file contains the functions required for fuzz testing. + +## Why Use .NET 8 (Windows)? + +1. **Current Support**: At the time of writing, OneFuzz supports only .NET 8 projects. The Fuzz team is actively working on .NET 9 support. +2. **Interim Solution**: Until .NET 9 support is available, .NET 8 serves as a robust and temporary solution for fuzz testing, enabling direct code linking for efficient development. + +## Requesting Access + +To log into the production instance of OneFuzz with the CLI, you **must request access**. Visit the internal [OneFuzz Access Request Page](https://myaccess.microsoft.com/@microsoft.onmicrosoft.com#/access-packages/6df691eb-e3d1-444b-b4b2-9e944dc794be) for details. + +## How to Fuzz .NET Code + +To set up and run fuzz testing on .NET code, follow the detailed guide available [Fuzz .NET Code](https://eng.ms/docs/cloud-ai-platform/azure-edge-platform-aep/aep-security/epsf-edge-and-platform-security-fundamentals/the-onefuzz-service/onefuzz/howto/fuzzing-dotnet-code). + +## Running a .NET Fuzz Target Locally + +Testing a .NET fuzz target locally requires specific configurations. For a step-by-step guide, see the section on [Running a .NET Fuzz Target Locally](https://eng.ms/docs/cloud-ai-platform/azure-edge-platform-aep/aep-security/epsf-edge-and-platform-security-fundamentals/the-onefuzz-service/onefuzz/howto/fuzzing-dotnet-code#extra-running-a-net-fuzz-target-locally). + +## Writing a Good OneFuzzConfig.json + +The `OneFuzzConfig.json` file provides critical information for deploying fuzzing jobs using the OneFuzz Ingestion Preparation Tool and Ingestion Service. + +### Structure + +The primary structure is an array of configuration entries. Outside the array, the `configVersion` field is used to track changes to the configuration schema. + +For more details on how to write and structure this file, see the [OneFuzzConfig V3 Documentation](https://eng.ms/docs/cloud-ai-platform/azure-edge-platform-aep/aep-security/epsf-edge-and-platform-security-fundamentals/the-onefuzz-service/onefuzz/onefuzzconfig/onefuzzconfigv3). + +## Tools + +### OneFuzz Ingestion Preparation (OIP) Tool + +The OIP tool helps prepare data for ingestion and fuzz testing. Learn more about [OneFuzz Ingestion Preparation (OIP) Tool](https://eng.ms/docs/cloud-ai-platform/azure-edge-platform-aep/aep-security/epsf-edge-and-platform-security-fundamentals/the-onefuzz-service/onefuzz/oip/onefuzzingestionpreparationtool). + +### OneFuzz CLI + +The CLI provides commands to manage and execute fuzzing jobs. Download and set up the CLI by following this [guide](https://eng.ms/docs/cloud-ai-platform/azure-edge-platform-aep/aep-security/epsf-edge-and-platform-security-fundamentals/the-onefuzz-service/onefuzz/howto/downloading-cli). + diff --git a/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/FuzzTests.cs b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/FuzzTests.cs new file mode 100644 index 000000000000..a23618862c78 --- /dev/null +++ b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/FuzzTests.cs @@ -0,0 +1,32 @@ +// 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 AdvancedPaste.Helpers; +using Windows.ApplicationModel.DataTransfer; + +// OneFuzz currently does not support .NET 9 code testing, so this is a temporary solution. +// Create a .NET 8 project and use a file link to include the code for testing first. +namespace AdvancedPaste.FuzzTests +{ + public class FuzzTests + { + public static void FuzzToJsonFromXmlOrCsv(ReadOnlySpan input) + { + try + { + var dataPackage = new DataPackage(); + dataPackage.SetText(input.ToString()); + _ = Task.Run(async () => await JsonHelper.ToJsonFromXmlOrCsvAsync(dataPackage.GetView())).Result; + } + catch (Exception ex) when (ex is ArgumentException) + { + // This is an example. It's important to filter out any *expected* exceptions from our code here. + // However, catching all exceptions is considered an anti-pattern because it may suppress legitimate + // issues, such as a NullReferenceException thrown by our code. In this case, we still re-throw + // the exception, as the ToJsonFromXmlOrCsvAsync method is not expected to throw any exceptions. + throw; + } + } + } +} diff --git a/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/Logger.cs b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/Logger.cs new file mode 100644 index 000000000000..4f47fe5713e8 --- /dev/null +++ b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/Logger.cs @@ -0,0 +1,46 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +// This is used for fuzz testing and ensures that the project links only to JsonHelper, +// avoiding unnecessary connections to additional files +namespace ManagedCommon +{ + public static class Logger + { + // An empty method to simulate logging information + public static void LogTrace() + { + // Do nothing + } + + // An empty method to simulate logging information + public static void LogInfo(string message) + { + // Do nothing + } + + // An empty method to simulate logging warnings + public static void LogWarning(string message) + { + // Do nothing + } + + // An empty method to simulate logging errors + public static void LogError(string message, Exception? ex = null) + { + // Do nothing + } + + public static void LogDebug(string message, Exception? ex = null) + { + // Do nothing + } + } +} diff --git a/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/MSTestSettings.cs b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/MSTestSettings.cs new file mode 100644 index 000000000000..5b05c0b86e3f --- /dev/null +++ b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/MSTestSettings.cs @@ -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)] diff --git a/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/OneFuzzConfig.json b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/OneFuzzConfig.json new file mode 100644 index 000000000000..41bdc8c58ad2 --- /dev/null +++ b/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/OneFuzzConfig.json @@ -0,0 +1,47 @@ +{ + "configVersion": 3, + "entries": [ + { + "fuzzer": { + "$type": "libfuzzerDotNet", + "dll": "AdvancedPaste.FuzzTests.dll", + "class": "AdvancedPaste.FuzzTests.FuzzTests", + "method": "FuzzToJsonFromXmlOrCsv", + "FuzzingTargetBinaries": [ + "PowerToys.AdvancedPaste.dll" + ] + }, + "adoTemplate": { + // supply the values appropriate to your + // project, where bugs will be filed + "org": "microsoft", + "project": "OS", + "AssignedTo": "leilzh@microsoft.com", + "AreaPath": "OS\\Windows Client and Services\\WinPD\\DEEP-Developer Experience, Ecosystem and Partnerships\\SHINE\\PowerToys", + "IterationPath": "OS\\Future" + }, + "jobNotificationEmail": "leilzh@microsoft.com", + "skip": false, + "rebootAfterSetup": false, + "oneFuzzJobs": [ + // at least one job is required + { + "projectName": "AdvancedPaste", + "targetName": "AdvancedPaste-dotnet-fuzzer" + } + ], + "jobDependencies": [ + // this should contain, at minimum, + // the DLL and PDB files + // you will need to add any other files required + // (globs are supported) + "AdvancedPaste.FuzzTests.dll", + "AdvancedPaste.FuzzTests.pdb", + "Microsoft.Windows.SDK.NET.dll", + "Newtonsoft.Json.dll", + "WinRT.Runtime.dll" + ], + "SdlWorkItemId": 49911822 + } + ] +}