Inheritance Demands for Interfaces

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.