Removing Permissions From FullTrust


Executing the following code:

PermissionSet ps = new PermissionSet(PermissionState.Unrestricted);
Console.WriteLine(“Before Removing Permissions:”);
Console.WriteLine(ps.ToXml().ToString());

ps.RemovePermission(typeof(RegistryPermission));
Console.WriteLine(“After Removing Permissions:”);
Console.WriteLine(ps.ToXml().ToString());

May lead to surprising results.  The output is:

Before Removing Permissions:
<PermissionSet class=”System.Security.PermissionSet”
version=”1″
Unrestricted=”true”/>

After Removing Permissions:
<PermissionSet class=”System.Security.PermissionSet”
version=”1″
Unrestricted=”true”/>

It appears that the RemovePermission call didn’t actually remove the registry permission.  That can’t be right can it?

Lets take a step back and look at what’s actually going on here.  First we create an unrestricted permission set, and write that out to the console.  However, notice how FullTrust is represented as a permission set with the unrestricted flag set to true.  The CLR uses this representation rather than have the FullTrust set contain all of the permissions in their unrestricted state for several reasons

  1. Upradability — for instance in Whidbey, we’ve introduced several permissions, such as DataProtectionPermission.  If the FullTrust set contained every permission in their unrestricted state, a FullTrust set on Everett would not be FullTrust on Whidbey.
  2. Extensibility — since we allow custom permissions to be written, we run into a problem with custom permissions.  Since we don’t know every custom permission available, it would be impossible to create a FullTrust set that contained them in their unrestricted state.

Because of those factors, we decided to create a special FullTrust flag that would mean FullTrust regardless of the version of the runtime in use, or which special permissions are installed on the machine.  Internally, this flag also lets us make certain optimizations inside the CLR when evaluating demands.

So now that we’ve established that the FullTrust set doesn’t actually contain any permissions per say, it becomes more clear why the call to RemovePermission did not do anything.  The FullTrust set doesn’t actually contain a ReflectionPermission, so when we call RemovePermission asking it to take away the ReflectionPermission there’s nothing to do.  This can be easily verified by examining the return value from the RemovePermission call:

IPermission removed = ps.RemovePermission(typeof(RegistryPermission));
Console.WriteLine(“After Removing Permissions:”);
Console.WriteLine(ps.ToXml().ToString());
if(removed == null)
    Console.WriteLine(“No permission removed”);
else
    Console.WriteLine(removed.ToXml().ToString());

Running this shows:

After Removing Permissions:
<PermissionSet class=”System.Security.PermissionSet”
version=”1″
Unrestricted=”true”/>

No permission removed

Which means that no permission was actually removed.  Hopefully this behavior, which at first seems pretty counter-intuitive, makes a little more sense when you look at it from the inside out.

Comments (6)

  1. It seems like what we need to do the set arithmetic implied by the example is:

    PermissionSet ps = new PermissionSet(PermissionState.AllPermissions);

    This would give full access using fully populated PermissionSet, which you could then remove things from.

  2. Andrew Law says:

    Thanks for explaining this.

    So what should we do if we have full permission, and we want to remove certain ones?

    It seems that we need to start from scratch, create a new "blank" permission, and then add the specific permission sets that we need.

  3. Shawn says:

    Close David … we’d have to call it something closer to:

    PermissionSet ps = new PermissionSet(PermissionState.AllPermissionsThatWeCurrentlyKnowAbout);

    :-) And that just gets difficult to type :-)

    -Shawn

  4. Shawn says:

    Andrew — that’s one way about it. Another way would be to start with the Everything permission set, (which is everything in the framework with the exception of SkipVerification), and then add back SkipVerification. Finally subtract out the permissions you need. Realizing of course that this will give you only the permissions available that shipped with the current verison of the framework. You’re suceptable to upgrade and extensibility problems mentioned above.

    -Shawn

  5. Bob Pesner says:

    Thanks for explaining why some code I have runs fine when granted FullTrust but throws a SecurityException when granted Everything (including when modified to include Security->Skip verification.

    I now need to determine what permission is being denied. I’m using version 1.1. SecurityException PermissionState is null and PermissionType is undefined. Is there any way for me to determine what permission is being denied? Or to determine what is included in FullTrust that’s not included in Everything?

    Thanks.

  6. shawnfa says:

    You’ll have to debug to see where the exception is coming from.  Maybe the API you’re calling is explicitly demanding FullTrust (like the Process class for instance).

    -Shawn