@@ -77,23 +77,33 @@ def extract(self, tarinfo: tarfile.TarInfo, extract_root: Path): # noqa: C901
77
77
# prevent traversal attempts through links
78
78
if tarinfo .islnk () or tarinfo .issym ():
79
79
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
- )
85
80
86
81
def calculate_linkname ():
87
82
root = extract_root .resolve ()
88
83
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 )
93
89
return ("/" .join ([".." ] * depth ) or "." ) + tarinfo .linkname
94
90
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
97
107
98
108
resolved_path = (extract_root / tarinfo .name ).parent / tarinfo .linkname
99
109
if not is_safe_path (basedir = extract_root , path = resolved_path ):
0 commit comments