8
8
9
9
from .file_utils import carve , is_safe_path
10
10
from .models import Chunk , File , PaddingChunk , TaskResult , UnknownChunk , ValidChunk
11
- from .report import MaliciousSymlinkRemoved
12
11
13
12
logger = get_logger ()
14
13
15
14
FILE_PERMISSION_MASK = 0o644
16
15
DIR_PERMISSION_MASK = 0o775
17
16
17
+ _ = is_safe_path # it is re-exported
18
+
18
19
19
20
def carve_chunk_to_file (carve_path : Path , file : File , chunk : Chunk ):
20
21
"""Extract valid chunk to a file, which we then pass to another tool to extract it."""
@@ -57,8 +58,11 @@ def sanitize_symlink_target(base_dir, current_dir, target):
57
58
# Normalize all paths to their absolute forms
58
59
base_dir_abs = os .path .abspath (base_dir )
59
60
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 )
61
+ target_abs = (
62
+ os .path .abspath (os .path .join (current_dir , target ))
63
+ if not os .path .isabs (target )
64
+ else os .path .abspath (target )
65
+ )
62
66
63
67
# Check if the target is absolute and within the base_dir
64
68
if os .path .isabs (target ):
@@ -67,7 +71,13 @@ def sanitize_symlink_target(base_dir, current_dir, target):
67
71
else :
68
72
# Target is absolute but outside base_dir - we'll pretend base_dir is our root
69
73
# 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 ]))
74
+ abs = (
75
+ base_dir
76
+ + "/"
77
+ + os .path .relpath (
78
+ target_abs , os .path .commonpath ([target_abs , base_dir_abs ])
79
+ )
80
+ )
71
81
# We want to return the relative path from current_dir to the adjusted target
72
82
return os .path .relpath (abs , current_dir_abs )
73
83
else :
@@ -82,18 +92,21 @@ def sanitize_symlink_target(base_dir, current_dir, target):
82
92
# relative path from /host/test_archive/foo to /host/test_archive/etc/passwd
83
93
# without escaping /host/test_archive
84
94
85
- for drop_count in range (0 , len (target .split ('/' ))):
95
+ for drop_count in range (len (target .split ("/" ))):
86
96
# We drop '..'s from the target by prepending placeholder directories until we get something valid
87
97
abs = current_dir + "/" + "/" .join (["foo" ] * drop_count ) + target
88
98
resolved = os .path .abspath (abs )
89
99
if resolved .startswith (base_dir_abs ):
90
100
break
91
101
else :
92
- raise ValueError (f"Could not resolve symlink target { target } within base_dir { base_dir } " )
102
+ raise ValueError (
103
+ f"Could not resolve symlink target { target } within base_dir { base_dir } "
104
+ )
93
105
94
106
# We need to add the /placeholder to the relative path because we need
95
107
# 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' )
108
+ return os .path .relpath (resolved , base_dir_abs + "/placeholder" )
109
+
97
110
98
111
def fix_extracted_directory (outdir : Path , task_result : TaskResult ):
99
112
def _fix_extracted_directory (directory : Path ):
@@ -103,7 +116,7 @@ def _fix_extracted_directory(directory: Path):
103
116
base_dir = os .path .abspath (outdir )
104
117
for root , dirs , files in os .walk (base_dir , topdown = True ):
105
118
fix_permission (Path (root ))
106
- for name in dirs + files :
119
+ for name in dirs + files :
107
120
try :
108
121
full_path = os .path .join (root , name )
109
122
if os .path .islink (full_path ):
@@ -113,9 +126,15 @@ def _fix_extracted_directory(directory: Path):
113
126
if new_target != target :
114
127
os .remove (full_path )
115
128
os .symlink (new_target , full_path )
116
- logger .info ("Updated symlink" , path = full_path , target = new_target )
129
+ logger .info (
130
+ "Updated symlink" , path = full_path , target = new_target
131
+ )
117
132
else :
118
- logger .debug ("Symlink is already sanitized" , path = full_path , target = new_target )
133
+ logger .debug (
134
+ "Symlink is already sanitized" ,
135
+ path = full_path ,
136
+ target = new_target ,
137
+ )
119
138
except OSError as e :
120
139
if e .errno == errno .ENAMETOOLONG :
121
140
continue
0 commit comments