The demand was for: <PermissionSet class="System.Security.PermissionSet" version="1" Unrestricted="true"/>

StackOverflow https://stackoverflow.com/questions/20957089

Question

I'm getting the System.Security.SecurityException The demand was for: <PermissionSet class="System.Security.PermissionSet" version="1" Unrestricted="true"/> when attempting to create an AppDomain with restricted permissions defined as follows:

var permissionSet = new PermissionSet(PermissionState.None);
    permissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, System.Reflection.Assembly.GetExecutingAssembly().Location));
    permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
    permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.SerializationFormatter));

This error message suggests to me that it will accept no less than an unrestricted/full trust environment, but I don't understand why that would be demanded or how to fix it.

I create only one instance of Stub into the new restricted AppDomain:

public interface IHostStub // Implemented by a MarshalByRefObject object in the primary AppDomain
{
    void Ping();
    void SayTime(DateTimeOffset time);
}

// In the restricted AppDomain
class Stub : MarshalByRefObject
{
    public event EventHandler OnQuit;

    public void RequestTime(IHostStub host)
    {    
        host.SayTime(DateTimeOffset.Now);
    }

    public void Quit(IHostStub host)
    {
        if (this.OnQuit != null) 
            this.OnQuit(this, new EventArgs());
    }
}

Can you please explain this error message to me? Perhaps I misunderstand what Unrestricted means. But setting it to Unrestricted seems to give the app domain free reign (as I expect it would) regardless of any permissions I add or don't add to it.

Thanks!

====

In response to @Nicole and to add some discoveries as I work through this, here are two code samples below. This is a tricky scenario - sandboxing plugins - that would take too much code to show all of. The first code sample demonstrates the exception. It has an obvious fix, but it doesn't take into account the whole scenario.

class Program
{
    static void Main(string[] args)
    {
        var currentAssembly = System.Reflection.Assembly.GetExecutingAssembly();

        var permissionSet = new PermissionSet(PermissionState.None);
        permissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, currentAssembly.Location));
        permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
        permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.SerializationFormatter));
        permissionSet.AddPermission(new ReflectionPermission(PermissionState.Unrestricted));

        var appDomain = AppDomain.CreateDomain(
            "Sandboxed",
            null,
            new AppDomainSetup
            {
                ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase
            },
            permissionSet,
            Assembly.GetExecutingAssembly().Evidence.GetHostEvidence<StrongName>());

        try
        {
            var stub = (Stub)appDomain.CreateInstanceFromAndUnwrap(
                currentAssembly.Location,
                typeof(Stub).FullName);
        }
        catch (SecurityException ex)
        {
            Console.WriteLine(ex);
            throw;
        }
    }
}

// In the restricted AppDomain
class Stub : MarshalByRefObject
{
}

In that example, the ApplicationBase is the same as the primary AppDomain. Also, the assembly itself is listed as a FullTrust assembly for the AppDomain. The trivial fix is to remove that full-trust param.

In this next example, for protection against plugins loading host's assemblies, the ApplicationBase is set to a random path that doesn't even need to exist (works fine with PermissionState.Unrestricted, same error if the directory DOES exist). AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve; requires full trust AFAIK so I have to list the assembly with full-trust (which I believe should override any restrictions set on the AppDomain for that trusted assembly but not the others it may load) - this assembly can just be the "loader" and the plugins would be part of another assembly for which the restricted permissions should be enforced. I must custom AssemblyResolve because the directory doesn't exist (or is empty) and because I want to be in control of loading additional assemblies (say, from byte[]s).

class Program
{
    static void Main(string[] args)
    {
        var currentAssembly = System.Reflection.Assembly.GetExecutingAssembly();

        var permissionSet = new PermissionSet(PermissionState.None);
        permissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, currentAssembly.Location));
        permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
        permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.SerializationFormatter));
        permissionSet.AddPermission(new ReflectionPermission(PermissionState.Unrestricted));

        string path;
        do
        {
            path = Path.GetTempPath() + Path.GetFileNameWithoutExtension(Path.GetRandomFileName());
        } while (Directory.Exists(path));

        var appDomain = AppDomain.CreateDomain(
            "Sandboxed",
            null,
            new AppDomainSetup
            {
                ApplicationBase = path
            },
            permissionSet,
            Assembly.GetExecutingAssembly().Evidence.GetHostEvidence<StrongName>());

        try
        {
            var stub = (Stub)appDomain.CreateInstanceFromAndUnwrap(
                currentAssembly.Location,
                typeof(Stub).FullName);
        }
        catch (SecurityException ex)
        {
            Console.WriteLine(ex);
            throw;
        }
    }
}

class Stub : MarshalByRefObject
{
    static Stub()
    {
        AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve;
    }

    public static Assembly AssemblyResolve(object sender, ResolveEventArgs e)
    {
        if (e.Name == Assembly.GetExecutingAssembly().FullName)
            return Assembly.GetExecutingAssembly();
        else
            Console.WriteLine("Unable to load {0}", e.Name);

        return null;
    }
}
Was it helpful?

Solution

Try creating the stub handle via Activator.CreateInstanceFrom instead of AppDomain.CreateInstanceFromAndUnwrap. The permission verifications differ, and using the Activator method should allow you to also avoid adding the extra permissions (besides SecurityPermission\Execution) to your sandboxed app domain. e.g.:

var currentAssembly = System.Reflection.Assembly.GetExecutingAssembly();

var permissionSet = new PermissionSet(PermissionState.None);
permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));

var appDomain = AppDomain.CreateDomain(
    "Sandboxed",
    null,
    new AppDomainSetup { ApplicationBase = CreateFakePath() },
    permissionSet,
    currentAssembly.Evidence.GetHostEvidence<StrongName>());

var stub = (Stub)Activator.CreateInstanceFrom(appDomain, currentAssembly.Location, typeof(Stub).FullName).Unwrap();

var hostStub = new HostStub();
stub.RequestTime(hostStub);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top