From d72c8b26138915673505eaa8674847d2decf322c Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Wed, 8 Jul 2020 14:58:22 -0700 Subject: [PATCH] Add tests for SecureAppContext --- .../tests/System.Runtime.Tests.csproj | 1 + .../System/AppContext/SecureAppContext.cs | 82 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 src/libraries/System.Runtime/tests/System/AppContext/SecureAppContext.cs diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj index 548ac964d8584..f6a8701f9b584 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj @@ -149,6 +149,7 @@ + diff --git a/src/libraries/System.Runtime/tests/System/AppContext/SecureAppContext.cs b/src/libraries/System.Runtime/tests/System/AppContext/SecureAppContext.cs new file mode 100644 index 0000000000000..b03775e706e60 --- /dev/null +++ b/src/libraries/System.Runtime/tests/System/AppContext/SecureAppContext.cs @@ -0,0 +1,82 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Reflection; +using Microsoft.DotNet.RemoteExecutor; +using Xunit; +using Xunit.Sdk; + +namespace System.Tests +{ + public partial class SecureAppContextTests + { + // these tests only make sense on platforms where reflection is expected to forbid overwriting initonly fields + public static bool RunForbidSettingInitonlyTests => PlatformDetection.IsNetCore && RemoteExecutor.IsSupported; + + [ConditionalFact(nameof(RunForbidSettingInitonlyTests))] + public void CannotUseReflectionToChangeValues() + { + RemoteExecutor.Invoke(() => + { + Type secureAppContextType = typeof(AppContext).Assembly.GetType("System.SecureAppContext", throwOnError: true); + + foreach (FieldInfo field in secureAppContextType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)) + { + try + { + Assert.True(field.FieldType.IsValueType, "Field is a reference type; instance members may be subject to mutation."); + Assert.True(field.IsInitOnly, "Field is mutable."); + + object originalValue = field.GetValue(null); + Assert.Throws(() => field.SetValue(null, originalValue)); + } + catch (Exception ex) + { + throw new Exception($"Failure when testing field {field.Name}.", ex); + } + } + }).Dispose(); + } + + [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [InlineData("Switch.System.Runtime.Serialization.SerializationGuard", "SerializationGuardEnabled", true)] + [InlineData("System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization", "BinaryFormatterEnabled", true)] + public void PopulatedAtAppDomainStart(string switchName, string propertyName, bool defaultValue) + { + RunTest(switchName, propertyName, null, defaultValue); + RunTest(switchName, propertyName, true, true); + RunTest(switchName, propertyName, false, false); + + static void RunTest(string switchName, string propertyName, bool? configuredValue, bool expectedValue) + { + try + { + RemoteInvokeOptions options = null; + if (configuredValue != null) + { + options = new RemoteInvokeOptions(); + options.RuntimeConfigurationOptions[switchName] = configuredValue.ToString(); + } + + RemoteExecutor.Invoke((switchName, propertyName, expectedValue) => + { + Type secureAppContextType = typeof(AppContext).Assembly.GetType("System.SecureAppContext", throwOnError: true); + PropertyInfo pi = secureAppContextType.GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + if (pi == null) + { + throw new XunitException($"Property {propertyName} not found."); + } + + Assert.Equal(bool.Parse(expectedValue), pi.GetValue(null)); + }, + switchName, propertyName, expectedValue.ToString(), options).Dispose(); + } + catch (Exception ex) + { + throw new Exception($"Exception occurred for scenario configuredValue={configuredValue?.ToString() ?? ""}, expectedValue={expectedValue}.", ex); + } + } + } + } +}