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