Skip to content

Commit bbd75bb

Browse files
fix(tar) absolute symlink extraction
Absolute targets were converted before, but it was too simple to be right other than when the link target was in the same directory. With this change absolute symlinks like /sbin/ls -> /bin/busybox are converted to /sbin/ls -> ../bin/busybox Co-authored-by: Andrew Fasano <fasano@mit.edu>
1 parent 3a4549b commit bbd75bb

File tree

1 file changed

+13
-2
lines changed

1 file changed

+13
-2
lines changed

unblob/handlers/archive/_safe_tarfile.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def extract(self, tarinfo: tarfile.TarInfo, extract_root: Path): # noqa: C901
6363
"Absolute path.",
6464
"Converted to extraction relative path.",
6565
)
66-
tarinfo.name = f"./{tarinfo.name}"
66+
tarinfo.name = str(Path(tarinfo.name).relative_to("/"))
6767

6868
# prevent traversal attempts through file name
6969
if not is_safe_path(basedir=extract_root, path=extract_root / tarinfo.name):
@@ -82,7 +82,18 @@ def extract(self, tarinfo: tarfile.TarInfo, extract_root: Path): # noqa: C901
8282
"Absolute path as link target.",
8383
"Converted to extraction relative path.",
8484
)
85-
tarinfo.linkname = f"./{tarinfo.linkname}"
85+
86+
def calculate_linkname():
87+
root = extract_root.resolve()
88+
path = (extract_root / tarinfo.name).resolve()
89+
common_path = Path(os.path.commonpath([root, path]))
90+
# normally root == common_path
91+
# if it is not, the output will be bad
92+
depth = max(0, len(path.parts) - len(common_path.parts) - 1)
93+
return ("/".join([".."] * depth) or ".") + tarinfo.linkname
94+
95+
tarinfo.linkname = calculate_linkname()
96+
assert not Path(tarinfo.linkname).is_absolute()
8697

8798
resolved_path = (extract_root / tarinfo.name).parent / tarinfo.linkname
8899
if not is_safe_path(basedir=extract_root, path=resolved_path):

0 commit comments

Comments
 (0)