Home All Groups Group Topic Archive Search About

Sandboxing AppDomain

Author
17 Aug 2005 8:54 PM
krsgoss@gmail.com
I am trying to load an untrusted assembly within a separate AppDomain
so that I can restrict it's permissions.  I based my AppDomain setup
off some blog entries here:

http://blogs.msdn.com/shawnfa/archive/2004/11/02/251239.aspx
http://blogs.msdn.com/shawnfa/archive/2004/11/08/253971.aspx

The code to create the AppDomain is below.  I'm mimicing the internet
zone permission set in my test application for now.  I would like to
use a custom permission set so that I have fine-grained control over
the sandbox security.  If I call a method on the plugin implementation
which displays a message box, I get the following error:

System.Security.Policy.PolicyException: Required permissions cannot be
acquired.

If change the implementation below to instead initialize and use a
NamedPermissionSet with the "Internet" zone specified in the
constructor, the plugin works as expected.  I do not understand why the
same permissions being created manually fails vs. the named permission
set.

Any help is appreciated.

Thanks,

Kris


public AppDomain CreateAppDomain()
{
PolicyStatement emptyPolicy = new PolicyStatement(new
PermissionSet(PermissionState.None));
            UnionCodeGroup policyRoot = new UnionCodeGroup(new
AllMembershipCondition(), emptyPolicy);

            // now grant permissions explicitly for the sandbox
            PermissionSet permissionSet = new
PermissionSet(PermissionState.None);
            permissionSet.AddPermission(new
SecurityPermission(SecurityPermissionFlag.Execution));
            permissionSet.AddPermission(new
UIPermission(UIPermissionWindow.SafeTopLevelWindows,
UIPermissionClipboard.OwnClipboard));
            permissionSet.AddPermission(new
PrintingPermission(PrintingPermissionLevel.SafePrinting));
            permissionSet.AddPermission(new
FileDialogPermission(FileDialogPermissionAccess.Open));

            PolicyStatement permissions = new PolicyStatement(permissionSet);
            policyRoot.AddChild(new UnionCodeGroup(new AllMembershipCondition(),
permissions));

            // create a policy level for the policy tree
            PolicyLevel appDomainLevel = PolicyLevel.CreateAppDomainLevel();
            appDomainLevel.RootCodeGroup = policyRoot;

            // create the AppDomain which lives under this policy
            AppDomain result = AppDomain.CreateDomain("Plugin-Sandbox");
            result.SetAppDomainPolicy(appDomainLevel);
            return result;
}

Author
18 Aug 2005 1:28 PM
Nicole Calinoiu
Unfortunately, I can't seem to reproduce the problem.  Might you be able to
provide sample code for both the target method and its invocation?


<krsg***@gmail.com> wrote in message
Show quoteHide quote
news:1124312040.984766.142870@g44g2000cwa.googlegroups.com...
>I am trying to load an untrusted assembly within a separate AppDomain
> so that I can restrict it's permissions.  I based my AppDomain setup
> off some blog entries here:
>
> http://blogs.msdn.com/shawnfa/archive/2004/11/02/251239.aspx
> http://blogs.msdn.com/shawnfa/archive/2004/11/08/253971.aspx
>
> The code to create the AppDomain is below.  I'm mimicing the internet
> zone permission set in my test application for now.  I would like to
> use a custom permission set so that I have fine-grained control over
> the sandbox security.  If I call a method on the plugin implementation
> which displays a message box, I get the following error:
>
> System.Security.Policy.PolicyException: Required permissions cannot be
> acquired.
>
> If change the implementation below to instead initialize and use a
> NamedPermissionSet with the "Internet" zone specified in the
> constructor, the plugin works as expected.  I do not understand why the
> same permissions being created manually fails vs. the named permission
> set.
>
> Any help is appreciated.
>
> Thanks,
>
> Kris
>
>
> public AppDomain CreateAppDomain()
> {
> PolicyStatement emptyPolicy = new PolicyStatement(new
> PermissionSet(PermissionState.None));
> UnionCodeGroup policyRoot = new UnionCodeGroup(new
> AllMembershipCondition(), emptyPolicy);
>
> // now grant permissions explicitly for the sandbox
> PermissionSet permissionSet = new
> PermissionSet(PermissionState.None);
> permissionSet.AddPermission(new
> SecurityPermission(SecurityPermissionFlag.Execution));
> permissionSet.AddPermission(new
> UIPermission(UIPermissionWindow.SafeTopLevelWindows,
> UIPermissionClipboard.OwnClipboard));
> permissionSet.AddPermission(new
> PrintingPermission(PrintingPermissionLevel.SafePrinting));
> permissionSet.AddPermission(new
> FileDialogPermission(FileDialogPermissionAccess.Open));
>
> PolicyStatement permissions = new PolicyStatement(permissionSet);
> policyRoot.AddChild(new UnionCodeGroup(new AllMembershipCondition(),
> permissions));
>
> // create a policy level for the policy tree
> PolicyLevel appDomainLevel = PolicyLevel.CreateAppDomainLevel();
> appDomainLevel.RootCodeGroup = policyRoot;
>
> // create the AppDomain which lives under this policy
> AppDomain result = AppDomain.CreateDomain("Plugin-Sandbox");
> result.SetAppDomainPolicy(appDomainLevel);
> return result;
> }
>
Author
20 Aug 2005 6:41 PM
kris
Hi Nicole, here is a more comprehensive code sample:

First I have an IPlugin interface in a shared assemblyy with two simple
methods.

        public interface IPlugin
    {
        void DoSomething();
        void DoSomethingBad();
    }

In my concrete plugin assembly is the corresponding implementation:

    public class PluginImpl : MarshalByRefObject, IPlugin
    {
        public void DoSomething()
        {
            // this should be fine since its a msgbox
            MessageBox.Show("Hello from plugin: " +
AppDomain.CurrentDomain.FriendlyName);
        }

        public void DoSomethingBad()
        {
            // this should not be allowed
            SaveFileDialog dialog = new SaveFileDialog();
            dialog.ShowDialog();
        }
    }

In my plugin host EXE I create the sandboxed AppDomain instance and
load the plugin into it:

    class PluginHost
    {
        [STAThread]
        static void Main(string[] args)
        {
            try
            {
                AppDomain pluginDomain = CreateAppDomain();
                IPlugin plugin = (IPlugin)pluginDomain.CreateInstanceAndUnwrap(
                    "Spike.AppDomainHosting.Plugin",
"Spike.AppDomainHosting.Plugin.PluginImpl");

                // interact with the plugin
                plugin.DoSomething();

                // now tear down the appdomain
                AppDomain.Unload(pluginDomain);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
        }

        private static AppDomain CreateAppDomain()
        {
            // default all code to no permissions
            PolicyStatement emptyPolicy = new PolicyStatement(new
PermissionSet(PermissionState.None));
            UnionCodeGroup policyRoot = new UnionCodeGroup(new
AllMembershipCondition(), emptyPolicy);

            // now grant permissions explicitly for the sandbox
            PermissionSet permissionSet = new
PermissionSet(PermissionState.None);
            permissionSet.AddPermission(new
SecurityPermission(SecurityPermissionFlag.Execution));
            permissionSet.AddPermission(new
UIPermission(UIPermissionWindow.SafeTopLevelWindows,
UIPermissionClipboard.OwnClipboard));
            permissionSet.AddPermission(new
PrintingPermission(PrintingPermissionLevel.SafePrinting));
            permissionSet.AddPermission(new
FileDialogPermission(FileDialogPermissionAccess.Open));

            PolicyStatement permissions = new PolicyStatement(permissionSet);
            policyRoot.AddChild(new UnionCodeGroup(new AllMembershipCondition(),
permissions));

            // create a policy level for the policy tree
            PolicyLevel appDomainLevel = PolicyLevel.CreateAppDomainLevel();
            appDomainLevel.RootCodeGroup = policyRoot;

            // create the AppDomain which lives under this policy
            AppDomain result = AppDomain.CreateDomain("Plugin-Sandbox");
            result.SetAppDomainPolicy(appDomainLevel);
            return result;
        }
    }
}

When I call the PluginImpl.DoSomething() method which displays a
message box (and should be allowed based on the permissions I'm
assigning in PluginHost.CreateAppDomain method), I'm met with the
following exception:

System.Security.Policy.PolicyException: Required permissions cannot be
acquired.

Server stack trace:
   at Spike.AppDomainHosting.Plugin.PluginImpl.DoSomething()
   at
System.Runtime.Remoting.Messaging.StackBuilderSink.PrivateProcessMessage(MethodBase
mb, Object[] args, Object server, Int32 methodPtr, Boolean
fExecuteInContext, Object[]& outArgs)
   at
System.Runtime.Remoting.Messaging.StackBuilderSink.SyncProcessMessage(IMessage
msg, Int32 methodPtr, Boolean fExecuteInContext)

Exception rethrown at [0]:
   at
System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage
reqMsg, IMessage retMsg)
   at
System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData&
msgData, Int32 type)
   at Spike.AppDomainHosting.Shared.IPlugin.DoSomething()
   at Spike.AppDomainHosting.PluginHost.Main(String[] args) in
e:\dev\spike\spike.appdomainhosting\pluginhost.cs:line 33

If within CreateAppDomain, I substitute my created PermissionSet for a
NamedPermissionSet with the "Internet" name specified, the code works
(sort of.)  As I was writing this I just realized that even under the
NamedPermissionSet, the code is able to instantiate the SaveFileDialog,
which should be prohibited under the Internet level of trust.  :-(

Any help on sorting this out is really appreciated!

Thanks,

Kris
Author
22 Aug 2005 3:26 PM
Nicole Calinoiu
"kris" <krsg***@gmail.com> wrote in message
news:1124563307.946760.32560@g43g2000cwa.googlegroups.com...
> Hi Nicole, here is a more comprehensive code sample:
<snip>

Thanks, that really helped me with figuring out what you were doing.


> If within CreateAppDomain, I substitute my created PermissionSet for a
> NamedPermissionSet with the "Internet" name specified, the code works
> (sort of.)  As I was writing this I just realized that even under the
> NamedPermissionSet, the code is able to instantiate the SaveFileDialog,
> which should be prohibited under the Internet level of trust.  :-(

That's because creating a permission set from a name doesn't actually
populate the new permission set with the policy-set permissions for the
named permission set.  Instead, something like "new NamedPermissionSet("any
name")" generates an _unrestricted_ permission set (same as FullTrust).


> Any help on sorting this out is really appreciated!

Your underlying problem is that the target assembly doesn't have sufficient
permissions to deal with the remoting plumbing.  You might want to re-read
the parts of Shawn's blog postings that deal with the use of
MarshalByRefObject.  Here are some pointers:

1.  The MarshalByRefObject subtype that will be the remoting invocation
target should be in a fully trusted assembly that you will create (not the
in the plug-in implementation assembly).

2.  You should call the plug-in implementation from a copy of the assembly
described in #1 that has been loaded into the restricted app domain.

3.  The policy for the restricted app domain should restrict the permissions
of all assemblies other than the "conductor" assembly described in #1.

4.  Since the plug-in implementations will not be remoting targets (at least
with respect to the permissions restriction mechanism), there's no need for
them to subclass MarshalByRefObject.

Does that make a bit more sense?
Author
23 Aug 2005 6:35 AM
kris
Hi Nicole, this makes more sense (especially my confusion on the named
permission set), thanks for the response.  I've made some changes based
on your comments as well as rereading the MarshalByRefObject blog entry
here:

http://blogs.msdn.com/shawnfa/archive/2004/11/02/251239.aspx

I'm still encountering the PolicyException stating that required
permissions cannot be acquired.  Here's the steps I've taken:

-The concrete plugin implementation no longer derives from MBR, it only
implements the interface from the shared assembly.

- In the shared assembly, I now have a PluginFactory implementation
that derives from MBR, and loads a concrete plugin implementation given
an assembly path and type name.  Instead of returning the plugin
instance, which would mean loading of the concrete plugin type in the
host AppDomain, it wraps the IPlugin implementation in a PluginProxy
object, which derives from MBR.  This forwards all calls to the
concrete plugin and all within the context of the restricted AppDomain.
This is the now the conductor as you described it.

- I signed both the plugin host and shared assemblies.  In the
AppDomain setup code based on the blog posts, I assign a
StrongNameMembershipCondition for the shared assembly and grant it full
permissions.  This too is based on the post here:

http://blogs.msdn.com/shawnfa/archive/2004/10/26/248114.aspx

When attempting to call IPlugin.DoSomething() which displays a
MessageBox (allowable under the internet named permission) I am failing
with the security exception:

System.Security.Policy.PolicyException: Required permissions cannot be
acquired.

The AppDomain setup/initializiation is verbatim from the blog posts
cited, and this revised remoting model seems to match your comments as
well as the blog entries.  Since the plugin is now only a reference
within a "safe" MBR which I own in my shared/conductor assembly, the
remoting stack would seem to be out of the picture.  I'm still unclear
as to why this still fails. 

Thanks again!

Kris
Author
23 Aug 2005 12:22 PM
Nicole Calinoiu
Might you be able to provide a relevant code sample similar to the one from
your last message?  Looking at what your code is actually doing would be far
more efficient than attempting to repro by guessing at some of the pickier
details... <g>



Show quoteHide quote
"kris" <krsg***@gmail.com> wrote in message
news:1124778934.019889.32750@z14g2000cwz.googlegroups.com...
> Hi Nicole, this makes more sense (especially my confusion on the named
> permission set), thanks for the response.  I've made some changes based
> on your comments as well as rereading the MarshalByRefObject blog entry
> here:
>
> http://blogs.msdn.com/shawnfa/archive/2004/11/02/251239.aspx
>
> I'm still encountering the PolicyException stating that required
> permissions cannot be acquired.  Here's the steps I've taken:
>
> -The concrete plugin implementation no longer derives from MBR, it only
> implements the interface from the shared assembly.
>
> - In the shared assembly, I now have a PluginFactory implementation
> that derives from MBR, and loads a concrete plugin implementation given
> an assembly path and type name.  Instead of returning the plugin
> instance, which would mean loading of the concrete plugin type in the
> host AppDomain, it wraps the IPlugin implementation in a PluginProxy
> object, which derives from MBR.  This forwards all calls to the
> concrete plugin and all within the context of the restricted AppDomain.
> This is the now the conductor as you described it.
>
> - I signed both the plugin host and shared assemblies.  In the
> AppDomain setup code based on the blog posts, I assign a
> StrongNameMembershipCondition for the shared assembly and grant it full
> permissions.  This too is based on the post here:
>
> http://blogs.msdn.com/shawnfa/archive/2004/10/26/248114.aspx
>
> When attempting to call IPlugin.DoSomething() which displays a
> MessageBox (allowable under the internet named permission) I am failing
> with the security exception:
>
> System.Security.Policy.PolicyException: Required permissions cannot be
> acquired.
>
> The AppDomain setup/initializiation is verbatim from the blog posts
> cited, and this revised remoting model seems to match your comments as
> well as the blog entries.  Since the plugin is now only a reference
> within a "safe" MBR which I own in my shared/conductor assembly, the
> remoting stack would seem to be out of the picture.  I'm still unclear
> as to why this still fails.
>
> Thanks again!
>
> Kris
>
Author
23 Aug 2005 1:54 PM
kris
Hi Nicole, to give you full context as to my approach, I've emailed you
my current sample directly to your email.  If and when the issue is
identified, I'll post back the issue/solution to the list for the
record.  If anyone else is interested in the sample in the interim
please let me know and I'll forward it. 

Thanks again,  Kris.
Author
23 Aug 2005 3:20 PM
Nicole Calinoiu
You might have better luck if you were to grant full trust to .NET Framework
assemblies. <g>  The easiest way to fix this would probably be to add a new
code group that uses a StrongNameMembershipCondition based on only the key
(but not name or version) from mscorlib (typeof(object).Assembly).

HTH,
Nicole


Show quoteHide quote
"kris" <krsg***@gmail.com> wrote in message
news:1124805268.814622.63760@z14g2000cwz.googlegroups.com...
> Hi Nicole, to give you full context as to my approach, I've emailed you
> my current sample directly to your email.  If and when the issue is
> identified, I'll post back the issue/solution to the list for the
> record.  If anyone else is interested in the sample in the interim
> please let me know and I'll forward it.
>
> Thanks again,  Kris.
>
Author
23 Aug 2005 5:59 PM
kris
Hi Nicole, I wish you could of heard the slap to my forehead! :)
Thanks again for your help.  By adding full-trust, strong name
membership code groups for mscorlib and System.Windows.Forms things
worked wonderfully.  I'm a little unclear as to why mscorlib and the
winforms stuff have different public keys but that's a secondary issue.
Author
23 Aug 2005 6:37 PM
kris
Nix that last message, I had misunderstood your last comment regarding
the StrongNameMembershipCondition which explains the issue I had
mentioned.  Thanks again.
Author
23 Aug 2005 7:04 PM
Nicole Calinoiu
Nix my last too. <g>  I answered before seeing yours...


Show quoteHide quote
"kris" <krsg***@gmail.com> wrote in message
news:1124822247.338042.8290@g14g2000cwa.googlegroups.com...
> Nix that last message, I had misunderstood your last comment regarding
> the StrongNameMembershipCondition which explains the issue I had
> mentioned.  Thanks again.
>
Author
24 Aug 2005 8:05 PM
kris
I can't seem to shake the dreaded security exception, this time however
in a different context.  The final goal of my plugin proof of concept
is to allow the plugin host to provide services to the plugin.  My
plugin host implements IApplication which is handed to the IPlugin
instance to allow callbacks to the host.

It would appear that remoting is again the culprit given that my plugin
is interacting with a MarshalByRefObject from within the restricted
domain.  I attempted to wrap the MBR with a proxy which is handed to
plugin, and created within the fully-trusted shared/conductor assembly.
This would then forward calls from the plugin off to the actual MBR.
Unfortunately, I was met with the same error.  The exception states
that:

System.Security.SecurityException: Security error.
   at Spike.AppDomainHosting.Plugin.PluginImpl.Handshake(IApplication
application)
   at Spike.AppDomainHosting.Shared.PluginProxy.Handshake(IApplication
application) in
c:\dev\spike\plugins\spike.appdomainhosting.shared\pluginproxy.cs:line
43

The granted set of the failing assembly was:
<PermissionSet class="System.Security.PermissionSet"
               version="1">
   <IPermission
class="System.Security.Permissions.FileDialogPermission, mscorlib,
Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
                version="1"
                Access="Open"/>
   <IPermission
class="System.Security.Permissions.IsolatedStorageFilePermission,
mscorlib, Version=1.0.5000.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089"
                version="1"
                Allowed="DomainIsolationByUser"
                UserQuota="10240"/>
   <IPermission class="System.Security.Permissions.SecurityPermission,
mscorlib, Version=1.0.5000.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089"
                version="1"
                Flags="Execution"/>
   <IPermission class="System.Security.Permissions.UIPermission,
mscorlib, Version=1.0.5000.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089"
                version="1"
                Window="SafeTopLevelWindows"
                Clipboard="OwnClipboard"/>
   <IPermission class="System.Drawing.Printing.PrintingPermission,
System.Drawing, Version=1.0.5000.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a"
                version="1"
                Level="SafePrinting"/>
   <IPermission
class="System.Security.Permissions.UrlIdentityPermission, mscorlib,
Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
                version="1"

Url="file://C:/dev/spike/plugins/Spike.AppDomainHosting.Plugin/bin/Debug/Spike.AppDomainHosting.Plugin.dll"/>
   <IPermission
class="System.Security.Permissions.ZoneIdentityPermission, mscorlib,
Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
                version="1"
                Zone="MyComputer"/>
</PermissionSet>

Thanks again,

Kris
Author
25 Aug 2005 11:41 AM
Nicole Calinoiu
Hmm...  Without attempting a repro, it's hard to be sure, but I suspect that
this particular exception might simply be the result of attempting to call
into a strongly named assembly (either the proxy or the host) from a
partially trusted assembly (the plugin implementation).  See
http://blogs.msdn.com/shawnfa/archive/2005/02/04/367390.aspx for an
explanation of why this exception is thrown and how to address the problem.




Show quoteHide quote
"kris" <krsg***@gmail.com> wrote in message
news:1124913917.327893.29230@f14g2000cwb.googlegroups.com...
>I can't seem to shake the dreaded security exception, this time however
> in a different context.  The final goal of my plugin proof of concept
> is to allow the plugin host to provide services to the plugin.  My
> plugin host implements IApplication which is handed to the IPlugin
> instance to allow callbacks to the host.
>
> It would appear that remoting is again the culprit given that my plugin
> is interacting with a MarshalByRefObject from within the restricted
> domain.  I attempted to wrap the MBR with a proxy which is handed to
> plugin, and created within the fully-trusted shared/conductor assembly.
> This would then forward calls from the plugin off to the actual MBR.
> Unfortunately, I was met with the same error.  The exception states
> that:
>
> System.Security.SecurityException: Security error.
>   at Spike.AppDomainHosting.Plugin.PluginImpl.Handshake(IApplication
> application)
>   at Spike.AppDomainHosting.Shared.PluginProxy.Handshake(IApplication
> application) in
> c:\dev\spike\plugins\spike.appdomainhosting.shared\pluginproxy.cs:line
> 43
>
> The granted set of the failing assembly was:
> <PermissionSet class="System.Security.PermissionSet"
>               version="1">
>   <IPermission
> class="System.Security.Permissions.FileDialogPermission, mscorlib,
> Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
>                version="1"
>                Access="Open"/>
>   <IPermission
> class="System.Security.Permissions.IsolatedStorageFilePermission,
> mscorlib, Version=1.0.5000.0, Culture=neutral,
> PublicKeyToken=b77a5c561934e089"
>                version="1"
>                Allowed="DomainIsolationByUser"
>                UserQuota="10240"/>
>   <IPermission class="System.Security.Permissions.SecurityPermission,
> mscorlib, Version=1.0.5000.0, Culture=neutral,
> PublicKeyToken=b77a5c561934e089"
>                version="1"
>                Flags="Execution"/>
>   <IPermission class="System.Security.Permissions.UIPermission,
> mscorlib, Version=1.0.5000.0, Culture=neutral,
> PublicKeyToken=b77a5c561934e089"
>                version="1"
>                Window="SafeTopLevelWindows"
>                Clipboard="OwnClipboard"/>
>   <IPermission class="System.Drawing.Printing.PrintingPermission,
> System.Drawing, Version=1.0.5000.0, Culture=neutral,
> PublicKeyToken=b03f5f7f11d50a3a"
>                version="1"
>                Level="SafePrinting"/>
>   <IPermission
> class="System.Security.Permissions.UrlIdentityPermission, mscorlib,
> Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
>                version="1"
>
> Url="file://C:/dev/spike/plugins/Spike.AppDomainHosting.Plugin/bin/Debug/Spike.AppDomainHosting.Plugin.dll"/>
>   <IPermission
> class="System.Security.Permissions.ZoneIdentityPermission, mscorlib,
> Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
>                version="1"
>                Zone="MyComputer"/>
> </PermissionSet>
>
> Thanks again,
>
> Kris
>
Author
23 Aug 2005 6:58 PM
Nicole Calinoiu
"kris" <krsg***@gmail.com> wrote in message
news:1124819988.463476.47470@g44g2000cwa.googlegroups.com...
> Hi Nicole, I wish you could of heard the slap to my forehead! :)
> Thanks again for your help.  By adding full-trust, strong name
> membership code groups for mscorlib and System.Windows.Forms things
> worked wonderfully.  I'm a little unclear as to why mscorlib and the
> winforms stuff have different public keys but that's a secondary issue.

They don't.  Both mscorlib.dll and System.Windows.Forms.dll are signed with
the same key, which is generally referred to as the "ECMA key".  There's
another key that's used for signing some of the other assemblies that ship
with the .NET Framework (e.g.: System.Drawing.dll, System.Web.dll).  If you
look under the All_Code\My_Computer_Zone node of the default machine-level
CAS policy, you'll see two code groups that grant full trust to assemblies
signed with each of these keys.

If you found that you needed to add full trust code groups for both
mscorlib.dll and System.Windows.Forms.dll to your app domain policy, that's
probably because your CreateStrongNameMembershipCondition method created a
membership condition based on key, name, and version as opposed to just on
the key.  If you want to exclude the name and version from the membership
condition, supply null values for the corresponding constructor parameters.