Does This Scare You?

eryk sun eryksun at gmail.com
Sat Aug 27 00:11:06 EDT 2016


On Fri, Aug 26, 2016 at 11:28 AM, Jon Ribbens <jon+usenet at unequivocal.eu> wrote:
> On 2016-08-24, Chris Angelico <rosuav at gmail.com> wrote:
>> On Thu, Aug 25, 2016 at 7:00 AM, eryk sun <eryksun at gmail.com> wrote:
>>> I discovered why "Logs/con.txt" isn't working right in Windows 7,
>>> while "Logs/nul.txt" does get redirected correctly to r"\\.\nul".
>>> Prior to Windows 8 the console doesn't use an NT device, so the base
>>> API has a function named BaseIsThisAConsoleName that looks for names
>>> such as r"\\.CON", r"\\.CONIN$", "CON", or r"C:\Temp\con.txt" and
>>> returns either "CONIN$" or "CONOUT$" if there's a match. A match for
>>> just "CON" maps to one or the other of the latter depending on whether
>>> read or write access is desired.
>>
>> See? This is why *even after I tested it* I wasn't sure I was right!
>> The rules are... complicated.
>
> Hence my doubts about this function - it has almost no chance of not
> being broken, potentially leading to whatever code was using it having
> security holes. Perhaps it should be deprecated or at least attract a
> large caveat in the documentation.

I agree that the docs need a warning that the behavior of paths
containing legacy DOS device names is inconsistent between versions of
Windows and that the rules that Windows uses aren't explicitly
documented.

There's another inconsistency if Python is run under ReactOS (and
probably Wine, too). The ReactOS equivalent to BaseIsThisAConsoleName
is IntCheckForConsoleFileName, which doesn't have the (buggy) speed
hack that Windows uses to gate the more expensive call to
RtlIsDosDeviceName_U:

    http://preview.tinyurl.com/reactos-console-c-71210

Also note the comment on line 354 that "C:\some_path\CONIN$" should
open the console. This highlights yet another problem with the current
pathlib check: it doesn't reserve the names "CONIN$" and "CONOUT$".

Actually, the comment is technically wrong for versions prior to
Windows 8. The old implementation of RtlIsDosDeviceName_U only checks
for "CON", not "CONIN$" or "CONOUT$". The latter two devices aren't
inherited from DOS. They were added to the Windows API to allow
opening console handles with both read and write access, e.g. to be
able to call WriteConsoleInput and ReadConsoleOutput. "CON" doesn't
allow this. However, the base API does allow opening plain "CONIN$"
and "CONOUT$" without the "\\.\" device namespace prefix, so those
names are at least reserved for the current directory.

The problem is more encompassing for Windows 8+, which has a real
console device. It no longer calls BaseIsThisAConsoleName to redirect
CreateFile to OpenConsoleW. Instead it passes the regular NT paths
r"\??\CON", r"\??\CONIN$", or r"\??\CONOUT$" to the NtCreateFile
system call, which resolves the object manager symbolic links
respectively to r"\Device\ConDrv\Console",
r"\Device\ConDrv\CurrentIn", and r"\Device\ConDrv\CurrentOut". As part
of the redesign, the base API moved the check for "CONIN$" and
"CONOUT$" into the NT runtime library function
RtlpIsDosDeviceName_Ustr. Now "CON", "CONIN$", and "CONOUT$" are
reserved in every directory, just like how it's always worked for NUL,
AUX, PRN, COM1-9, and LPT1-9. For example:

Windows 10

    >>> print(os.path.abspath('C:/Temp/conout$  : spam . eggs'))
    \\.\conout$

Windows 7

    >>> print(os.path.abspath('C:/Temp/conout$  : spam . eggs'))
    C:\Temp\conout$  : spam . eggs



More information about the Python-list mailing list