@@ -288,26 +288,51 @@ def _download_src(self):
288288 f .write (data )
289289
290290 def _unpack_src (self ):
291- """Unpack tar.gz bundle"""
292- # cleanup
293- if os .path .isdir (self .build_dir ):
294- shutil .rmtree (self .build_dir )
295- os .makedirs (self .build_dir )
296-
297- tf = tarfile .open (self .src_file )
298- name = self .build_template .format (self .version )
299- base = name + '/'
300- # force extraction into build dir
301- members = tf .getmembers ()
302- for member in list (members ):
303- if member .name == name :
304- members .remove (member )
305- elif not member .name .startswith (base ):
306- raise ValueError (member .name , base )
307- member .name = member .name [len (base ):].lstrip ('/' )
308- log .info ("Unpacking files to {}" .format (self .build_dir ))
309- tf .extractall (self .build_dir , members )
310-
291+ """Unpack tar.gz bundle"""
292+ # cleanup
293+ if os .path .isdir (self .build_dir ):
294+ shutil .rmtree (self .build_dir )
295+ os .makedirs (self .build_dir )
296+
297+ tf = tarfile .open (self .src_file )
298+ name = self .build_template .format (self .version )
299+ base = name + '/'
300+ # force extraction into build dir
301+ members = tf .getmembers ()
302+
303+ log .info ("Unpacking files to {}" .format (self .build_dir ))
304+ build_dir_real = os .path .realpath (self .build_dir )
305+
306+ for member in members :
307+ if member .name == name :
308+ continue
309+ elif not member .name .startswith (base ):
310+ raise ValueError (member .name , base )
311+
312+ # Strip the base directory and normalize the path
313+ member .name = member .name [len (base ):].lstrip ('/' )
314+
315+ # Security checks for safe extraction
316+ if member .islnk () or member .issym ():
317+ log .warning ("Skipping symbolic/hard link: {}" .format (member .name ))
318+ continue
319+
320+ # Normalize the member path
321+ normalized_path = os .path .normpath (member .name )
322+
323+ # Check for directory traversal attempts
324+ if normalized_path .startswith ('/' ) or '..' in normalized_path .split (os .sep ):
325+ log .warning ("Skipping potentially malicious member: {}" .format (member .name ))
326+ continue
327+
328+ # Construct final path and validate it's within build directory
329+ final_path = os .path .realpath (os .path .join (self .build_dir , normalized_path ))
330+ if not final_path .startswith (build_dir_real + os .sep ) and final_path != build_dir_real :
331+ log .warning ("Skipping member attempting directory traversal: {}" .format (member .name ))
332+ continue
333+
334+ # Safe extraction
335+ tf .extract (member , self .build_dir )
311336 def _build_src (self , config_args = ()):
312337 """Now build openssl"""
313338 log .info ("Running build in {}" .format (self .build_dir ))
0 commit comments