diff options
author | Tomáš Rylek <trylek@microsoft.com> | 2022-07-30 18:39:54 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-30 18:39:54 +0300 |
commit | aa8489c135ff53bd6ed03d948502f114e7ac12e0 (patch) | |
tree | b1d6301ae103d4b39f5b39b0062a29ced556b487 | |
parent | 948142214f24c0b2db485e9246b73f18be43cf49 (diff) |
Implement test checking whether CET is active (#71509)
As part of Control Flow Enforcement Technology (CET) testing we need
to make sure that CET is actually active on the execution machines;
otherwise subtle infra changes could easily regress the testing by
inadvertently deactivating CET without anyone noticing. This change
introduces an initial CET availability test for this purpose.
Thanks
Tomas
-rw-r--r-- | eng/pipelines/common/templates/runtimes/run-test-job.yml | 12 | ||||
-rw-r--r-- | eng/pipelines/runtime-cet.yml | 1 | ||||
-rw-r--r-- | src/tests/Directory.Build.targets | 4 | ||||
-rw-r--r-- | src/tests/baseservices/CET/CETCheck.cpp | 11 | ||||
-rw-r--r-- | src/tests/baseservices/CET/CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/tests/baseservices/CET/CheckCETPresence.cs | 20 | ||||
-rw-r--r-- | src/tests/baseservices/CET/CheckCETPresence.csproj | 14 | ||||
-rw-r--r-- | src/tests/build.proj | 1 |
8 files changed, 65 insertions, 2 deletions
diff --git a/eng/pipelines/common/templates/runtimes/run-test-job.yml b/eng/pipelines/common/templates/runtimes/run-test-job.yml index fdad46255cc..298cae733ad 100644 --- a/eng/pipelines/common/templates/runtimes/run-test-job.yml +++ b/eng/pipelines/common/templates/runtimes/run-test-job.yml @@ -11,6 +11,7 @@ parameters: liveLibrariesBuildConfig: '' crossgen2: false compositeBuildMode: false + useCodeFlowEnforcement: '' helixQueues: '' condition: true stagedBuild: false @@ -112,6 +113,13 @@ jobs: - name: runtimeVariantArg value: '/p:RuntimeVariant=${{ parameters.runtimeVariant }}' + - name: codeFlowEnforcementArg + value: '' + + - ${{ if ne(parameters.useCodeFlowEnforcement, '') }}: + - name: codeFlowEnforcementArg + value: '/p:UseCodeFlowEnforcement=${{ parameters.useCodeFlowEnforcement }}' + - name: crossgenArg value: '' - name: LogNamePrefix @@ -301,8 +309,8 @@ jobs: # during product build (so that we could zip up the files in their final test location # and directly unzip them there after download). Unfortunately the logic to copy # the native artifacts to the final test folders is dependent on availability of the - # managed test artifacts. - - script: $(Build.SourcesDirectory)/src/tests/build$(scriptExt) copynativeonly $(logRootNameArg)Native $(testTreeFilterArg) $(runtimeFlavorArgs) $(crossgenArg) $(buildConfig) $(archType) $(priorityArg) $(librariesOverrideArg) + # managed test artifacts. This step also generates the final test execution scripts. + - script: $(Build.SourcesDirectory)/src/tests/build$(scriptExt) copynativeonly $(logRootNameArg)Native $(testTreeFilterArg) $(runtimeFlavorArgs) $(crossgenArg) $(buildConfig) $(archType) $(priorityArg) $(librariesOverrideArg) $(codeFlowEnforcementArg) displayName: Copy native test components to test output folder diff --git a/eng/pipelines/runtime-cet.yml b/eng/pipelines/runtime-cet.yml index ab2fe28ad55..4e882faa2e9 100644 --- a/eng/pipelines/runtime-cet.yml +++ b/eng/pipelines/runtime-cet.yml @@ -82,3 +82,4 @@ jobs: jobParameters: testGroup: innerloop liveLibrariesBuildConfig: release + useCodeFlowEnforcement: true diff --git a/src/tests/Directory.Build.targets b/src/tests/Directory.Build.targets index dccce1cb63a..000af600e2a 100644 --- a/src/tests/Directory.Build.targets +++ b/src/tests/Directory.Build.targets @@ -83,6 +83,10 @@ </ProjectReference> </ItemGroup> + <PropertyGroup Condition="'$(RequiresCodeFlowEnforcement)' == 'true'"> + <CLRTestTargetUnsupported Condition="'$(UseCodeFlowEnforcement)' != 'true'">true</CLRTestTargetUnsupported> + </PropertyGroup> + <!-- Determine if this project should be built or not --> <PropertyGroup> <BuildAllProjects Condition="'$(BuildAllProjects)' == ''">false</BuildAllProjects> diff --git a/src/tests/baseservices/CET/CETCheck.cpp b/src/tests/baseservices/CET/CETCheck.cpp new file mode 100644 index 00000000000..0c8d9d2d381 --- /dev/null +++ b/src/tests/baseservices/CET/CETCheck.cpp @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if defined(TARGET_AMD64) && defined(TARGET_WINDOWS) +#include <intrin.h> + +extern "C" __declspec(dllexport) __int64 ReadShadowStackPointer() +{ + return _rdsspq(); +} +#endif diff --git a/src/tests/baseservices/CET/CMakeLists.txt b/src/tests/baseservices/CET/CMakeLists.txt new file mode 100644 index 00000000000..226738c71f8 --- /dev/null +++ b/src/tests/baseservices/CET/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(cet_check SHARED CETCheck.cpp) + +# add the install targets +install (TARGETS cet_check DESTINATION bin) diff --git a/src/tests/baseservices/CET/CheckCETPresence.cs b/src/tests/baseservices/CET/CheckCETPresence.cs new file mode 100644 index 00000000000..656fcadfb7c --- /dev/null +++ b/src/tests/baseservices/CET/CheckCETPresence.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; + +static class Program +{ + [DllImport("cet_check.dll")] + private static extern long ReadShadowStackPointer(); + + public static int Main() + { + Console.WriteLine("Checking whether codeflow enforcement technology (CET) is active"); + long ssp = ReadShadowStackPointer(); + Console.WriteLine("Shadow stack pointer: 0x{0:x16}", ssp); + // Non-zero shadow stack pointer value confirms that CET is active on the runtime processor. + return ssp != 0 ? 100 : 101; + } +} diff --git a/src/tests/baseservices/CET/CheckCETPresence.csproj b/src/tests/baseservices/CET/CheckCETPresence.csproj new file mode 100644 index 00000000000..845ff56e1c7 --- /dev/null +++ b/src/tests/baseservices/CET/CheckCETPresence.csproj @@ -0,0 +1,14 @@ +<Project Sdk="Microsoft.NET.Sdk"> + <PropertyGroup> + <OutputType>Exe</OutputType> + <RequiresCodeFlowEnforcement>true</RequiresCodeFlowEnforcement> + <RequiresProcessIsolation>true</RequiresProcessIsolation> + <CLRTestTargetUnsupported Condition="'$(TargetArchitecture)' != 'x64' or '$(TargetOS)' != 'windows'">true</CLRTestTargetUnsupported> + </PropertyGroup> + <ItemGroup> + <Compile Include="$(MSBuildProjectName).cs" /> + </ItemGroup> + <ItemGroup> + <CMakeProjectReference Include="CMakeLists.txt" /> + </ItemGroup> +</Project> diff --git a/src/tests/build.proj b/src/tests/build.proj index e83ee2129ed..59ba59511a4 100644 --- a/src/tests/build.proj +++ b/src/tests/build.proj @@ -487,6 +487,7 @@ <GroupBuildCmd>$(GroupBuildCmd) "/p:RuntimeFlavor=$(RuntimeFlavor)"</GroupBuildCmd> <GroupBuildCmd>$(GroupBuildCmd) "/p:RuntimeVariant=$(RuntimeVariant)"</GroupBuildCmd> <GroupBuildCmd>$(GroupBuildCmd) "/p:CLRTestBuildAllTargets=$(CLRTestBuildAllTargets)"</GroupBuildCmd> + <GroupBuildCmd>$(GroupBuildCmd) "/p:UseCodeFlowEnforcement=$(UseCodeFlowEnforcement)"</GroupBuildCmd> <GroupBuildCmd>$(GroupBuildCmd) "/p:__TestGroupToBuild=$(__TestGroupToBuild)"</GroupBuildCmd> <GroupBuildCmd>$(GroupBuildCmd) "/p:__SkipRestorePackages=1"</GroupBuildCmd> <GroupBuildCmd>$(GroupBuildCmd) /nodeReuse:false</GroupBuildCmd> |