The Labs \ Source Viewer \ SSCLI \ System.Runtime.InteropServices \ SafeHandle

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** Class:  SafeHandle
  18. **
  19. **
  20. ** A specially designed handle wrapper to ensure we never leak
  21. ** an OS handle.  The runtime treats this class specially during
  22. ** P/Invoke marshaling and finalization.  Users should write
  23. ** subclasses of SafeHandle for each distinct handle type.
  24. **
  25. **
  26. ===========================================================*/
  27. using System;
  28. using System.Reflection;
  29. using System.Threading;
  30. using System.Security.Permissions;
  31. using System.Runtime.CompilerServices;
  32. using System.IO;
  33. using System.Runtime.ConstrainedExecution;
  34. using System.Runtime.Versioning;
  35. /*
  36.   Problems addressed by the SafeHandle class:
  37.   1) Critical finalization - ensure we never leak OS resources in SQL.  Done
  38.     without running truly arbitrary & unbounded amounts of managed code.
  39.   2) Reduced graph promotion - during finalization, keep object graph small
  40.   3) GC.KeepAlive behavior - P/Invoke vs. finalizer thread race (HandleRef)
  41.   4) Elimination of security races w/ explicit calls to Close (HandleProtector)
  42.   5) Enforcement of the above via the type system - Don't use IntPtr anymore.
  43.   6) Allows the handle lifetime to be controlled externally via a boolean.
  44.   Subclasses of SafeHandle will implement the ReleaseHandle abstract method
  45.   used to execute any code required to free the handle. This method will be
  46.   prepared as a constrained execution region at instance construction time
  47.   (along with all the methods in its statically determinable call graph). This
  48.   implies that we won't get any inconvenient jit allocation errors or rude
  49.   thread abort interrupts while releasing the handle but the user must still
  50.   write careful code to avoid injecting fault paths of their own (see the CER
  51.   spec for more details). In particular, any sub-methods you call should be
  52.   decorated with a reliability contract of the appropriate level. In most cases
  53.   this should be:
  54.     ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)
  55.   Also, any P/Invoke methods should use the SuppressUnmanagedCodeSecurity
  56.   attribute to avoid a runtime security check that can also inject failures
  57.   (even if the check is guaranteed to pass).
  58.   The GC will run ReleaseHandle methods after any normal finalizers have been
  59.   run for objects that were collected at the same time. This ensures classes
  60.   like FileStream can run a normal finalizer to flush out existing buffered
  61.   data. This is key - it means adding this class to a class like FileStream does
  62.   not alter our current semantics w.r.t. finalization today.
  63.   Subclasses must also implement the IsInvalid property so that the
  64.   infrastructure can tell when critical finalization is actually required.
  65.   Again, this method is prepared ahead of time. It's envisioned that direct
  66.   subclasses of SafeHandle will provide an IsInvalid implementation that suits
  67.   the general type of handle they support (null is invalid, -1 is invalid etc.)
  68.   and then these classes will be further derived for specific safe handle types.
  69.   Most classes using SafeHandle should not provide a finalizer.  If they do
  70.   need to do so (ie, for flushing out file buffers, needing to write some data
  71.   back into memory, etc), then they can provide a finalizer that will be
  72.   guaranteed to run before the SafeHandle's critical finalizer. 
  73.   Note that SafeHandle's ReleaseHandle is called from a constrained execution
  74.   region, and is eagerly prepared before we create your class.  This means you
  75.   should only call methods with an appropriate reliability contract from your
  76.   ReleaseHandle method.
  77.   Subclasses are expected to be written as follows (note that
  78.   SuppressUnmanagedCodeSecurity should always be used on any P/Invoke methods
  79.   invoked as part of ReleaseHandle, in order to switch the security check from
  80.   runtime to jit time and thus remove a possible failure path from the
  81.   invocation of the method):
  82.   internal sealed MySafeHandleSubclass : SafeHandle {
  83.       // Called by P/Invoke when returning SafeHandles
  84.       private MySafeHandleSubclass() : base(IntPtr.Zero, true)
  85.       {
  86.       }
  87.       // If & only if you need to support user-supplied handles
  88.       internal MySafeHandleSubclass(IntPtr preexistingHandle, bool ownsHandle) : base(IntPtr.Zero, ownsHandle)
  89.       {
  90.           SetHandle(preexistingHandle);
  91.       }
  92.       // Do not provide a finalizer - SafeHandle's critical finalizer will
  93.       // call ReleaseHandle for you.
  94.       public override bool IsInvalid {
  95.           get { return handle == IntPtr.Zero; }
  96.       }
  97.       override protected bool ReleaseHandle()
  98.       {
  99.           return MyNativeMethods.CloseHandle(handle);
  100.       }
  101.   }
  102.   Then elsewhere to create one of these SafeHandles, define a method
  103.   with the following type of signature (CreateFile follows this model).
  104.   Note that when returning a SafeHandle like this, P/Invoke will call your
  105.   class's default constructor.  Also, you probably want to define CloseHandle
  106.   somewhere, and remember to apply a reliability contract to it.
  107.   [SuppressUnmanagedCodeSecurity]
  108.   internal static class MyNativeMethods {
  109.       [DllImport("kernel32")]
  110.       private static extern MySafeHandleSubclass CreateHandle(int someState);
  111.       [DllImport("kernel32", SetLastError=true), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  112.       private static extern bool CloseHandle(IntPtr handle);
  113.   }
  114.   Drawbacks with this implementation:
  115.   1) Requires some magic to run the critical finalizer.
  116. */
  117. namespace System.Runtime.InteropServices
  118. {
  119.    
  120.     // This class should not be serializable - it's a handle. We require unmanaged
  121.     // code permission to subclass SafeHandle to prevent people from writing a
  122.     // subclass and suddenly being able to run arbitrary native code with the
  123.     // same signature as CloseHandle. This is technically a little redundant, but
  124.     // we'll do this to ensure we've cut off all attack vectors. Similarly, all
  125.     // methods have a link demand to ensure untrusted code cannot directly edit
  126.     // or alter a handle.
  127.     [SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
  128.     [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
  129.    
  130.     public abstract class SafeHandle : CriticalFinalizerObject, IDisposable
  131.     {
  132.         // ! Do not add or rearrange fields as the EE depends on this layout.
  133.         //------------------------------------------------------------------
  134.         #if DEBUG
  135.         private string _stackTrace;
  136.         // Where we allocated this SafeHandle.
  137.         #endif
  138.         protected IntPtr handle;
  139.         // this must be protected so derived classes can use out params.
  140.         private int _state;
  141.         // Combined ref count and closed/disposed flags (so we can atomically modify them).
  142.         private bool _ownsHandle;
  143.         // Whether we can release this handle.
  144.         #pragma warning disable 414
  145.         private bool _fullyInitialized;
  146.         // Whether constructor completed.
  147.         #pragma warning restore 414
  148.         // Creates a SafeHandle class. Users must then set the Handle property.
  149.         // To prevent the SafeHandle from being freed, write a subclass that
  150.         // doesn't define a finalizer.
  151.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  152.         protected SafeHandle(IntPtr invalidHandleValue, bool ownsHandle)
  153.         {
  154.             handle = invalidHandleValue;
  155.             _state = 4;
  156.             // Ref count 1 and not closed or disposed.
  157.             _ownsHandle = ownsHandle;
  158.            
  159.             if (!ownsHandle)
  160.                 GC.SuppressFinalize(this);
  161.            
  162.             #if DEBUG
  163.             if (BCLDebug.SafeHandleStackTracesEnabled)
  164.                 _stackTrace = Environment.GetStackTrace(null, false);
  165.             else
  166.                 _stackTrace = "For a stack trace showing who allocated this SafeHandle, set SafeHandleStackTraces to 1 and rerun your app.";
  167.             #endif
  168.            
  169.             // Set this last to prevent SafeHandle's finalizer from freeing an
  170.             // invalid handle. This means we don't have to worry about
  171.             // ThreadAbortExceptions interrupting this constructor or the managed
  172.             // constructors on subclasses that call this constructor.
  173.             _fullyInitialized = true;
  174.         }
  175.        
  176.         ~SafeHandle()
  177.         {
  178.             Dispose(false);
  179.         }
  180.        
  181.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  182.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  183.         extern void InternalFinalize();
  184.        
  185.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  186.         protected void SetHandle(IntPtr handle)
  187.         {
  188.             this.handle = handle;
  189.         }
  190.        
  191.         // This method is necessary for getting an IntPtr out of a SafeHandle.
  192.         // Used to tell whether a call to create the handle succeeded by comparing
  193.         // the handle against a known invalid value, and for backwards
  194.         // compatibility to support the handle properties returning IntPtrs on
  195.         // many of our Framework classes.
  196.         // Note that this method is dangerous for two reasons:
  197.         // 1) If the handle has been marked invalid with SetHandleasInvalid,
  198.         // DangerousGetHandle will still return the original handle value.
  199.         // 2) The handle returned may be recycled at any point. At best this means
  200.         // the handle might stop working suddenly. At worst, if the handle or
  201.         // the resource the handle represents is exposed to untrusted code in
  202.         // any way, this can lead to a handle recycling security attack (i.e. an
  203.         // untrusted caller can query data on the handle you've just returned
  204.         // and get back information for an entirely unrelated resource).
  205.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  206.         [ResourceExposure(ResourceScope.Machine)]
  207.         public IntPtr DangerousGetHandle()
  208.         {
  209.             return handle;
  210.         }
  211.        
  212.         public bool IsClosed {
  213.             [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  214.             get { return (_state & 1) == 1; }
  215.         }
  216.        
  217.         public abstract bool IsInvalid {
  218.             [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  219.             get;
  220.         }
  221.        
  222.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  223.         public void Close()
  224.         {
  225.             Dispose(true);
  226.         }
  227.        
  228.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  229.         public void Dispose()
  230.         {
  231.             Dispose(true);
  232.         }
  233.        
  234.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  235.         protected virtual void Dispose(bool disposing)
  236.         {
  237.             if (disposing)
  238.                 InternalDispose();
  239.             else
  240.                 InternalFinalize();
  241.         }
  242.        
  243.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  244.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  245.         private extern void InternalDispose();
  246.        
  247.         // This should only be called for cases when you know for a fact that
  248.         // your handle is invalid and you want to record that information.
  249.         // An example is calling a syscall and getting back ERROR_INVALID_HANDLE.
  250.         // This method will normally leak handles!
  251.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  252.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  253.         public extern void SetHandleAsInvalid();
  254.        
  255.         // Implement this abstract method in your derived class to specify how to
  256.         // free the handle. Be careful not write any code that's subject to faults
  257.         // in this method (the runtime will prepare the infrastructure for you so
  258.         // that no jit allocations etc. will occur, but don't allocate memory unless
  259.         // you can deal with the failure and still free the handle).
  260.         // The boolean returned should be true for success and false if the runtime
  261.         // should fire a SafeHandleCriticalFailure MDA (CustomerDebugProbe) if that
  262.         // MDA is enabled.
  263.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  264.         protected abstract bool ReleaseHandle();
  265.        
  266.         // Add a reason why this handle should not be relinquished (i.e. have
  267.         // ReleaseHandle called on it). This method has dangerous in the name since
  268.         // it must always be used carefully (e.g. called within a CER) to avoid
  269.         // leakage of the handle. It returns a boolean indicating whether the
  270.         // increment was actually performed to make it easy for program logic to
  271.         // back out in failure cases (i.e. is a call to DangerousRelease needed).
  272.         // It is passed back via a ref parameter rather than as a direct return so
  273.         // that callers need not worry about the atomicity of calling the routine
  274.         // and assigning the return value to a variable (the variable should be
  275.         // explicitly set to false prior to the call). The only failure cases are
  276.         // when the method is interrupted prior to processing by a thread abort or
  277.         // when the handle has already been (or is in the process of being)
  278.         // released.
  279.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
  280.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  281.         public extern void DangerousAddRef(ref bool success);
  282.        
  283.         // Partner to DangerousAddRef. This should always be successful when used in
  284.         // a correct manner (i.e. matching a successful DangerousAddRef and called
  285.         // from a region such as a CER where a thread abort cannot interrupt
  286.         // processing). In the same way that unbalanced DangerousAddRef calls can
  287.         // cause resource leakage, unbalanced DangerousRelease calls may cause
  288.         // invalid handle states to become visible to other threads. This
  289.         // constitutes a potential security hole (via handle recycling) as well as a
  290.         // correctness problem -- so don't ever expose Dangerous* calls out to
  291.         // untrusted code.
  292.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  293.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  294.         public extern void DangerousRelease();
  295.     }
  296. }

Developer Fusion