[New-bugs-announce] [issue38188] Incorrect Argument Order for Calls to _winapi.DuplicateHandle() in multiprocessing.reduction.DupHandle

Cameron Kennedy report at bugs.python.org
Mon Sep 16 13:51:37 EDT 2019


New submission from Cameron Kennedy <kennedy.c at husky.neu.edu>:

The DuplicateHandle function is utilized by the DupHandle object to duplicate handles for the purpose of sending and receiving between processes on Windows systems. At least on Python 3.7.3, this function is invoked with an incorrect argument order. In multiprocessing.reduction, send_handle passes _winapi.DUPLICATE_SAME_ACCESS as the access argument to the DupHandle constructor, which in-turn passes it to the access argument for _winapi.DuplicateHandle(). Instead, per https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-duplicatehandle this constant should be passed into the options argument. This bug results in any handles communicated via this method to have meaningless permissions set, which makes them unusable. 

I've monkeypatched the issue with the following code:

try:
    import _winapi
    log = logging.getLogger('')
    log.warning('Patching multiprocessing.reduction to deal with the _winapi.DuplicateHandle() PROCESS_DUP_HANDLE argument order bug.')
    class _PatchedDupHandle(object):
        '''Picklable wrapper for a handle.'''
        def __init__(self, handle, access, pid=None, options=0):
            if pid is None:
                # We just duplicate the handle in the current process and
                # let the receiving process steal the handle.
                pid = os.getpid()
            proc = _winapi.OpenProcess(_winapi.PROCESS_DUP_HANDLE, False, pid)
            try:
                self._handle = _winapi.DuplicateHandle(
                    _winapi.GetCurrentProcess(),
                    handle, proc, access, False, options)
            finally:
                _winapi.CloseHandle(proc)
            self._options = options
            self._access = access
            self._pid = pid

        def detach(self):
            '''Get the handle.  This should only be called once.'''
            # retrieve handle from process which currently owns it
            if self._pid == os.getpid():
                # The handle has already been duplicated for this process.
                return self._handle
            # We must steal the handle from the process whose pid is self._pid.
            proc = _winapi.OpenProcess(_winapi.PROCESS_DUP_HANDLE, False,
                                       self._pid)
            try:
                return _winapi.DuplicateHandle(
                    proc, self._handle, _winapi.GetCurrentProcess(),
                    self._access, False, self._options|_winapi.DUPLICATE_CLOSE_SOURCE)
            finally:
                _winapi.CloseHandle(proc)
    DupHandle = _PatchedDupHandle
    def _patched_send_handle(conn, handle, destination_pid):
        '''Send a handle over a local connection.'''
        dh = DupHandle(handle, 0, destination_pid, _winapi.DUPLICATE_SAME_ACCESS)
        conn.send(dh)
    send_handle=_patched_send_handle
except ImportError:
    pass

The above seems to fix the problem on my machine by adding an additional options property to the DupHandle object and an options argument to send_handle function.

----------
components: Windows
messages: 352560
nosy: m3rc1fulcameron, paul.moore, steve.dower, tim.golden, zach.ware
priority: normal
severity: normal
status: open
title: Incorrect Argument Order for Calls to _winapi.DuplicateHandle() in multiprocessing.reduction.DupHandle
versions: Python 3.7

_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue38188>
_______________________________________


More information about the New-bugs-announce mailing list