All About Assert Part III: Dispelling the Myths

So far we've seen What Assert Actually Does, and What Assert Is Good For, now its time to examine some popular misconceptions about the Assert stack modifier.

Myth #1: Assert changes an assembly's permission grant

Assert is a stack walk modifier.  It doesn't modify the permission grant that any assembly has, rather it prevents the stack walk for a permission demand from continuing up the call stack.  Assert is effective because it stops a permission demand from ever reaching assemblies without the given permission.

Myth #2: Assert is just a perf optimization

Assert should never be used as a perf optimization.  Oftentimes, in an attempt to speed up the security system, people think of using Assert to stop the call stack walk.   Doing this completely circumvents the CAS system, and will more than likely lead to a security hole down the line.  It's very unlikely that if your application is having performance problems that stopping a security stack walk early on will solve them, you should instead measure and measure again, then fix the areas that are actually causing the problem.

Myth #3: You don't need the permissions that you're Asserting in order to effectively Assert them

This one is pretty easy to get confused about because of the observed behavior.  When you Assert some permissions, the code doing the Assert needs to be granted the following two things:

  1. SecurityPermission with SecurityPermissionFlag.Assertion set.  If this is not true, calling Assert will result in a SecurityException.
  2. The permissions being asserted.  If this is not true, there's no observable runtime behavior difference (causing the confusion that leads to this myth).  The call to Assert will return as if the assertion were set, however when a subsequent demand occurs, the Assert will not stop the stack walk.

Myth #4: Assert will last for the lifetime of the process

Since Assert is a stack walk modifier, it is only in effect while the method that called Assert is still on the call stack.  Once this method returns and its frame is popped, the Assert is no longer in effect.

Myth #5: Since Assert goes away at the end of the calling method, I never need to call RevertAssert

While this is technically not a myth, and is true, good coding practice is to always Assert immediately before calling whatever method will result in the permission demand, and call RevertAssert as soon as you don't need the elevated permissions any more.  This limits the window of time that malicious code could use to take advantage of the stack walk modifier.

Myth #6: Assert stops all stack walks from proceeding further up the call stack

This is probably the most common misconception I see about Assert.  Asserting a set of permissions will only prevent a stack walk for those permissions from going further up the call stack.  For instance, if I assert FileIOPermission, and code I call demands RegistryPermission, that stack walk will blow right by my Assert and head further up the call stack.

A more interesting scenario occurs when a demand occurs that is a superset of the set of permissions that I've Asserted.  For instance, if I Assert FileIOPermission, but some code I call demands a permission set containing both FileIO and Registry permission.  Clearly stopping at my Assert would be the wrong behavior, but so would continuing past it.  In this case, when the CLR hits the Assert it will remove any permissions being Asserted from the permission set being demanded, and send the remaining permissions further on the stack walk.

Myth #7: Asserting a permission means that a demand for that permission will always succeed

I've already covered three cases where an Assert will not prevent a SecurityException (Myths #3, 4, and 6).  There are at least two other ways that this can happen.  Can you figure them out?  Post your guesses in the comments, and I'll provide answers in tomorrow's post.

Comments (7)
  1. Nicole Calinoiu says:

    Trivial case: the wrong (or incomplete) permission set is being asserted. In the more obscure department…

    1. Consider the following call chain:

    A (fully trusted) -> B (partially trusted) -> C (strongly named and fully trusted without APTCA)

    In this scenario, asserting full trust in A does not allow partially trusted B to bypass the full trust check for calling into C.

    2. Executable A instantiates type B1 from library B. Type B1 subclasses type C1 from library C. Type C1 implements an InheritanceDemand for a permission that library B does not possess. Even if executable A possesses the required permission, asserting it won’t allow B to pass the InheritanceDemand.

    I’m guessing that there are probably also some interesting circumstances around reflection, construction, and/or finalization, but I’ve finished my first coffee, so it’s time to start the day job…

  2. Shawn says:

    Good catch Nicole,

    Your examples are both specific cases of one situation I was thinking of. Specifically, any demand that does not cause a stack walk, and instead examines a grant set directly, will not be affected by Assert. #1 is a specific case of LinkDemand, and as you say in #2 InheritanceDemand also falls into this category.

    Now you’ve gotten the tricky one — there’s one more left. I wonder if anybody will get it before I post the answer later today.


  3. Nicole Calinoiu says:

    If that was the "tricky" one, I’m guessing that the other can’t be some obscure construction/finalization/reflection issue. The only fairly obvious thing left that I can see is an overriding denial on the stack, but perhaps that’s too obvious… <g>

  4. Shawn says:

    That’s the other one, another stack modifier that halts the stack walk before the Assert is even reached.


Comments are closed.

Skip to main content