| 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 | |
| 9 | Module Name: |
| 10 | |
| 11 | handleapi.cpp |
| 12 | |
| 13 | Abstract: |
| 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 | |
| 28 | using namespace CorUnix; |
| 29 | |
| 30 | SET_DEFAULT_DEBUG_CHANNEL(HANDLE); |
| 31 | |
| 32 | CAllowedObjectTypes aotDuplicateHandle(TRUE); |
| 33 | |
| 34 | PAL_ERROR |
| 35 | CloseSpecialHandle( |
| 36 | HANDLE hObject |
| 37 | ); |
| 38 | |
| 39 | /*++ |
| 40 | Function: |
| 41 | DuplicateHandle |
| 42 | |
| 43 | See MSDN doc. |
| 44 | |
| 45 | PAL-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 | --*/ |
| 54 | BOOL |
| 55 | PALAPI |
| 56 | DuplicateHandle( |
| 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 | |
| 98 | PAL_ERROR |
| 99 | CorUnix::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 | |
| 241 | InternalDuplicateHandleExit: |
| 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 | /*++ |
| 264 | Function: |
| 265 | CloseHandle |
| 266 | |
| 267 | See MSDN doc. |
| 268 | |
| 269 | Note : according to MSDN, FALSE is returned in case of error. But also |
| 270 | according to MSDN, closing an invalid handle raises an exception when running a |
| 271 | debugger [or, alternately, if a special registry key is set]. This behavior is |
| 272 | not required in the PAL, so we'll always return FALSE. |
| 273 | --*/ |
| 274 | BOOL |
| 275 | PALAPI |
| 276 | CloseHandle( |
| 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 | |
| 302 | PAL_ERROR |
| 303 | CorUnix::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 | |
| 325 | PAL_ERROR |
| 326 | CloseSpecialHandle( |
| 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 | |