@@ -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