在沙箱AppDomain的堆栈跟踪中缺少文件名和行号



我在一个锁定的AppDomain沙箱中运行代码。从这个AppDomain内抛出的异常不包括行号,即使pdbs是可用的。试图访问堆栈跟踪的代码是完全可信的:程序集被签名并作为强程序集加载到应用程序域中。所以我希望堆栈跟踪包含文件名和行号。我不能将AppDomain标记为完全可信,因为这会破坏沙箱的目的。我如何让我的堆栈跟踪包含文件名和行号?

我已经更新了代码,以显示如何使用Assembly.LoadFile加载外部代码。我最初的问题使用了一个单一的程序集,在我看来,它表现出与我的"真实"应用程序相同的行为。然而,正如@simon-mourier的答案适用于这个简化的代码,它在我的"真实"应用程序中不起作用。我已经更新了代码来反映这一点。

下面的示例代码(基于这个示例)显示了这个问题。有两个程序集:

  • 执行(父)程序集,该程序集已签名并具有完全信任
  • 未签名且不能信任的子程序集。

我已经在我的github上发布了示例应用程序。

// Executing signed assembly
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Permissions;
using System.Security.Policy;
namespace Parent
{
public class Worker : MarshalByRefObject
{
private static string childpath = Path.Combine(Path.GetDirectoryName(typeof(Worker).Assembly.Location), "Child.dll");
private static void Main()
{
var w = new Worker();
w.TestExceptionStacktrace();
var adSandbox = GetInternetSandbox();
var handle = Activator.CreateInstanceFrom(
adSandbox,
typeof(Worker).Assembly.ManifestModule.FullyQualifiedName,
typeof(Worker).FullName);
w = (Worker)handle.Unwrap();
w.TestExceptionStacktrace();
}
public void TestExceptionStacktrace()
{
TestInner();
}
private void TestInner()
{
var ass = Assembly.LoadFile(childpath);
var playMethod = ass.GetTypes()[0].GetMethod("Play");
try
{
playMethod.Invoke(null, Array.Empty<object>());
}
catch (Exception e)
{
var s = e.ToString();
Console.WriteLine("Stack trace contains {0}line numbers for Child assembly:",
s.Split(new[] { Environment.NewLine }, StringSplitOptions.None)
.Single(x => x.Contains("Play()")).Contains("line")
? ""
: "no ");
Console.WriteLine($"   {s}");
}
}
// ------------ Helper method ---------------------------------------
private static AppDomain GetInternetSandbox()
{
// Create the permission set to grant to all assemblies.
var hostEvidence = new Evidence();
hostEvidence.AddHostEvidence(new Zone(
System.Security.SecurityZone.Internet));
var pset =
System.Security.SecurityManager.GetStandardSandbox(hostEvidence);
// add this to the permission set
pset.AddPermission(new FileIOPermission(
FileIOPermissionAccess.PathDiscovery, typeof(Worker).Assembly.Location)
);
pset.AddPermission(new FileIOPermission(
FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read, Path.GetDirectoryName(childpath))
);
// Identify the folder to use for the sandbox.
var ads = new AppDomainSetup();
ads.ApplicationBase = System.IO.Directory.GetCurrentDirectory();
var fullTrustAssemblies = new[]
{
typeof(Worker).Assembly.Evidence.GetHostEvidence<StrongName>(),
};
// Create the sandboxed application domain.
return AppDomain.CreateDomain("Sandbox", hostEvidence, ads, pset, fullTrustAssemblies);
}
}
}
// Child assembly (not signed)
using System;
namespace Child
{
public class Child
{
public static void Play()
{
var ad = AppDomain.CurrentDomain;
Console.WriteLine("rnApplication domain '{0}': IsFullyTrusted = {1}",
ad.FriendlyName, ad.IsFullyTrusted);
Console.WriteLine("   IsFullyTrusted = {0} for the current assembly {1}",
typeof(Child).Assembly.IsFullyTrusted,
typeof(Child).Assembly);
Console.WriteLine("   IsFullyTrusted = {0} for mscorlib",
typeof(int).Assembly.IsFullyTrusted);
throw new Exception("Some exception");
}
}
}

该代码的输出是:

Application domain 'Parent.exe': IsFullyTrusted = True
IsFullyTrusted = True for the current assembly Child, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
IsFullyTrusted = True for mscorlib
Stack trace contains line numbers for Child assembly:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Exception: Some exception
at Child.Child.Play() in C:UsersBoukeDeveloperSandboxStacktraceChildChild.cs:line 20
(...)
Application domain 'Sandbox': IsFullyTrusted = False
IsFullyTrusted = False for the current assembly Child, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
IsFullyTrusted = True for mscorlib
Stack trace contains no line numbers for Child assembly:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Exception: Some exception
at Child.Child.Play()
(...)

到目前为止,我发现使用Assembly.Load(byte[], byte[], SecurityContextSource.CurrentAssembly)工作,但击败沙盒(加载程序集具有完全信任)。Assembly.Load(byte[], byte[], SecurityContextSource.CurrentAppDomain)不工作

互联网区是相当严格的。需要堆栈跟踪的AppDomain需要对文件本身进行访问,因此您需要在创建AppDomain时使用的权限集中添加一些文件权限,如下所示:

...
// add this to the permission set
pset.AddPermission(new FileIOPermission(
FileIOPermissionAccess.PathDiscovery, typeof(Worker).Assembly.Location)
);
return AppDomain.CreateDomain("Sandbox", hostEvidence, ads, pset, fullTrustAssemblies);

注意:当你在CAS中遇到问题时,你可以使用AppDomain的FirstChanceException事件(或者启用Visual Studio的所有异常,如果你使用它),它会显示你内部吞下的错误。

最新更新