Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reflection not restricted even if it's not in grant set

I'm currently trying to create a very very simple sandbox.

Some class A has a method Execute which is invoked in another AppDomain than the caller.

Problem is I've execution permission only and reflection is possible anyway.

This is the code sample:

[Serializable]
public class A : MarshalByRefObject
{
    public void Execute()
    {
        typeof(A).GetConstructor(Type.EmptyTypes).Invoke(null); // Fine - Why?
        typeof(B).GetConstructor(Type.EmptyTypes).Invoke(null); // Fine - Why?
    }
}

public class B
{

}

class Program
{
    static void Main(string[] args)
    {
        PermissionSet set = new PermissionSet(PermissionState.None);

        SecurityPermission security = new SecurityPermission(SecurityPermissionFlag.Execution);
        set.AddPermission(security);

        Evidence evidence = new Evidence();
        AppDomainSetup setup = new AppDomainSetup();
        setup.ApplicationBase = "C:";

        AppDomain domain = AppDomain.CreateDomain
        (
            "hello",
            evidence,
            setup,
            set
        );

        A a = (A)domain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(A).FullName);
        a.Execute();
    }
}

UPDATE

Great! Finally I did it.

Thanks to your advices I've revised my code and I'd like to share it with you, since I had a hard time understanding how to don't use CAS but use same kind of permissions in the new .NET 4.x and above security model, and the way of sandboxing using an AppDomain. That's it:

using System;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using System.Security.Policy;

namespace ConsoleApplication1
{
    [Serializable]
    public class A : MarshalByRefObject
    {
        public void Execute()
        {
        B b = new B();

        // BOMB! ERROR! Security demand: reflection forbidden!
        b.GetType()
                .GetMethod("ExecuteInB", BindingFlags.Instance | BindingFlags.NonPublic)
                    .Invoke(b, null);
        }
    }

    public class B
    {
        private void ExecuteInB()
        {

        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            PermissionSet set = new PermissionSet(PermissionState.None);

            SecurityPermission security = new SecurityPermission(PermissionState.None);
            security.Flags = SecurityPermissionFlag.Execution;
            set.AddPermission(security);

            Evidence evidence = new Evidence();
            AppDomainSetup setup = new AppDomainSetup();
            setup.ApplicationBase = "C:";

            AppDomain domain = AppDomain.CreateDomain
            (
                "hola",
                evidence,
                setup,
                set
            );

            A a = (A)domain.CreateInstanceAndUnwrap("ConsoleApplication1", "ConsoleApplication1.A");
            a.Execute();
        }
    }
}
like image 983
Matías Fidemraizer Avatar asked Feb 09 '12 19:02

Matías Fidemraizer


2 Answers

Reflection permission is demanded when invoking an inaccessible member. A and B are public types with public constructors, and so are accessible. You could invoke those constructors without reflection, so there is no demand when you attempt to do so with reflection.

Moreover, using reflection for discovery is always legal; you can interrogate an object and ask it for a list of its private members, even without reflection permission being granted. It is only when you attempt to cause an invocation of the private member that the permission is demanded.

like image 111
Eric Lippert Avatar answered Sep 21 '22 00:09

Eric Lippert


From MSDN Library: ReflectionPermission controls access to non-public types and members through the System.Reflection APIs. Without ReflectionPermission, code can use reflection to access only the public members of objects.

like image 40
Michael Liu Avatar answered Sep 21 '22 00:09

Michael Liu