Issue 22147: PosixPath() constructor should not accept strings with embedded NUL bytes (original) (raw)

This is listed as a python3.4 issue even though I only tried this on the python2.7 backport because I don't have a python3 handy, but I was not able to find an indication, either here or elsewhere, that this had been addressed. Please forgive me if it has.

The pathlib.PosixPath() constructor currently accepts strings containing NUL bytes, converting them into paths containing NUL bytes. POSIX specifies that a pathname may not contain embedded NULs.

It appears that PosixPath.stat() is checking for embedded NUL, but PosixPath.open() is not! For safety, constructing a PosixPath with embedded NULs should be forbidden.

pathlib.WindowsPath() should probably receive the same treatment.

Observed behavior:


>>> from pathlib import Path

>>> Path("\0I'm not malicious, I'm mischievous!")
PosixPath("\x00I'm not malicious, I'm mischievous!")

>>> _.open()
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File ".../site-packages/pathlib.py", line 1077, in open
 return io.open(str(self), mode, buffering, encoding, errors, newline)
IOError: [Errno 2] No such file or directory: ''

>>> Path('/') / _
PosixPath("/\x00I'm not malicious, I'm mischievous!")

>>> _.open()
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File ".../site-packages/pathlib.py", line 1077, in open
 return io.open(str(self), mode, buffering, encoding, errors, newline)
IOError: [Errno 21] Is a directory: "/\x00I'm not malicious, I'm mischievous!"

>>> _.stat()
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File ".../site-packages/pathlib.py", line 1051, in stat
 return self._accessor.stat(self)
 File ".../site-packages/pathlib.py", line 346, in wrapped
 return strfunc(str(pathobj), *args)
TypeError: must be encoded string without NULL bytes, not str

>>> p1 = Path('/etc/passwd\0/hello.txt').open()

>>> p2 = Path('/etc/passwd').open()

>>> os.path.sameopenfile(p1.fileno(), p2.fileno())
True  # DANGER WILL ROBINSON!

Expected behavior:


>>> Path("/\0I'm not malicious, I'm mischievous!")
...
ValueError: Illegal byte '\x00' in path