Skip to content
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

Fix disallow-unsafe-type Akka.NET settings and harden unsafe type detection #301

Merged
15 changes: 12 additions & 3 deletions build-system/pr-validation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,19 @@ jobs:
vmImage: 'windows-2019'
scriptFileName: build.cmd
scriptArgs: all

- template: azure-pipeline.template.yaml
parameters:
name: 'linux_pr'
displayName: 'Linux PR Validation'
name: 'linux_pr_net_core'
displayName: 'Linux PR Validation (netcoreapp3.1)'
vmImage: 'ubuntu-16.04'
scriptFileName: ./build.sh
scriptArgs: all
scriptArgs: runTestsNetCore

- template: azure-pipeline.template.yaml
parameters:
name: 'linux_pr_net_5'
displayName: 'Linux PR Validation (net5.0)'
vmImage: 'ubuntu-16.04'
scriptFileName: ./build.sh
scriptArgs: runTestsNet
15 changes: 12 additions & 3 deletions build-system/windows-pr-validation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,19 @@ jobs:
vmImage: 'windows-2019'
scriptFileName: build.cmd
scriptArgs: all

- template: azure-pipeline.template.yaml
parameters:
name: 'linux_pr'
displayName: 'Linux PR Validation'
name: 'linux_pr_net_core'
displayName: 'Linux PR Validation (netcoreapp3.1)'
vmImage: 'ubuntu-18.04'
scriptFileName: ./build.sh
scriptArgs: all
scriptArgs: runTestsNetCore

- template: azure-pipeline.template.yaml
parameters:
name: 'linux_pr_net_5'
displayName: 'Linux PR Validation (net5.0)'
vmImage: 'ubuntu-18.04'
scriptFileName: ./build.sh
scriptArgs: runTestsNet
2 changes: 2 additions & 0 deletions build.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ Target "Clean" (fun _ ->

CleanDirs !! "./**/bin"
CleanDirs !! "./**/obj"

CreateDir "bin/nuget"
)

Target "AssemblyInfo" (fun _ ->
Expand Down
73 changes: 73 additions & 0 deletions src/Hyperion.Akka.Integration.Tests/IntegrationSpec.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
using Akka.Actor;
using Akka.Configuration;
using Akka.Serialization;
using Xunit;
using Akka.TestKit;
using Akka.TestKit.Xunit2;
using FluentAssertions;
using Hyperion.Internal;
using Xunit.Abstractions;
using AkkaSerializer = Akka.Serialization.Serializer;

Expand Down Expand Up @@ -72,6 +80,71 @@ public void Bugfix263_Akka_HyperionSerializer_should_serialize_ActorPath_list()
deserialized.Destinations[0].Should().Be(deserialized.Destinations[1]);
}

[Fact]
public async Task CanDeserializeANaughtyTypeWhenAllowed()
{
var config = ConfigurationFactory.ParseString(@"
akka {
serialize-messages = on
actor {
serializers {
hyperion = ""Akka.Serialization.HyperionSerializer, Akka.Serialization.Hyperion""
}
serialization-bindings {
""System.Object"" = hyperion
}
serialization-settings.hyperion.disallow-unsafe-type = false
}
}");
var system = ActorSystem.Create("unsafeSystem", config);

try
{
var serializer = system.Serialization.FindSerializerForType(typeof(DirectoryInfo));
var di = new DirectoryInfo(@"c:\");

var serialized = serializer.ToBinary(di);
var deserialized = serializer.FromBinary<DirectoryInfo>(serialized);
}
finally
{
await system.Terminate();
}
}

[Fact]
public async Task CantDeserializeANaughtyTypeByDefault()
{
var config = ConfigurationFactory.ParseString(@"
akka {
serialize-messages = on
actor {
serializers {
hyperion = ""Akka.Serialization.HyperionSerializer, Akka.Serialization.Hyperion""
}
serialization-bindings {
""System.Object"" = hyperion
}
serialization-settings.hyperion.disallow-unsafe-type = true # this is the default value
}
}");
var system = ActorSystem.Create("unsafeSystem", config);

try
{
var serializer = system.Serialization.FindSerializerForType(typeof(DirectoryInfo));
var di = new DirectoryInfo(@"c:\");

var serialized = serializer.ToBinary(di);
var ex = Assert.Throws<SerializationException>(() => serializer.FromBinary<DirectoryInfo>(serialized));
ex.InnerException.Should().BeOfType<EvilDeserializationException>();
}
finally
{
await system.Terminate();
}
}

private class MyActor: ReceiveActor
{

Expand Down
45 changes: 41 additions & 4 deletions src/Hyperion.Tests/Hyperion.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,54 @@
<DefineConstants>$(DefineConstants);NETFX</DefineConstants>
</PropertyGroup>


<ItemGroup Condition="'$(TargetFramework)' == '$(NetFrameworkTestVersion)'">
<Reference Include="System.Drawing">
<Private>true</Private>
</Reference>
<Reference Include="System.Web">
<HintPath>./lib</HintPath>
<Private>true</Private>
</Reference>
<Reference Include="System.Web.Mobile">
<HintPath>./lib</HintPath>
<Private>true</Private>
</Reference>
<Reference Include="System.Windows.Forms">
<HintPath>./lib</HintPath>
<Private>true</Private>
</Reference>
<Reference Include="PresentationFramework">
<HintPath>./lib</HintPath>
<Private>true</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.Text.UI.Wpf">
<HintPath>./lib</HintPath>
<Private>true</Private>
</Reference>
<Reference Include="System.Drawing.Design">
<HintPath>./lib</HintPath>
<Private>true</Private>
</Reference>
<Reference Include="System.Drawing">
<HintPath>./lib</HintPath>
<Private>true</Private>
</Reference>
<Reference Include="System.IdentityModel">
<HintPath>./lib</HintPath>
<Private>true</Private>
</Reference>
<Reference Include="System.Activities.Presentation">
<HintPath>./lib</HintPath>
<Private>true</Private>
</Reference>
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' != '$(NetFrameworkTestVersion)'">
<PackageReference Include="System.Management.Automation" Version="6.2.7" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="$(FluentAssertionsVersion)" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(TestSdkVersion)" />
<PackageReference Include="System.Collections.Immutable" Version="5.0.0" />
<PackageReference Include="System.Security.Principal.Windows" Version="5.0.0" />
<PackageReference Include="xunit" Version="$(XunitVersion)" />
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitRunnerVersion)" />
</ItemGroup>
Expand Down
90 changes: 88 additions & 2 deletions src/Hyperion.Tests/UnsafeDeserializationExclusionTests.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
using System;
using System.Collections.Generic;
using System.IO;
using Hyperion.Extensions;
using System.Runtime.InteropServices;
using Hyperion.Internal;
using Xunit;
using FluentAssertions;
using Hyperion.Extensions;
using Xunit.Abstractions;

namespace Hyperion.Tests
{
public class UnsafeDeserializationExclusionTests
{
private readonly ITestOutputHelper _output;

public UnsafeDeserializationExclusionTests(ITestOutputHelper output)
{
_output = output;
}

[Fact]
public void CantDeserializeANaughtyType()
{
//System.Diagnostics.Process p = new Process();
var serializer = new Hyperion.Serializer();
var di =new System.IO.DirectoryInfo(@"c:\");

Expand All @@ -25,6 +34,73 @@ public void CantDeserializeANaughtyType()
}
}

[Theory]
[MemberData(nameof(DangerousObjectFactory))]
public void DetectNaughtyTypesByDefault(Type dangerousType)
Copy link
Contributor Author

@Arkatufus Arkatufus Mar 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Detection hardening unit test, actually try to use the dangerous types and see if they are being caught by the default filter

{
_output.WriteLine($"Testing for dangerous type [{dangerousType.AssemblyQualifiedName}]");
TypeEx.IsDisallowedType(dangerousType).Should().BeTrue();
}
/*
X "System.Security.Principal.WindowsIdentity",
X "System.Security.Principal.WindowsPrincipal",
X "System.Security.Claims.ClaimsIdentity",
X "System.Web.Security.RolePrincipal",
X "System.Windows.Forms.AxHost.State",
X "System.Windows.Data.ObjectDataProvider",
X "System.Management.Automation.PSObject",
X "System.IO.FileSystemInfo",
X "System.IO.FileInfo",
X "System.IdentityModel.Tokens.SessionSecurityToken",
X "SessionViewStateHistoryItem",
X "TextFormattingRunProperties",
X "ToolboxItemContainer",
X "System.CodeDom.Compiler.TempFileCollection",
X "System.Activities.Presentation.WorkflowDesigner",
X "System.Windows.ResourceDictionary",
X "System.Windows.Forms.BindingSource",
X "System.Diagnostics.Process",
"System.Management.IWbemClassObjectFreeThreaded" // Need to have sharepoint installed, simulated
"Microsoft.Exchange.Management.SystemManager.WinForms.ExchangeSettingsProvider", // Need to have ?Exchange? installed, simulated
??? "System.Security.Principal.WindowsClaimsIdentity", // This FQCN seemed to not exist in the past
*/
public static IEnumerable<object[]> DangerousObjectFactory()
{
var isWindow = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);

yield return new object[]{ typeof(System.IO.FileInfo) };
yield return new object[]{ typeof(System.IO.FileSystemInfo) };
yield return new object[]{ typeof(System.Security.Claims.ClaimsIdentity)};
yield return new object[]{ typeof(System.Diagnostics.Process)};
yield return new object[]{ typeof(System.CodeDom.Compiler.TempFileCollection)};
yield return new object[]{ typeof(System.Management.IWbemClassObjectFreeThreaded)}; // SIMULATED
yield return new object[]{ typeof(Microsoft.Exchange.Management.SystemManager.WinForms.ExchangeSettingsProvider)}; // SIMULATED
#if !NETFX
yield return new object[]{ typeof(System.Management.Automation.PSObject)};
#endif

if (isWindow)
{
yield return new object[]{ typeof(System.Security.Principal.WindowsIdentity) };
yield return new object[]{ typeof(System.Security.Principal.WindowsPrincipal)};
#if NETFX
var ass = typeof(System.Web.Mobile.MobileCapabilities).Assembly;
var type = ass.GetType("System.Web.UI.MobileControls.SessionViewState+SessionViewStateHistoryItem");
yield return new object[]{ type };

yield return new object[]{ typeof(System.Drawing.Design.ToolboxItemContainer)};
yield return new object[]{ typeof(System.Activities.Presentation.WorkflowDesigner)};
yield return new object[]{ typeof(Microsoft.VisualStudio.Text.Formatting.TextFormattingRunProperties)};
yield return new object[]{ typeof(System.IdentityModel.Tokens.SessionSecurityToken)};
yield return new object[]{ typeof(System.Web.Security.RolePrincipal) };
yield return new object[]{ typeof(System.Windows.Forms.AxHost.State)};
yield return new object[]{ typeof(System.Windows.Data.ObjectDataProvider)};
yield return new object[]{ typeof(System.Windows.ResourceDictionary)};
yield return new object[]{ typeof(System.Windows.Forms.BindingSource)};
#endif
}
}

internal class ClassA
{ }

Expand Down Expand Up @@ -84,4 +160,14 @@ public void TypeFilterShouldThrowOnNaughtyType()
}
}
}
}

namespace System.Management
{
public interface IWbemClassObjectFreeThreaded{ }
}

namespace Microsoft.Exchange.Management.SystemManager.WinForms
{
public class ExchangeSettingsProvider { }
}
Binary file not shown.
Binary file added src/Hyperion.Tests/lib/PresentationFramework.dll
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added src/Hyperion.Tests/lib/System.Drawing.dll
Binary file not shown.
Binary file added src/Hyperion.Tests/lib/System.IdentityModel.dll
Binary file not shown.
Binary file added src/Hyperion.Tests/lib/System.Web.Mobile.dll
Binary file not shown.
Binary file added src/Hyperion.Tests/lib/System.Web.dll
Binary file not shown.
Binary file added src/Hyperion.Tests/lib/System.Windows.Forms.dll
Binary file not shown.
Loading