1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*++
6
7
8
9Module Name:
10
11 handleapi.cpp
12
13Abstract:
14
15 Implementation of the handle management APIs
16
17
18
19--*/
20
21#include "pal/handleapi.hpp"
22#include "pal/handlemgr.hpp"
23#include "pal/thread.hpp"
24#include "pal/procobj.hpp"
25#include "pal/dbgmsg.h"
26#include "pal/process.h"
27
28using namespace CorUnix;
29
30SET_DEFAULT_DEBUG_CHANNEL(HANDLE);
31
32CAllowedObjectTypes aotDuplicateHandle(TRUE);
33
34PAL_ERROR
35CloseSpecialHandle(
36 HANDLE hObject
37 );
38
39/*++
40Function:
41 DuplicateHandle
42
43See MSDN doc.
44
45PAL-specific behavior :
46 -Source and Target process needs to be the current process.
47 -lpTargetHandle must be non-NULL
48 -dwDesiredAccess is ignored
49 -bInheritHandle must be FALSE
50 -dwOptions must be a combo of DUPLICATE_SAME_ACCESS and
51 DUPLICATE_CLOSE_SOURCE
52
53--*/
54BOOL
55PALAPI
56DuplicateHandle(
57 IN HANDLE hSourceProcessHandle,
58 IN HANDLE hSourceHandle,
59 IN HANDLE hTargetProcessHandle,
60 OUT LPHANDLE lpTargetHandle,
61 IN DWORD dwDesiredAccess,
62 IN BOOL bInheritHandle,
63 IN DWORD dwOptions)
64{
65 PAL_ERROR palError;
66 CPalThread *pThread;
67
68 PERF_ENTRY(DuplicateHandle);
69 ENTRY("DuplicateHandle( hSrcProcHandle=%p, hSrcHandle=%p, "
70 "hTargetProcHandle=%p, lpTargetHandle=%p, dwAccess=%#x, "
71 "bInheritHandle=%d, dwOptions=%#x) \n", hSourceProcessHandle,
72 hSourceHandle, hTargetProcessHandle, lpTargetHandle,
73 dwDesiredAccess, bInheritHandle, dwOptions);
74
75 pThread = InternalGetCurrentThread();
76
77 palError = InternalDuplicateHandle(
78 pThread,
79 hSourceProcessHandle,
80 hSourceHandle,
81 hTargetProcessHandle,
82 lpTargetHandle,
83 dwDesiredAccess,
84 bInheritHandle,
85 dwOptions
86 );
87
88 if (NO_ERROR != palError)
89 {
90 pThread->SetLastError(palError);
91 }
92
93 LOGEXIT("DuplicateHandle returns BOOL %d\n", (NO_ERROR == palError));
94 PERF_EXIT(DuplicateHandle);
95 return (NO_ERROR == palError);
96}
97
98PAL_ERROR
99CorUnix::InternalDuplicateHandle(
100 CPalThread *pThread,
101 HANDLE hSourceProcess,
102 HANDLE hSource,
103 HANDLE hTargetProcess,
104 LPHANDLE phDuplicate,
105 DWORD dwDesiredAccess,
106 BOOL bInheritHandle,
107 DWORD dwOptions
108 )
109{
110 PAL_ERROR palError = NO_ERROR;
111 IPalObject *pobjSource = NULL;
112
113 DWORD source_process_id;
114 DWORD target_process_id;
115 DWORD cur_process_id;
116
117 cur_process_id = GetCurrentProcessId();
118 source_process_id = PROCGetProcessIDFromHandle(hSourceProcess);
119 target_process_id = PROCGetProcessIDFromHandle(hTargetProcess);
120
121 /* Check validity of process handles */
122 if (0 == source_process_id || 0 == target_process_id)
123 {
124 ASSERT("Can't duplicate handle: invalid source or destination process");
125 palError = ERROR_INVALID_PARAMETER;
126 goto InternalDuplicateHandleExit;
127 }
128
129 /* At least source or target process should be the current process. */
130 if (source_process_id != cur_process_id
131 && target_process_id != cur_process_id)
132 {
133 ASSERT("Can't duplicate handle : neither source or destination"
134 "processes are from current process");
135 palError = ERROR_INVALID_PARAMETER;
136 goto InternalDuplicateHandleExit;
137 }
138
139 if (FALSE != bInheritHandle)
140 {
141 ASSERT("Can't duplicate handle : bInheritHandle is not FALSE.\n");
142 palError = ERROR_INVALID_PARAMETER;
143 goto InternalDuplicateHandleExit;
144 }
145
146 if (dwOptions & ~(DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
147 {
148 ASSERT(
149 "Can't duplicate handle : dwOptions is %#x which is not "
150 "a subset of (DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE) "
151 "(%#x).\n",
152 dwOptions,
153 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
154 palError = ERROR_INVALID_PARAMETER;
155 goto InternalDuplicateHandleExit;
156 }
157
158 if (0 == (dwOptions & DUPLICATE_SAME_ACCESS))
159 {
160 ASSERT(
161 "Can't duplicate handle : dwOptions is %#x which does not "
162 "include DUPLICATE_SAME_ACCESS (%#x).\n",
163 dwOptions,
164 DUPLICATE_SAME_ACCESS);
165 palError = ERROR_INVALID_PARAMETER;
166 goto InternalDuplicateHandleExit;
167 }
168
169 if (NULL == phDuplicate)
170 {
171 ASSERT("Can't duplicate handle : lpTargetHandle is NULL.\n");
172 goto InternalDuplicateHandleExit;
173 }
174
175 /* Since handles can be remoted to others processes using PAL_LocalHsndleToRemote
176 and PAL_RemoteHandleToLocal, DuplicateHandle needs some special handling
177 when this scenario occurs.
178
179 if hSourceProcessHandle is from another process OR
180 hTargetProcessHandle is from another process but both aren't
181 ( handled above ) return hSourceHandle.
182 */
183 if (source_process_id != cur_process_id
184 || target_process_id != cur_process_id)
185 {
186 *phDuplicate = hSource;
187 palError = NO_ERROR;
188 goto InternalDuplicateHandleExit;
189 }
190
191 //
192 // Obtain the source IPalObject
193 //
194
195 if (!HandleIsSpecial(hSource))
196 {
197 palError = g_pObjectManager->ReferenceObjectByHandle(
198 pThread,
199 hSource,
200 &aotDuplicateHandle,
201 dwDesiredAccess,
202 &pobjSource
203 );
204
205 if (NO_ERROR != palError)
206 {
207 ERROR("Unable to get object for source handle %p (%i)\n", hSource, palError);
208 goto InternalDuplicateHandleExit;
209 }
210 }
211 else if (hPseudoCurrentProcess == hSource)
212 {
213 TRACE("Duplicating process pseudo handle(%p)\n", hSource);
214
215 pobjSource = g_pobjProcess;
216 pobjSource->AddReference();
217 }
218 else if (hPseudoCurrentThread == hSource)
219 {
220 TRACE("Duplicating thread pseudo handle(%p)\n", hSource);
221
222 pobjSource = pThread->GetThreadObject();
223 pobjSource->AddReference();
224 }
225 else
226 {
227 ASSERT("Duplication not supported for this special handle (%p)\n", hSource);
228 palError = ERROR_INVALID_HANDLE;
229 goto InternalDuplicateHandleExit;
230 }
231
232 palError = g_pObjectManager->ObtainHandleForObject(
233 pThread,
234 pobjSource,
235 dwDesiredAccess,
236 bInheritHandle,
237 NULL,
238 phDuplicate
239 );
240
241InternalDuplicateHandleExit:
242
243 if (NULL != pobjSource)
244 {
245 pobjSource->ReleaseReference(pThread);
246 }
247
248 if (dwOptions & DUPLICATE_CLOSE_SOURCE)
249 {
250 //
251 // Since DUPLICATE_CLOSE_SOURCE was specified the source handle
252 // MUST be closed, even if an error occurred during the duplication
253 // process
254 //
255
256 TRACE("DuplicateHandle closing source handle %p\n", hSource);
257 InternalCloseHandle(pThread, hSource);
258 }
259
260 return palError;
261}
262
263/*++
264Function:
265 CloseHandle
266
267See MSDN doc.
268
269Note : according to MSDN, FALSE is returned in case of error. But also
270according to MSDN, closing an invalid handle raises an exception when running a
271debugger [or, alternately, if a special registry key is set]. This behavior is
272not required in the PAL, so we'll always return FALSE.
273--*/
274BOOL
275PALAPI
276CloseHandle(
277 IN OUT HANDLE hObject)
278{
279 CPalThread *pThread;
280 PAL_ERROR palError;
281
282 PERF_ENTRY(CloseHandle);
283 ENTRY("CloseHandle (hObject=%p) \n", hObject);
284
285 pThread = InternalGetCurrentThread();
286
287 palError = InternalCloseHandle(
288 pThread,
289 hObject
290 );
291
292 if (NO_ERROR != palError)
293 {
294 pThread->SetLastError(palError);
295 }
296
297 LOGEXIT("CloseHandle returns BOOL %d\n", (NO_ERROR == palError));
298 PERF_EXIT(CloseHandle);
299 return (NO_ERROR == palError);
300}
301
302PAL_ERROR
303CorUnix::InternalCloseHandle(
304 CPalThread * pThread,
305 HANDLE hObject
306 )
307{
308 PAL_ERROR palError = NO_ERROR;
309
310 if (!HandleIsSpecial(hObject))
311 {
312 palError = g_pObjectManager->RevokeHandle(
313 pThread,
314 hObject
315 );
316 }
317 else
318 {
319 palError = CloseSpecialHandle(hObject);
320 }
321
322 return palError;
323}
324
325PAL_ERROR
326CloseSpecialHandle(
327 HANDLE hObject
328 )
329{
330 if ((hObject == hPseudoCurrentThread) ||
331 (hObject == hPseudoCurrentProcess))
332 {
333 return NO_ERROR;
334 }
335
336 return ERROR_INVALID_HANDLE;
337}
338
339