11"""File extraction related functions."""
2+ # ruff: noqa
3+
24import errno
35import os
46from pathlib import Path
1517FILE_PERMISSION_MASK = 0o644
1618DIR_PERMISSION_MASK = 0o775
1719
20+ # re-exported, or unused symbols
21+ __all__ = [
22+ "is_safe_path" ,
23+ "MaliciousSymlinkRemoved" ,
24+ "fix_symlink" ,
25+ "is_recursive_link" ,
26+ ]
27+
1828
1929def carve_chunk_to_file (carve_path : Path , file : File , chunk : Chunk ):
2030 """Extract valid chunk to a file, which we then pass to another tool to extract it."""
@@ -57,8 +67,11 @@ def sanitize_symlink_target(base_dir, current_dir, target):
5767 # Normalize all paths to their absolute forms
5868 base_dir_abs = os .path .abspath (base_dir )
5969 current_dir_abs = os .path .abspath (current_dir )
60- target_abs = os .path .abspath (os .path .join (current_dir , target )) \
61- if not os .path .isabs (target ) else os .path .abspath (target )
70+ target_abs = (
71+ os .path .abspath (os .path .join (current_dir , target ))
72+ if not os .path .isabs (target )
73+ else os .path .abspath (target )
74+ )
6275
6376 # Check if the target is absolute and within the base_dir
6477 if os .path .isabs (target ):
@@ -67,7 +80,13 @@ def sanitize_symlink_target(base_dir, current_dir, target):
6780 else :
6881 # Target is absolute but outside base_dir - we'll pretend base_dir is our root
6982 # and adjust the target to be within base_dir
70- abs = base_dir + "/" + os .path .relpath (target_abs , os .path .commonpath ([target_abs , base_dir_abs ]))
83+ abs = (
84+ base_dir
85+ + "/"
86+ + os .path .relpath (
87+ target_abs , os .path .commonpath ([target_abs , base_dir_abs ])
88+ )
89+ )
7190 # We want to return the relative path from current_dir to the adjusted target
7291 return os .path .relpath (abs , current_dir_abs )
7392 else :
@@ -82,18 +101,21 @@ def sanitize_symlink_target(base_dir, current_dir, target):
82101 # relative path from /host/test_archive/foo to /host/test_archive/etc/passwd
83102 # without escaping /host/test_archive
84103
85- for drop_count in range (0 , len (target .split ('/' ))):
104+ for drop_count in range (len (target .split ("/" ))):
86105 # We drop '..'s from the target by prepending placeholder directories until we get something valid
87106 abs = current_dir + "/" + "/" .join (["foo" ] * drop_count ) + target
88107 resolved = os .path .abspath (abs )
89108 if resolved .startswith (base_dir_abs ):
90109 break
91110 else :
92- raise ValueError (f"Could not resolve symlink target { target } within base_dir { base_dir } " )
111+ raise ValueError (
112+ f"Could not resolve symlink target { target } within base_dir { base_dir } "
113+ )
93114
94115 # We need to add the /placeholder to the relative path because we need
95116 # to act like a file within base_dir is our root (as opposed to base_dir itself)
96- return os .path .relpath (resolved , base_dir_abs + '/placeholder' )
117+ return os .path .relpath (resolved , base_dir_abs + "/placeholder" )
118+
97119
98120def fix_extracted_directory (outdir : Path , task_result : TaskResult ):
99121 def _fix_extracted_directory (directory : Path ):
@@ -103,7 +125,7 @@ def _fix_extracted_directory(directory: Path):
103125 base_dir = os .path .abspath (outdir )
104126 for root , dirs , files in os .walk (base_dir , topdown = True ):
105127 fix_permission (Path (root ))
106- for name in dirs + files :
128+ for name in dirs + files :
107129 try :
108130 full_path = os .path .join (root , name )
109131 if os .path .islink (full_path ):
@@ -113,9 +135,15 @@ def _fix_extracted_directory(directory: Path):
113135 if new_target != target :
114136 os .remove (full_path )
115137 os .symlink (new_target , full_path )
116- logger .info ("Updated symlink" , path = full_path , target = new_target )
138+ logger .info (
139+ "Updated symlink" , path = full_path , target = new_target
140+ )
117141 else :
118- logger .debug ("Symlink is already sanitized" , path = full_path , target = new_target )
142+ logger .debug (
143+ "Symlink is already sanitized" ,
144+ path = full_path ,
145+ target = new_target ,
146+ )
119147 except OSError as e :
120148 if e .errno == errno .ENAMETOOLONG :
121149 continue
0 commit comments