Re: process-deb-once-with-python review
* Niels Thykier <niels@thykier.net>, 2014-07-08, 07:34:
target = os.path.normpath(os.path.join(output_dir,
member.name))
if (not target.startswith(output_dir_stem)
and target != output_dir):
raise ValueError("%s escapes unpack-root" % member.name)
os.path.normpath() doesn't access filesystem, so it won't protect you
from escaping unpack-root via a symlink.
You mean something like:
symlink usr to /etc
extract usr/password (which overwrites /etc/password)
Yes.
That should be fairly trivial to fix by doing a follow up check with
realpath.
realpath() could be racy. If the shipped symlink points into a
world-writable directory (e.g. /tmp/foo), and it is possible to predict
value of output_dir, local attacker could make such a /tmp/foo symlink
that the realpath() test passes, and later switch the /tmp/foo symlink
to something else.
So we probably need something better that realpath().
How about safepath() from the attachment?
[I'll reply to the rest of the mail later.]
--
Jakub Wilk
import errno
import os
import stat
class UnsafePath(Exception):
pass
def safepath(root, path):
comps = path.split('/')
comps.reverse()
if not comps:
raise UnsafePath
if comps[-1] in ('.', ''):
comps.pop()
tpath = root
while comps:
comp = comps.pop()
if comp in ('.', '..', ''):
raise UnsafePath
tpath += '/' + comp
try:
st = os.lstat(tpath)
except OSError as exc:
if exc.errno == errno.ENOENT:
continue
else:
if comps and stat.S_ISDIR(st.st_mode):
continue
raise UnsafePath(path)
return tpath
Reply to: