[issue24201] _winreg PyHKEY Type Confusion

eryksun report at bugs.python.org
Fri May 15 16:45:17 CEST 2015


eryksun added the comment:

> wherein pointers can be passed directly in place of PyHKEY 
> instances e.g. _winreg.QueryValue(0x41414141, "")

If a debugger is attached you see the first-chance exception for the access violation. Normally the registry function simply returns ERROR_INVALID_HANDLE (6), which gets raised as an OSError in Python. 

The call took the RPC path because the low bit (1) marks a remote handle, which is actually a pointer to a data structure. RPCRT4!NDRCContextBinding looks for a signature (0xFEDCBA98) to validate this structure.

In this case the attempt raised an access violation, which gets handled by raising another exception with the exception code set to ERROR_INVALID_HANDLE. The same exception gets raised if it can't validate the handle. Subsequently this exception is handled by calling RPCRT4!NdrClientMapCommFault to map the code to a return value. 

For example (x64 ISA):

    >>> _winreg.QueryInfoKey(0x41414141)
    (a2c.828): Access violation - code c0000005 (first chance)
    First chance exceptions are reported before any exception handling.
    This exception may be expected and handled.
    RPCRT4!NDRCContextBinding+0x4:
    000007fe`fefca6e4 81790898badcfe  cmp     dword ptr [rcx+8],0FEDCBA98h ds:00000000`41414148=????????

    0:000> gN
    (a2c.828): Unknown exception - code 00000006 (first chance)
    Breakpoint 0 hit
    RPCRT4!NdrClientMapCommFault:
    000007fe`ff05f010 fff3            push    rbx

    0:000> kc 8
    Call Site
    RPCRT4!NdrClientMapCommFault
    RPCRT4!NdrpClientCall3
    RPCRT4!NdrClientCall3
    ADVAPI32!SafeBaseRegQueryInfoKey
    ADVAPI32!RemoteRegQueryInfoKeyWrapper
    kernel32!TlsGetValue
    ADVAPI32!RegQueryInfoKeyAStub
    python27!PyQueryInfoKey

The exception code is passed in register r8 and gets assigned to the address in r9:

    0:000> r r8, r9
    r8=0000000000000006 r9=000000000021f1d8

    0:000> dd 21f1d8 l1
    00000000`0021f1d8  00000000

    0:000> pt
    RPCRT4!NdrClientMapCommFault+0x80:
    000007fe`ff05f080 c3              ret
    0:000> dd 21f1d8 l1
    00000000`0021f1d8  00000006

This return value gets passed back up the call stack:

    0:000> gu; pt; r rax
    rax=0000000000000006
    0:000> gu; pt; r rax
    rax=0000000000000006
    0:000> gu; pt; r rax
    rax=0000000000000006
    0:000> gu; pt; r rax
    rax=0000000000000006
    0:000> gu; pt; r rax
    rax=0000000000000006
    0:000> r
    rax=0000000000000006 rbx=0000000000e1cda0 rcx=0000000000000000
    rdx=0000000000000000 rsi=0000000000000000 rdi=000000001e1027b0
    rip=00000000779ba204 rsp=000000000021f9d8 rbp=0000000000eb61c8
     r8=000000000021f1d8  r9=0000000000000000 r10=000000000021f1d8
    r11=000000000021f8b0 r12=0000000000e1cda0 r13=0000000000807bb0
    r14=000000001e2b3210 r15=0000000000eb7060
    iopl=0         nv up ei pl nz na po nc
    cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
    kernel32!RegQueryInfoKeyA+0x364:
    00000000`779ba204 c3              ret

Until finally getting raised as a Python exception:

    0:000> g
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    WindowsError: [Error 6] The handle is invalid

The odds are extremely low that someone will pass in an integer address that's flagged as a remote handle (ends in 1) and is a valid, mapped address that contains the RPC handle signature. Even then, it won't reference an actual proxy handle for a remote registry, so it'll just fail farther along the chain. 

I'm sure if a feature exists that someone, somewhere depends on it, so I don't see a reason to change this unless there's a real problem here. Is there a specific technical or security problem that you see here?

----------
nosy: +eryksun

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue24201>
_______________________________________


More information about the Python-bugs-list mailing list