Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing with Roslyn.Services.Workspace results in a SecurityException while working at x86 target

I'm working on set of constants for my project, and I'd like to use roslyn to verify some of them in source code level. To achieve this, I'm loading entire solution using following snippet into AppDomain with IsFullyTrusted == true and IsHomogenous == true, i.e. remoting is enabled with x86 platform target:

// load workspace, i.e. solution from Visual Studio
var workspace = Roslyn.Services.Workspace.LoadSolution(solutionFile);

Test runners for NCrunch and NUnit with x86 platform with Roslyn

But while using either ncrunch 1.45 or nunit 2.6.2 nunit-console-x86.exe with platform configuration x86 as test runners, I'm constantly getting following System.Security.SecurityException:

System.Security.SecurityException : Type System.Runtime.Remoting.ObjRef and the types derived from it (such as System.Runtime.Remoting.ObjRef) are not permitted to be deserialized at this security level.

Server stack trace: 
   at System.Runtime.Serialization.FormatterServices.CheckTypeSecurity(Type t, TypeFilterLevel securityLevel)
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.CheckSecurity(ParseRecord pr)
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ParseObject(ParseRecord pr)
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Parse(ParseRecord pr)
   at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryObjectWithMapTyped record)
   at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryHeaderEnum binaryHeaderEnum)
   at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Remoting.Channels.CoreChannel.DeserializeBinaryRequestMessage(String objectUri, Stream inputStream, Boolean bStrictBinding, TypeFilterLevel securityLevel)
   at System.Runtime.Remoting.Channels.BinaryServerFormatterSink.ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, IMessage& responseMsg, ITransportHeaders& responseHeaders, Stream& responseStream)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at Roslyn.Utilities.RemoteServices.Initialize(Int32 clientProcessId)
   at Roslyn.Utilities.RemoteServices.StartRemoteServicesProcess()
   at Roslyn.Utilities.RemoteServices.get_Instance()
   at Roslyn.Utilities.RemoteServices.CreateInstance[T]()
   at Roslyn.Services.Host.TemporaryStorageServiceFactory.CreateService(IWorkspaceServiceProvider workspaceServices)
   at Roslyn.Services.Host.WorkspaceServiceProviderFactory.<>c__DisplayClass6.<OnImportsSatisfied>b__1(IWorkspaceServiceProvider wsp)
   at Roslyn.Services.Host.WorkspaceServiceProvider.ConstructService(Type type)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Roslyn.Services.Host.WorkspaceServiceProvider.GetService[TWorkspaceService]()
   at Roslyn.Services.SolutionServices..ctor(IWorkspaceServiceProvider workspaceServices)
   at Roslyn.Services.Solution..ctor(SolutionId id, String filePath, VersionStamp version, VersionStamp latestProjectVersion, IWorkspaceServiceProvider workspaceServices)
   at Roslyn.Services.Host.SolutionFactoryServiceFactory.SolutionFactoryService.CreateSolution(SolutionId id)
   at Roslyn.Services.Host.TrackingWorkspace.CreateNewSolution(ISolutionFactoryService solutionFactory, SolutionId id)
   at Roslyn.Services.Host.TrackingWorkspace..ctor(IWorkspaceServiceProvider workspaceServiceProvider, Boolean enableBackgroundCompilation, Boolean enableInProgressSolutions)
   at Roslyn.Services.Host.HostWorkspace..ctor(IWorkspaceServiceProvider workspaceServiceProvider, Boolean enableBackgroundCompilation, Boolean enableInProgressSolutions, Boolean enableFileTracking)
   at Roslyn.Services.Host.LoadedWorkspace..ctor(IWorkspaceServiceProvider workspaceServiceProvider, IDictionary`2 globalProperties, Boolean enableBackgroundCompilation, Boolean enableFileTracking)
   at Roslyn.Services.Host.LoadedWorkspace.LoadSolution(String solutionFileName, String configuration, String platform, Boolean enableFileTracking)
   at Roslyn.Services.Workspace.LoadSolution(String solutionFileName, String configuration, String platform, Boolean enableFileTracking)

There is a discussion on NCrunch forum, but I have tried all following options without success:

  • Add [assembly: AllowPartiallyTrustedCallers] to AssemblyInfo.cs
  • Add [assembly: SecurityRules(SecurityRuleSet.Level1)] to AssemblyInfo.cs
  • Add <NetFx40_LegacySecurityPolicy enabled="true" /> to app.config
  • Run VS2012 as Administrator
  • Decorate both unittests and implementation with [SecuritySafeCritical]
  • Update: create new AppDomain and provide
    • PermissionState.Unrestricted, SecurityPermissionFlag.AllFlags and DataProtectionPermissionFlags.AllFlags
    • Add Host Evidence: SecurityZone.MyComputer, System.Security.Policy.Hash and System.Security.Policy.StrongName
    • Add all assemblies (both mine and Roslyn CTP) to fullTrustAssemblies while creating of AppDomain

Update #2

This exception happens only while I'm running test under x86 configuration, after I had switched to x64 platform configuration, everything seems to work fine

Question

Are there any other attributes or configuration changes to app.config or AppDomain that could help to enable deserialization in .NET Framework remoting for System.Runtime.Remoting.ObjRef while running under x86 configuration?

Temporary solution

Switch to x64 build configuration only for unittest project(s)

Source code

  • Whole source code is available at github: to reproduce error run following unittest using NCrunch IntrospectionTests.Introspection_SearchForComplexityGt10_ApprovedList
  • Discussion at NCrunch forum

Additional information

Also I notice...

  1. A lot of instances of Roslyn.Services.dll hang in background, after all tests had been completed.
  2. Lack of Host Evidences for NCrunch: System.Security.Policy.Hash and System.Security.Policy.StrongName with test runner assembly name
  3. resharper MSIL (should be x64 inside) and nunit 2.6.2 nunit-console.exe test runner are working fine, so it looks like Roslyn configuration/remoting/security configuration issue.
like image 630
Akim Avatar asked May 06 '13 07:05

Akim


2 Answers

It looks like ncrunch is executing the tests in Partial Trust, whereas Resharper is running them in Full Trust.

Roslyn has not been tested in Partial Trust scenarios. There are likely to be accesses to APIs that require Full Trust.

I haven't used ncrunch, but maybe there is a way to configure it to run the tests in Full Trust?

like image 136
Kevin Pilch Avatar answered Sep 19 '22 07:09

Kevin Pilch


I want to add something!

After upgrading an NUnit instance I manage to run to both 2.6.2 and 2.6.3 of the software, my team ran into similar issues with this exact System.Security exception that Akim was seeing.

We were creating an IpcChannel with some of our custom NUnit logic that wasn't created with the right trust settings, so we had to change something that looked like:

IpcChannel channel = new IpcChannel(string.Format("localhost:{0}", portNum));

To -

BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;

BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();

var properties = new System.Collections.Hashtable();
properties["name"] = "ipc";
properties["priority"] = "20";
properties["portName"] = string.Format("localhost:{0}", portNum);

IpcChannel channel = new IpcChannel(properties, clientProvider, serverProvider);

Just a quick fix I noticed that I figured I would forward to anybody seeing something similar that can't just switch their platform settings. To be fair, it took me about four hours to figure out so I didn't want the knowledge to go to waste.

like image 31
Patrick Ramser Avatar answered Sep 20 '22 07:09

Patrick Ramser