Author eryksun
Recipients eryksun, paul.moore, steve.dower, tim.golden, zach.ware
Date 2017-03-06.11:26:56
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <>
The implementation of nt._getfinalpathname leaks a File handle if calling GetFinalPathNameByHandle fails. The latter function is practically guaranteed to fail when resolving the path for a non-file-system device. It also fails when VOLUME_NAME_DOS is requested for a volume GUID path that isn't currently mounted as either a DOS drive letter or an NTFS junction. In this case requesting VOLUME_NAME_GUID should work.

For example, when I try calling _getfinalpathname to resolve the device paths \\?\MAILSLOT, \\?\PIPE, \\?\UNC, \\?\C:, \\?\PhysicalDrive0, \\?\NUL, \\?\CONIN$, and \\?\COM1, I get the following list of leaked handles:

      0x168 File                  \Device\Mailslot
      0x16c File                  \Device\NamedPipe
      0x178 File                  \Device\Mup
      0x17c File                  \Device\HarddiskVolume2
      0x180 File                  \Device\Harddisk0\DR0
      0x18c File                  \Device\Null
      0x194 File                  \Device\ConDrv
      0x198 File                  \Device\Serial0

(The above is from a context manager that checks for leaked handles using ctypes to call the PssCaptureSnapshot API, which was introduced in Windows 8.1. I think Process Snapshotting is the only Windows API that uses the kernel's ability to fork a clone of a process.) 

The reason that GetFinalPathNameByHandle fails in these cases is that the information classes it queries are typically only serviced by file systems. Other I/O devices (e.g. disk and volume devices) will fail these I/O requests. It happens that GetFinalPathNameByHandle starts with an NtQueryObject request that succeeds in these cases (it's the source of the above native NT device names), but it doesn't stop there. It continues requesting information from the device and the mount-point manager until it either has everything or a request fails.

Also, in os__getfinalpathname_impl, I notice that it's switching from VOLUME_NAME_NT in the first call that's used to get the buffer size to VOLUME_NAME_DOS in the second call. It should use VOLUME_NAME_DOS in both cases, or better yet, add a keyword-only argument to select a different volume-name style (i.e. None, DOS, GUID, or NT).
Date User Action Args
2017-03-06 11:26:57eryksunsetrecipients: + eryksun, paul.moore, tim.golden, zach.ware, steve.dower
2017-03-06 11:26:57eryksunsetmessageid: <>
2017-03-06 11:26:57eryksunlinkissue29734 messages
2017-03-06 11:26:56eryksuncreate