Esempio n. 1
0
 /// <summary>
 /// Destroy the AppDomain.
 /// </summary>
 private void DestroyDomain(bool disposing)
 {
     Debug.WriteLine("Unloading AppDomain '" + mAppDomain.FriendlyName +
                     "', id=" + mAppDomain.Id + ", disposing=" + disposing);
     if (mKeepAliveTimer != null)
     {
         mKeepAliveTimer.Stop();
         mKeepAliveTimer.Dispose();
         mKeepAliveTimer = null;
     }
     if (mPluginManager != null)
     {
         mPluginManager.Dispose();
         mPluginManager = null;
     }
     if (mAppDomain != null)
     {
         // We can't simply invoke AppDomain.Unload() from a finalizer.  The unload is
         // handled by a thread that won't run at the same time as the finalizer thread,
         // so if we got here through finalization we will deadlock.  Fortunately the
         // runtime sees the situation and throws an exception out of Unload().
         //
         // If we don't have a finalizer, and we forget to make an explicit cleanup
         // call, the AppDomain will stick around and keep the DLL files locked, which
         // could be annoying if the user is trying to iterate on extension script
         // development.
         //
         // So we use a workaround from https://stackoverflow.com/q/4064749/294248
         // and invoke it asynchronously.
         if (disposing)
         {
             AppDomain.Unload(mAppDomain);
         }
         else
         {
             new Action <AppDomain>(AppDomain.Unload).BeginInvoke(mAppDomain, null, null);
         }
         mAppDomain = null;
     }
 }
Esempio n. 2
0
        /// <summary>
        /// Creates a new AppDomain.  If our plugin is just executing
        /// pre-compiled code we can lock the permissions down, but if
        /// it needs to dynamically compile code we need to open things up.
        /// </summary>
        /// <param name="appDomainName">The "friendly" name.</param>
        /// <param name="appBaseBath">Directory to use for ApplicationBase.</param>
        public void CreateDomain(string appDomainName, string appBaseBath)
        {
            // This doesn't seem to affect Sponsor.  Doing this over in the PluginManager
            // does have the desired effect, but requires unrestricted security.
            //LifetimeServices.LeaseTime = TimeSpan.FromSeconds(5);
            //LifetimeServices.LeaseManagerPollTime = TimeSpan.FromSeconds(3);
            //LifetimeServices.RenewOnCallTime = TimeSpan.FromSeconds(2);
            //LifetimeServices.SponsorshipTimeout = TimeSpan.FromSeconds(1);

            if (mAppDomain != null)
            {
                throw new Exception("Domain already created");
            }

            PermissionSet permSet;

            // Start with everything disabled.
            permSet = new PermissionSet(PermissionState.None);
            //permSet = new PermissionSet(PermissionState.Unrestricted);

            // Allow code execution.
            permSet.AddPermission(new SecurityPermission(
                                      SecurityPermissionFlag.Execution));

            // This appears to be necessary to allow the lease renewal to work.  Without
            // this the lease silently fails to renew.
            permSet.AddPermission(new SecurityPermission(
                                      SecurityPermissionFlag.Infrastructure));

            // Allow changes to Remoting stuff.  Without this, we can't
            // register our ISponsor.
            permSet.AddPermission(new SecurityPermission(
                                      SecurityPermissionFlag.RemotingConfiguration));

            // Allow read-only file access, but only in the plugin directory.
            // This is necessary to allow PluginLoader to load the assembly.
            FileIOPermission fp = new FileIOPermission(
                FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery,
                appBaseBath);

            permSet.AddPermission(fp);

            // TODO(maybe): it looks like this would allow us to mark the PluginCommon dll as
            // trusted, so we wouldn't have to give the above permissions to everything.
            // That seems to require a cryptographic pair and some other voodoo.
            //StrongName fullTrustAssembly =
            //    typeof(PluginManager).Assembly.Evidence.GetHostEvidence<StrongName>();

            // Configure the AppDomain.  Setting the ApplicationBase directory away from
            // the main app location is apparently very important, as it mitigates the
            // risk of certain exploits from untrusted plugin code.
            AppDomainSetup adSetup = new AppDomainSetup();

            adSetup.ApplicationBase = appBaseBath;

            // Create the AppDomain.
            mAppDomain = AppDomain.CreateDomain(appDomainName, null, adSetup, permSet);

            Debug.WriteLine("Created AppDomain '" + appDomainName + "', id=" + mAppDomain.Id);
            //Debug.WriteLine("Loading '" + typeof(PluginManager).Assembly.FullName + "' / '" +
            //    typeof(PluginManager).FullName + "'");

            // Create a PluginManager in the remote AppDomain.  The local
            // object is actually a proxy.
            PluginManager pm = (PluginManager)mAppDomain.CreateInstanceAndUnwrap(
                typeof(PluginManager).Assembly.FullName,
                typeof(PluginManager).FullName);

            // Wrap it so it doesn't disappear on us.
            mPluginManager = new Sponsor <PluginManager>(pm);

            Debug.WriteLine("IsTransparentProxy: " +
                            System.Runtime.Remoting.RemotingServices.IsTransparentProxy(pm));
        }