CA2116: APTCA methods should only call APTCA methods

Item Value
RuleId CA2116
Category Microsoft.Security
Breaking change Breaking

Cause

A method in an assembly with the System.Security.AllowPartiallyTrustedCallersAttribute attribute calls a method in an assembly that does not have the attribute.

Note

This rule has been deprecated. For more information, see Deprecated rules.

Rule description

By default, public or protected methods in assemblies with strong names are implicitly protected by a Link Demands for full trust; only fully trusted callers can access a strong-named assembly. Strong-named assemblies marked with the AllowPartiallyTrustedCallersAttribute (APTCA) attribute do not have this protection. The attribute disables the link demand, making the assembly accessible to callers that do not have full trust, such as code executing from an intranet or the Internet.

When the APTCA attribute is present on a fully trusted assembly, and the assembly executes code in another assembly that does not allow partially trusted callers, a security exploit is possible. If two methods M1 and M2 meet the following conditions, malicious callers can use the method M1 to bypass the implicit full trust link demand that protects M2:

  • M1 is a public method declared in a fully trusted assembly that has the APTCA attribute.

  • M1 calls a method M2 outside M1's assembly.

  • M2's assembly does not have the APTCA attribute and, therefore, should not be executed by or on behalf of callers that are partially trusted.

A partially trusted caller X can call method M1, causing M1 to call M2. Because M2 does not have the APTCA attribute, its immediate caller (M1) must satisfy a link demand for full trust; M1 has full trust and therefore satisfies this check. The security risk is because X does not participate in satisfying the link demand that protects M2 from untrusted callers. Therefore, methods with the APTCA attribute must not call methods that do not have the attribute.

How to fix violations

If the APTCA attribute is required, use a demand to protect the method that calls into the full trust assembly. The exact permissions you demand will depend on the functionality exposed by your method. If it is possible, protect the method with a demand for full trust to ensure that the underlying functionality is not exposed to partially trusted callers. If this is not possible, select a set of permissions that effectively protects the exposed functionality.

When to suppress warnings

To safely suppress a warning from this rule, you must ensure that the functionality exposed by your method does not directly or indirectly allow callers to access sensitive information, operations, or resources that can be used in a destructive manner.

Example 1

The following example uses two assemblies and a test application to illustrate the security vulnerability detected by this rule. The first assembly does not have the APTCA attribute and should not be accessible to partially trusted callers (represented by M2 in the previous discussion).

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

// This code is compiled into a strong-named
// assembly that requires full trust and does 
// not allow partially trusted callers. 

namespace AptcaTestLibrary
{
   public class ClassRequiringFullTrust
   {
      public static void DoWork()
      {
        Console.WriteLine("ClassRequiringFullTrust.DoWork was called.");
      }
   }
}

Example 2

The second assembly is fully trusted and allows partially trusted callers (represented by M1 in the previous discussion).

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

// This assembly executes with full trust and 
// allows partially trusted callers. 

[assembly:AllowPartiallyTrustedCallers]  

namespace AptcaTestLibrary
{
   public class AccessAClassRequiringFullTrust
   {
      public static void Access()
      {    
         // This security check fails if the caller 
         // does not have full trust. 
         NamedPermissionSet pset= new NamedPermissionSet("FullTrust");

         // This try-catch block shows the caller's permissions.
         // Correct code would either not catch the exception,
         // or would rethrow it.
         try 
         {
            pset.Demand();
         }
         catch (SecurityException e)
         {
            Console.WriteLine("Demand for full trust:{0}", e.Message);
         }
         // Call the type that requires full trust.
         // Violates rule AptcaMethodsShouldOnlyCallAptcaMethods.
         ClassRequiringFullTrust.DoWork();
     }
   }
}

Example 3

The test application (represented by X in the previous discussion) is partially trusted.

using System;
using AptcaTestLibrary;

// If this test is run from the local computer, it gets full trust by default.
// Remove full trust.
[assembly:System.Security.Permissions.PermissionSetAttribute(
   System.Security.Permissions.SecurityAction.RequestRefuse, Name="FullTrust")]

namespace TestSecLibrary
{
   class TestApctaMethodRule
   {
      public static void Main()
      {
          // Indirectly calls DoWork in the full-trust class.
          ClassRequiringFullTrust testClass = new ClassRequiringFullTrust();
          testClass.Access();
      }
   }
}

This example produces the following output:

Demand for full trust:Request failed.
ClassRequiringFullTrust.DoWork was called.

See also