Inheritance Demands for Interfaces

Inheritance Demands for Interfaces

  • Comments 11

I'm cheating here by re-posting an e-mail I sent the other day... but hey, you don't expect me to come up with new content for this blog do you? :-)

Here is a deliberately contrived example of why you might need to protect interfaces with inheritance demands.

Say I have declared an interface, IWhichFileShouldIDelete, that has a single property string FileName that returns the name of a file to delete.

I also have a fully-trusted object, FileDeleter, which has a FileToDelete property and a DeleteFile mehod. The FileToDelete property takes an IWhichFileShouldIDelete object that is then queried in the DeleteFile method. (I already said this was contrived, right? :-) ).

The problem with this design is that the way in which the interface / object interact allows partially-trusted code to delete sensitive files. This is because the actual implementation of the FileName property doesn't require any special permissions (it just returns a string), and when the DeleteFile method is called there is no code from the IWhichFileShouldIDelete object on the stack, so any stack walks for FileIOPermission will succeed. This is bad because now partially-trusted code can cause random files to be deleted.

As an example, you might have code like this:

 

  // Inside fully-trusted code...

 

  IWhichFileShouldIDelete file = new GetTheFileName(); // See below

  FileDelete deleter = new FileDeleter()

 

  // Here is where the design falls apart...

  deleter.FileToDelete = file;

 

  // Note the call-stack will be 100% FT code at this point

  deleter.DeleteFile(); // Deletes c:\boot.ini -- Ooops!

 

  // ----------

  // Assembly boundary

  // ----------

 

  // Inside partially-trusted code...

 

  class GetTheFileName : IWhichFileShouldIDelete

  {

    public string FileName { get { return @"c:\boot.ini"; } }

  }

In this scenario, the IWhichFileShouldIDelete interface should only be implemented by fully-trusted code, because only fully-trusted code should be able to say which files are deleted. To ensure that only fully-trusted code can implement IWhichFileShouldIDelete, you have to put an inheritance demand on the interface itself for unrestricted permissions (or maybe just unrestricted File I/O). This is necessary because the CLR's security system is based around code (stack walks), not information (data flow analysis).

A really cool (but most likely completely impractical) thing to add to the CLR would be a "forward" demand -- "Make sure the code that I am about to call has such-and-such a permission" -- to complement the current "Make sure the code that called me has such-and-such a permission" we get from normal demands.

For now, the best we can do is to make sure bad people can't implement methods that they shouldn't be allowed to, and we can accomplish that with inheritance demands.

  • slap!
  • So why not protect the System.Security.Principal.IIdentity and IPrincipal interfaces with inheritance demands for SecurityPermission\ControlPrincipal? I can think of a few arguments against it (mostly centred around low-privilege ASP.NET apps), but none of them are particularly satisfactory.
  • Good question, but since anyone can create a GenericIdentity or GenericPrincipal object, what would be the point?

    You have to "trust" your authentication provider... IIdentity objects aren't just things you would randomly accept from anywhere.

    (The following JScript program will run from the intranet zone):

    import System.Security.Principal

    function GetPrincipal() : IPrincipal
    {
    var gi : GenericIdentity = new GenericIdentity("Bob", "DodgyBros. Auth 1.0")
    var gp : GenericPrincipal = new GenericPrincipal(gi, ["Janitors", "Aliens"])
    return gp
    }

    function Test()
    {
    var ip : IPrincipal = GetPrincipal()
    print("Is he an alien? " + ip.IsInRole("Aliens"))
    print("How was he authenticated? " + ip.Identity.AuthenticationType)
    }

    Test()
  • If the interfaces did specify inheritance demands for SecurityPermission\ControlPrincipal, it would seem reasonable for all types that implement the interfaces to specify at least a link demand for the same permission on members that contribute to defining the implementation data. This is also true of your IWhichFileShouldIDelete example, where the permission verification is essentially lost if the interface implementer allows a caller to provide defining data without verifying its right to do so.
  • Yes, or (even better) a full demand.

    The assumption (oops! :-) ) in my post was that the "good" people who legitimately implement these interfaces will adequately protect themselves from harm.

    You would then also want the interface definition itself to have LinkDemands on any methods that could munge the state in a bad way, and then require the implementations to either also have LinkDemands or have strong demands.

    Luckily IWhichFileBalbla has no such methods, and (in general) it might be hard for the interface designer to tell which methods are "dangerous" and which aren't, and therefore will have to rely on the implementations to do full demands.
  • In light of this, shouldn't FxCop include a rule for verifying that link/full demands corresponding to inheritance demands are present? There's already one for the opposite scenario (TypeLinkDemandsRequireInheritanceDemands), and I can't really think of any reason that this should be any less worthy of verification. Of course, identifying where the demands are actually required may be tricky, but that's the developer's job, not the verifier's.
  • That's a good suggestion, but one of the problems with tools like FXCop is that if you start complaining about every single thing that might be bad in some possible universe, the warnings quickly get ignored / turned off and you lose any benefit you might have had. False positives are a HUGE problem with both static and dynamic code analysis tools.

    Since a tool like FXCop can't tell which interface methods *might* mutate the object in "interesting" ways in *some* implementations and which ones don't, the warning would have to apply to ALL members, and that's just a pain.
  • I don't think it needs to be quite that ugly. For starters, we're dealing only with classes that implement interfaces or inherit from base classes with inheritance demands at the type level.* The simplest (and most often safest) way to propagate the permission verification is to add a corresponding full demand at the class level in the subtype, and this is probably all that the rule would really need to verify. Implementers who believe it's safe to apply the permission verification only at the level of critical members can be excluded from the rule check, but at least those folks who've missed the boat entirely will see a red flag.

    Even if you assume that most implementers would choose to verify only at the member level (which I think is probably incorrect since it would be more work for the designer/developer), it still seems unlikely to me that the rule would cause undue pain. After all, inheritance demands are quite rare, so the rule isn't likely to be applied very often. (One might argue that inheritance demands are perhaps too rare, but that's another rule entirely. <g>)

    The other side of the coin is that many developers will be highly unlikely to notice that the supertype or interface they are implementing even has an inheritance demand in the first place. If the subtype is destined to run with full trust, they may never notice. If it's destined to run without the required permission, they may not notice until rather late in the lifecycle. Why not provide a tool to flag the potential problem early?


    *While the same rule could also verify members with inheritance demands, the logic is much simpler unless one is concerned that the presence of an inheritance demand on any member may have repercussions for other members.
  • Good points (and I think it's pretty well known that I personally hate all types of LinkDemands because of their obscurity).

    I'll send your suggestion to the FXCop team to see what they say.

  • They now have your suggestion -- thanks Nicole!
Page 1 of 1 (11 items)