4
votes

I have an asp.net web api that has a logic to execute some dynamically generated DLLs. I want to create a new sandbox AppDomain with restricted permissionset to execute these DLLs.

This is the method to create new restricted appdomain:

public static AppDomain CreateRestrictedDomain(string applicationBasePath)
{
    PermissionSet permissionSet = new PermissionSet(PermissionState.None);
    permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
    permissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read, applicationBasePath));

    AppDomainSetup appDomainSetup = new AppDomainSetup
    {
        ApplicationBase = applicationBasePath,
        DisallowCodeDownload = true,
        DisallowBindingRedirects = true,
        DisallowPublisherPolicy = true,
        LoaderOptimization = LoaderOptimization.MultiDomainHost,
    };


    AppDomain restrictedDomain = AppDomain.CreateDomain(
        friendlyName: "MySandbox",
        securityInfo: null,
        info: appDomainSetup,
        grantSet: permissionSet,
        fullTrustAssemblies: null);

    return restrictedDomain;
}

The problem that I have is the first time when I reference the new appDomain, e.g. just to read the appDomain.FriendlyName, the framework tries to load a few dependencies present in the current application to the new AppDomain. If the dependencies are not in GAC, it will try to find them in the applicationBasePath, and it would fail because the applicationBasePath is set to a folder that stores only the untrusted DLLs.

My question is why creating a new AppDomain triggers loading of those extra dependencies. In my CreateRestrictedDomain method above, there's no reference to any of those dependencies.

I created a new asp.net project using the default template in VS 2013, and in the Index controller I just create a new AppDomain using the code above, and print out the name. Here's the code:

public ActionResult Index()
{
    var tempPath = Path.GetTempPath();
    var untrustedPath = Path.Combine(tempPath, "unstrusted");
    if (!Directory.Exists(untrustedPath))
    {
        Directory.CreateDirectory(untrustedPath);
    }
    var appDomain = AppDomainSandboxHelper.CreateRestrictedDomain(untrustedPath);
    var friendlyName = appDomain.FriendlyName;
    ViewBag.Title = friendlyName;

    return View();
}

When I run in debug mode, I can see that the line that read appDomain.FriendLyName would trigger System.Web.dll to be loaded into the new AppDomain "MySandbox"

'iisexpress.exe' (CLR v4.0.30319: Domain 4): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll'. Symbols loaded.

'iisexpress.exe' (CLR v4.0.30319: MySandbox): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_64\System.Web\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Web.dll'. Symbols loaded.

Why does System.Web.dll needs to be loaded to new AppDomain ?

2

2 Answers

1
votes

Passing null for securityInfo uses the evidence of the currently executing AppDomain.

AppDomain.CreateDomain:

securityInfo

Type: System.Security.Policy.Evidence

Evidence that establishes the identity of the code that runs in the application domain. Pass null to use the evidence of the current application domain.

It's likely that the System.Web.dll assembly needs to be loaded to inspect its evidence.

1
votes

It turned out that because I'm creating an AppDomain inside an existing ASP.NET-owned AppDomain. ASP.NET installs its own AppDomainManager into the parent AppDomain, and this is automatically propagated down to child AppDomains unless explicitly overridden by the caller like the following

AppDomainSetup appDomainSetup = new AppDomainSetup
{
    ApplicationBase = applicationBasePath,
    DisallowCodeDownload = true,
    DisallowBindingRedirects = true,
    DisallowPublisherPolicy = true,
    LoaderOptimization = LoaderOptimization.MultiDomainHost,
    AppDomainManagerAssembly = "", // overridden by caller
    AppDomainManagerType = "" // overridden by caller
};