| # Security guidelines for HANDLEs on Windows |
| |
| TL;DR; |
| |
| * Use [ScopedHandle](https://source.chromium.org/chromium/chromium/src/+/main:base/win/scoped_handle.h) |
| whenever possible. |
| * If you have to use a raw HANDLE: |
| * Reject invalid values using [base::win::IsPseudoHandle()](https://source.chromium.org/chromium/chromium/src/+/main:base/win/windows_handle_util.h) |
| do not just check against INVALID_HANDLE_VALUE, |
| * Initialize and return nullptr on failure. |
| * Avoid storing pseudo handle values. |
| * Provide GetCurrentProcess() or GetCurrentThread() directly to Windows APIs. |
| |
| ## Discussion |
| |
| Windows HANDLEs are used to represent objects such as Events, Files, Processes |
| and Threads. HANDLEs are typedef’d as a pointer-sized type but Windows only uses |
| 32 bits (with sign extension) so that 32 and 64 bit processes can interoperate. |
| |
| Windows HANDLEs are generally returned by Windows APIs that create or open |
| objects, and must be closed once the object is no longer in use to conserve |
| system resources. HANDLEs to the same object might have different access rights |
| (for instance, a process handle might only allow waiting on exit, or might allow |
| full memory access). HANDLEs can also be duplicated, both within the process |
| that created them (to allow code with different lifetimes to refer to the same |
| underlying object), and to other processes. |
| |
| HANDLE has several quirks. Many Windows APIs take or return pseudo handle |
| values, such as the return from ::GetCurrentProcess() or ::GetCurrentThread(). |
| These pseudo handle values may overlap with return values from some handle |
| manipulation functions, and malicious code could send these placeholder values |
| from less privileged processes. |
| |
| In particular, GetCurrentProcess() == INVALID_HANDLE_VALUE. Code must be very |
| careful not to use these pseudo handle values accidentally. For instance, code |
| might intend to open and send a file handle to a renderer, but if the file |
| opening failed it might accidentally provide INVALID_HANDLE_VALUE as the source |
| handle to DuplicateHandle(), resulting in a handle to the current process being |
| sent to the renderer, which would be a serious security bug. |
| |
| In general it should not be necessary for Chromium code to directly manipulate |
| Windows HANDLEs, and instead code should use abstractions such as [base::File](https://source.chromium.org/chromium/chromium/src/+/main:base/files/file.h). |
| Chromium, via mojo, makes it easy to send appropriately wrapped objects to |
| children using [mojo_base](https://source.chromium.org/chromium/chromium/src/+/main:mojo/public/mojom/base/) wrappers. |
| |
| # Guidelines |
| |
| ## Use ScopedHandle whenever possible |
| |
| In Chromium, HANDLEs should always be owned by a [base::win::ScopedHandle](https://source.chromium.org/chromium/chromium/src/+/main:base/win/scoped_handle.h) |
| and their underlying HANDLE should only be accessed when a related Windows API |
| is called. This ensures that HANDLEs are not leaked and that ownership of the |
| underlying object in Chromium code is clear. ScopedHandle refuses to adopt or |
| represent pseudo handle values, and will not return them from its .get() |
| accessor. |
| |
| When duplicating a ScopedHandle’s underlying HANDLE always call |
| ScopedHandle::is_valid() before calling DuplicateHandle, and return an empty |
| ScopedHandle or a raw nullptr HANDLE if duplication fails. |
| |
| When adopting a HANDLE value into a base::win::ScopedHandle that another process |
| duplicated into the current process (e.g. a log file handle on a command line) |
| use [base::win::TakeHandleOfType()](https://source.chromium.org/chromium/chromium/src/+/main:base/win/scoped_handle.h) |
| to validate that the HANDLE is not a pseudo handle and points to a valid object |
| before adopting it. |
| |
| ## Using HANDLE in Chromium |
| |
| If you must manipulate HANDLEs directly, the following guidelines apply: |
| |
| Do not store pseudo handles, and instead simply call ::GetCurrentProcess() when |
| you need the pseudo handle value. If you need a real handle to a process (and |
| [base::Process](https://source.chromium.org/chromium/chromium/src/+/main:base/process/process.h) |
| does not provide what you need), you must duplicate to a real HANDLE before |
| adopting it. |
| |
| Use nullptr to represent uninitialized or invalid values. In code that manages |
| its own HANDLEs use nullptr to initialize all HANDLE variables and members and |
| return nullptr from any accessor that returns a raw HANDLE while the wrapper |
| object is invalid. Use [base::win::IsPseudoHandle()](https://source.chromium.org/chromium/chromium/src/+/main:base/win/windows_handle_util.h) to validate HANDLE values |
| provided to constructors (do not just check handle != INVALID_HANDLE_VALUE). |