19
votes

Scenario

Let's say we've the next code:

[SecuritySafeCritical]
public void SomeMethod()
{
    SomeCriticalClass critical = new SomeCriticalClass();

    Action someDelegate = () => 
    {
         critical.Do();
    }

    someDelegate();
}
  1. The SomeMethod signature has [SecuritySafeCritical] attribute.
  2. SomeCriticalClass is some class that has the [SecurityCritical] attribute either in the class or method Do method-level.
  3. We create an anonymous delegate auto-inferred to Action.

Problem

Calling critical.Do() causes a MethodAccessException FieldAccessException because a security transparent method (the anonymous method) is trying to access a security critical field (the critical SomeCriticalClass local variable).

Question

How you overcome this?

The easy way would be implementing an actual method marked with [SecuritySafeCritical] instead of using an anonymous delegate. But this moves us to pre-anonymous delegates and lambas era. I don't want this.

Other easy way would be just don't using security transparency. This isn't a solution.

Almost any available libraries both from Microsoft and open source community aren't designed with security transparency in mind. That is, any own custom code must interoperate with third-party libraries through [SecuritySafeCritical] or [SecurityCritical] methods/properties/delegates.

Actually I believe that security transparency is a good tool because it forces better and secure software designs, critical actions are very localized and the rest of the code works with minimal permissions.

1
In the specific case you've given, it's not clear that you need a lambda at all. You could just use Action someDelegate = critical.Do; couldn't you? - Jon Skeet
look at MSDN on this issue.. google the ERROR just as I did to get you to a good starting point on how to resolve this issue. msdn.microsoft.com/en-us/library/bb264475.aspx or msdn.microsoft.com/en-us/library/dd233102.aspx - MethodMan
@JonSkeet I'm my real-world scenario isn't that easy. Well, I can do it, but this wouldn't be in a single place, but in a lot of places. This is very bad because using security transparency prevents me from using modern and compact anonymous lambda delegates which saves a lot of code lines and makes the code smaller and yet readable. - Matías Fidemraizer
@MatíasFidemraizer: As you say at the bottom of your question - "critical actions are very localized" - if you don't have many places to do this, you can keep most of your code "modern", and just have more verbose code in a few places - Jon Skeet
@DJKRAZE Thanks for your contribution, but I really know how security transparency works. I'm asking this question because this is a real limitation of using it. - Matías Fidemraizer

1 Answers

18
votes

Sorry but I couldn't wait for other answerers... I got the solution!

By experimentation I could determine that marking with [SecuritySafeCritical] the class having the method that creates the anonymous method in its body, does the trick!!

In other words, or talking about the code:

[SecurityCritical]
public class SomeCriticalClass
{
      [SecurityCritical]
      public void Do()
      {
      }
}

[SecuritySafeCritical]
public sealed class SomeClass
{
    [SecuritySafeCritical]
    public void SomeMethod()
    {
          SomeCriticalClass critical = new SomeCriticalClass()

          // No more FieldAccessException!
          Action action = () => critical.Do();         
    }
}

I want to make some clarifications:

  • Marking the class SomeClass with [SecuritySafeCritical] doesn't mean that all declared methods will be [SecuritySafeCritical] by default. It means that the class can be used by partially-trusted callers. You still need to mark with [SecuritySafeCritical] attribute those methods, properties or fields that can be accessed by partially-trusted callers.

  • It seems that [SecuritySafeCritical] at class-level makes local variables and anonymous methods (maybe anonymous objects too!) security safe critical.

Yes! I hope both my question and my own answer will be useful for everyone, because I believe that the situation described in my question can happen often!