IronLanguages / main

Work for this repo has moved to https://github.com/IronLanguages/ironpython2
1.16k stars 350 forks source link

PythonSocket -- unhandled exception in Finalize() in restricted AppDomain #1053

Open ironpythonbot opened 9 years ago

ironpythonbot commented 9 years ago

Perhaps it's just my C# ignorance, but I haven't found a way to sandbox this away so that a sandboxed script can't bring down the host.

Example:

using System;
using System.Security;
using System.Security.Permissions;
using IronPython.Hosting;
using Microsoft.Scripting.Hosting;

namespace BugReport
{
    class Program
    {
        static void Main(string[] args)
        {
            AppDomain root = AppDomain.CurrentDomain;

            AppDomainSetup sandboxSetup = new AppDomainSetup();
            sandboxSetup.ApplicationBase = root.SetupInformation.ApplicationBase;

            PermissionSet sandboxPermissionSet = new PermissionSet(PermissionState.None);

            AppDomain sandbox = AppDomain.CreateDomain("sandbox", null, sandboxSetup, sandboxPermissionSet);

            ScriptEngine engine = Python.CreateEngine(sandbox);

            try
            {
                engine.Execute("from socket import *; s = socket(AF_INET, SOCK_STREAM)");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }

            // we don't want to wait
            GC.Collect();
            GC.WaitForPendingFinalizers();

            Console.WriteLine("Press a key...");
            Console.ReadKey();
        }
    }
}

Exception:

System.Security.SecurityException was unhandled
  Message=Request for the permission of type 'System.Security.Permissions.SecurityPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.
  Source=mscorlib
  StackTrace:
       at System.Security.CodeAccessSecurityEngine.Check(Object demand, StackCrawlMark& stackMark, Boolean isPermSet)
       at System.Security.CodeAccessSecurityEngine.Check(CodeAccessPermission cap, StackCrawlMark& stackMark)
       at System.Security.CodeAccessPermission.Demand()
       at System.Net.Sockets.Socket.get_Handle()
       at IronPython.Modules.PythonSocket.socket._close()
       at IronPython.Modules.PythonSocket.socket.Finalize()
  InnerException: 

Work Item Details

Original CodePlex Issue: Issue 33779 Status: Proposed Reason Closed: Unassigned Assigned to: Unassigned Reported on: Feb 15, 2013 at 5:44 PM Reported by: creinke Updated on: Feb 22, 2013 at 2:08 AM Updated by: KeithJRome

ironpythonbot commented 9 years ago

On 2013-02-18 22:14:59 UTC, MarkusSchaber commented:

You should be able to catch the exception by attaching to the UnhandledException event of your appdomain:

http://msdn.microsoft.com/de-de/library/system.appdomain.unhandledexception.aspx

ironpythonbot commented 9 years ago

On 2013-02-19 00:27:11 UTC, creinke commented:

As I understand it, "the UnhandledException event simply notifies you that an exception has gone unhandled, in case you want to try to save state before your thread or application dies." [1] So, yes, I can catch it, but it still brings down the host.

[1] http://www.codinghorror.com/blog/2005/02/console-apps-and-appdomain-currentdomain-unhandledexception.html

ironpythonbot commented 9 years ago

On 2013-02-19 12:46:35 UTC, jdhardy commented:

What I can't quite figure out is why it throws on finalization but not creation, since socket.Handle is called from socket.Initialize() as well. I also don't know enough about CAS to know if there's a way to make it fail sooner, when it might be possible to handle the error.

ironpythonbot commented 9 years ago

On 2013-02-20 09:54:04 UTC, KeithJRome commented:

Most likely has something to do with the fact that the finalization queue is run on the finalizer thread. The finalizer calls _close(), which in turn tries to delist the socket from the static dictionary _handleToSocket. But to get the key used in that dictionary, it uses the Handle property, which makes a CAS demand on SecurityPermissionFlag.UnmanagedCode. And I guess the finalizer thread is not endowed with that permission.

Seems like the least nasty fix might be to change how _close() searches for the socket in that dictionary... doing a brute-force lookup by value instead of by key and removing it that way? This would avoid any attempts to dereference the Handle property of the Socket during finalization.