Maintaining LinkDemands across inheritance boundaries

As you already know, LinkDemands can be dangerous. But if you do use them, you need to know how to use them correctly. One problem that happens is when people add (or fail to maintain) a LinkDemand to a derived class when one did (or did not) exist on the base class.

Let's say you have the following code:

    public class BaseClass

    {

        [SecurityPermission(SecurityAction.LinkDemand, Unrestricted=true)]

        public void DoSomething()

        {

// Do something here

        }

    }

    public class DerivedClass : BaseClass

    {

        public override void DoSomething()

        {

// Do something else here...

 

// Now call base class' implementation

base.DoSomething();

        }

    }

Hopefully it is pretty clear that this represents a security risk: BaseClass has protected its method with a LinkDemand so that untrusted code cannot call it. Unfortunately, DerivedClass goes ahead and calls the method as part of its implementation of DoSomething, and in doing so will likely satisfy the LinkDemand. To fix this problem the author of DerivedClass needs to add the LinkDemand attribute to DerivedClass.DoSomething.

That one was easy. But what's wrong with this?

    public class BaseClass

    {

        public void DoSomething()

        {

// Do something safe here

        }

    }

    public class DerivedClass : BaseClass

    {

        [SecurityPermission(SecurityAction.LinkDemand, Unrestricted=true)]

        public override void DoSomething()

        {

// Do something dangerous here

        }

    }

Surely it's OK since the DerivedClass is being more secure than the BaseClass?

The problem here is that LinkDemand checks are done as the calling method is being JITted. If you have a method in an untrusted piece of code that accepts a parameter of type BaseClass then it will be JITted without any problems since no LinkDemand will be done. The method can then be passed a DerivedClass instance (which wants the check to occur) but the check will never occur.

Taking advantage of this is easy:

    void DoSomethingHelper()

    {

        CallDoSomething(new DerivedClass());

    }

 

    void CallDoSomething(BaseClass bc)

    {

        bc.DoSomething();

    }

In this case, when the JITter compiles CallDoSomething all it knows is that you are calling BaseClass.DoSomething. It doesn't know that you are later going to pass in a DerivedClass instance as the parameter. In fact, in a more complicated scenario the JITter may not even know that DerivedClass exists -- it could be in an assembly that is dynamically loaded at some future point in time.

Obviously if you want to add a LinkDemand to your DerivedClass but you are not in control of BaseClass (and so can't add the LinkDemand to it) you are in a bit of a bind. Two reasonable approaches:

1) Create a new method! If the base class' implementation of DoSomething was safe, you're probably abusing it by making the override dangerous

2) Do a full demand; it will always work, and it's probably what you want anyway

And don't call me Shirley.