Skip to content

Commit 117aaac

Browse files
committed
fixup! fix(tar) absolute symlink extraction
1 parent ca32156 commit 117aaac

File tree

1 file changed

+21
-11
lines changed

1 file changed

+21
-11
lines changed

unblob/handlers/archive/_safe_tarfile.py

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -77,23 +77,33 @@ def extract(self, tarinfo: tarfile.TarInfo, extract_root: Path): # noqa: C901
7777
# prevent traversal attempts through links
7878
if tarinfo.islnk() or tarinfo.issym():
7979
if Path(tarinfo.linkname).is_absolute():
80-
self.record_problem(
81-
tarinfo,
82-
"Absolute path as link target.",
83-
"Converted to extraction relative path.",
84-
)
8580

8681
def calculate_linkname():
8782
root = extract_root.resolve()
8883
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)
84+
85+
if path.parts[: len(root.parts)] != root.parts:
86+
return None
87+
88+
depth = max(0, len(path.parts) - len(root.parts) - 1)
9389
return ("/".join([".."] * depth) or ".") + tarinfo.linkname
9490

95-
tarinfo.linkname = calculate_linkname()
96-
assert not Path(tarinfo.linkname).is_absolute()
91+
relative_linkname = calculate_linkname()
92+
if relative_linkname is None:
93+
self.record_problem(
94+
tarinfo,
95+
"Absolute path conversion to extraction relative failed - would escape root.",
96+
"Skipped.",
97+
)
98+
return
99+
100+
assert not Path(relative_linkname).is_absolute()
101+
self.record_problem(
102+
tarinfo,
103+
"Absolute path as link target.",
104+
"Converted to extraction relative path.",
105+
)
106+
tarinfo.linkname = relative_linkname
97107

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

0 commit comments

Comments
 (0)