[Mono-devel-list] Flag-ing security actions

Sebastien Pouliot sebastien at ximian.com
Tue Nov 16 11:57:53 EST 2004


Assemblies, classes and methods can have security informations. Those
declarative security attributes are stored in the metadata. This is also
where the security action is stored.

It's easy to know if a class/method have such informations (the
HasSecurity attributes) however we need to look into the metadata to
find out the actions.

As different actions are executed at different times (load time, JIT
time or run time) and in some case can be executed many times the
metadata lookup can be costly (as a good proportions of the lookups will
be negative - i.e. no action is required at present time).

Here's are some examples. All examples are for methods but the same also
applies for classes (but assemblies are different and not a problem).



Example #1: Method "X" as a LinkDemand for a specific strongname.
----------

So what happens...

At load time, the class loader will detect that the method "X" has
security and will search the metadata for [NonCas]
InheritanceDemand[Choice] only to find out it's a LinkDemand.

	* Note: This happens once for the method "X".

At JIT time, the JIT will check all methods calling "X" (as "X" has
security). The metadata is again searched for [NonCas]LinkDemand
[Choice]. As this is a LinkDemand it will need to be evaluated by the
SecurityManager.

	* Note: This happens for every method calling "X".

At JIT time, the JIT *may* also need to generate code for method "X" (as
"X" has security). The metadata is searched for [NonCas]Demand[Choice]
but nothing is found (if it was found then some code would be generated
to start a stack walk before executing the method code).

	* Note: This happens once when JITting method "X".

At run time stack walks will occur (when something demands it). Each
method on the stack will be queried for security. Method "X" has
security so the metadata will be searched looking for stack modifiers
(i.e. Assert, Deny and PermitOnly) but only a LinkDemand will be found.

        * Note: This happens for every stackwalk where "X" is in the
        stack.


Example #2: Method "Y" has a Deny for UnmanagedCode.
----------

At load time, the class loader will "loose" time (once).

At JIT time, the JIT will "loose" time for every method calling
"Y" (possibly multiple times or never);

At JIT time, the JIT will "loose" time because no code has to be
generated for a Deny (once);

At run time, stack walks will find (and apply) the Deny (no lost);


Example #3: Method "Z" has an InheritanceDemand for a strongname.
----------

At load time, the class loader will find (and apply) the
InheritanceDemand (no lost);

At JIT time, the JIT will "loose" time for every method calling
"Z" (possibly multiple times or never);

At JIT time, the JIT will "loose" time because no code has to be
generated for an InheritanceDemand (once);

At runtime, stack walks will also "loose" time when "Z" is on the stack
(possibly multiple times or never).



Solutions
---------

* HasSecurity

        Both class and methods have attributes so it's possible to know
        if they have (or not) security (e.g. MethodAttributes.
        HasSecurity). This is a quick way to see if security is present
        but doesn't help to know when (load/jit/run time) the security
        is applicable. In fact the previous examples all used
        "HasSecurity".

* Cache

        The declarative security attributes in the metadata don't change
        so it's possible to cache them. However the absence of a
        permission set in the cache doesn't say if it (a) wasn't yet
        loaded from the metadata or (b) doesn't apply at this
        (load/jit/run) time. Aggressively loading all the permission
        sets (with actions) in the cache (e.g. the first time we check a
        method - at load time) would not help performance (and memory
        consumption).

* Flags

        HasSecurity lacks details. Having a bitmask for security actions
        (in both methods and class) would be a lot more helpful.
        
There are, with CLR 2.0, 18 different security actions (including some
I've never seen in real life - but that doesn't make them inexistent).
Easiest way would be to include a bit for each of them (which would be
useful in later steps).

Now the MonoMethod structure already have (too) much stuff (and the
number of actions can only grow in future versions). Paolo thinks I can
squeeze 2 bits in it.

There are also other structures, Paolo suggested MonoCompile and
MonoJitInfo, but they exists after load time (so we miss the first
case).

So I'm trying to reduce... There are 4 (well for class/method) times
when actions needs to be categorized:

* load time;
	- check for [NonCas]InheritanceDemand[Choice] actions;
* JIT time (2);
	- check for [NonCas]LinkDemand[Choice] actions;
	- generate code for [NonCas]Demand[Choice] actions;
* Run time
	- check for stack modifiers: Assert, Deny and PermitOnly

Still too much but...

Load time is less problematic because
- it happens only once;
- it happens first and always (so it's great place to set the flags ;-)

JIT code generation also only happen once (well if the method gets
JITted) so doing a "full lookup" in the metadata wouldn't be "too bad".

So it could be squeezed into 2 bits like this:

HasSecurity and bit 0 -> [NonCas]LinkDemand[Choice]
HasSecurity and bit 1 -> Stack modifiers (Assert | Deny | PermitOnly)


Any other ideas ?
Thanks
-- 
Sebastien Pouliot  <sebastien at ximian.com>
blog: http://pages.infinit.net/ctech/poupou.html




More information about the Mono-devel-list mailing list