1
+ #!/usr/bin/python
2
+
3
+ import sys
4
+ import tarfile
5
+ import tempfile
6
+ import os
7
+ from tarfile import TarFile
8
+ from contextlib import closing , contextmanager
9
+ import subprocess
10
+ import os .path
11
+
12
+ unsafe_filename_tar = sys .argv [2 ]
13
+ safe_filename_tar = "safe_path.tar"
14
+
15
+ tar = tarfile .open (unsafe_filename_tar )
16
+ result = []
17
+ for member in tar :
18
+ if ".." in member .name :
19
+ raise ValueError ("Path in member name !!!" )
20
+ result .append (member )
21
+ path = unsafe_filename_tar
22
+ tar .extractall (path = path , members = result )
23
+ tar .close ()
24
+
25
+
26
+ def members_filter1 (tarfile ):
27
+ result = []
28
+ for member in tarfile :
29
+ if '../' in member .name :
30
+ print ('Member name container directory traversal sequence' )
31
+ continue
32
+ elif member .issym () or member .islnk ():
33
+ print ('Symlink to external resource' )
34
+ continue
35
+ result .append (member )
36
+ return result
37
+
38
+ tar = tarfile .open (unsafe_filename_tar )
39
+ tar .extractall (path = tempfile .mkdtemp (), members = members_filter1 (tar ))
40
+ tar .close ()
41
+
42
+
43
+ with tarfile .open (unsafe_filename_tar ) as tar :
44
+ for entry in tar :
45
+ if ".." in entry .name :
46
+ raise ValueError ("Illegal tar archive entry" )
47
+ tar .extract (entry , "/tmp/unpack/" )
48
+
49
+
50
+ def _validate_archive_name (name , target ):
51
+ if not os .path .abspath (os .path .join (target , name )).startswith (target + os .path .sep ):
52
+ raise ValueError (f"Provided language pack contains invalid name { name } " )
53
+
54
+ with tarfile .open (unsafe_filename_tar ) as tar :
55
+ target = "/tmp/unpack"
56
+ for entry in tar :
57
+ _validate_archive_name (entry .name , target )
58
+ tar .extract (entry , target )
59
+
60
+
61
+ def members_filter2 (tarfile ):
62
+ result = []
63
+ for member in tarfile .getmembers ():
64
+ if '../' in member .name :
65
+ print ('Member name container directory traversal sequence' )
66
+ continue
67
+ elif (member .issym () or member .islnk ()) and ('../' in member .linkname ):
68
+ print ('Symlink to external resource' )
69
+ continue
70
+ result .append (member )
71
+ return result
72
+
73
+ tar = tarfile .open (unsafe_filename_tar )
74
+ tar .extractall (path = tempfile .mkdtemp (), members = members_filter2 (tar ))
75
+ tar .close ()
76
+
77
+
78
+ def _validate_tar_info (info , target ):
79
+ _validate_archive_name (info .name , target )
80
+ if not (info .isfile () or info .isdir ()):
81
+ raise ValueError ("Provided language pack contains invalid file type" )
82
+
83
+ def _validate_archive_name (name , target ):
84
+ if not os .path .abspath (os .path .join (target , name )).startswith (target + os .path .sep ):
85
+ raise ValueError (f"Provided language pack contains invalid name { name } " )
86
+
87
+ target = "/tmp/unpack"
88
+ with tarfile .open (unsafe_filename_tar , "r" ) as tar :
89
+ for info in tar .getmembers ():
90
+ _validate_tar_info (info , target )
91
+ tar .extractall (target )
92
+
93
+
94
+ def members_filter3 (tarfile ):
95
+ result = []
96
+ for member in tarfile .getmembers ():
97
+ if '../' in member .name :
98
+ print ('Member name container directory traversal sequence' )
99
+ continue
100
+ elif member .issym () or member .islnk ():
101
+ print ('Symlink to external resource' )
102
+ continue
103
+ result .append (member )
104
+ return result
105
+
106
+ tar = tarfile .open (unsafe_filename_tar )
107
+ tar .extractall (path = tempfile .mkdtemp (), members = members_filter3 (tar ))
108
+ tar .close ()
109
+
110
+
111
+ tar = tarfile .open (unsafe_filename_tar )
112
+ tarf = tar .getmembers ()
113
+ for f in tarf :
114
+ if not f .issym ():
115
+ tar .extractall (path = tempfile .mkdtemp (), members = [f ])
116
+ tar .close ()
117
+
118
+
119
+ class MKTar (TarFile ):
120
+ pass
121
+
122
+ tarball = unsafe_filename_tar
123
+ with MKTar .open (name = tarball ) as tar :
124
+ for entry in tar :
125
+ tar ._extract_member (entry , entry .name )
126
+
127
+
128
+ tarball = unsafe_filename_tar
129
+ with tarfile .open (tarball ) as tar :
130
+ tar .extractall ()
131
+
132
+
133
+ tar = tarfile .open (unsafe_filename_tar )
134
+ tar .extractall (path = tempfile .mkdtemp (), members = None )
135
+
136
+
137
+ class MKTar (tarfile .TarFile ):
138
+ pass
139
+
140
+ tarball = unsafe_filename_tar
141
+ with MKTar .open (name = tarball ) as tar :
142
+ for entry in tar :
143
+ tar ._extract_member (entry , entry .name )
144
+
145
+
146
+ @contextmanager
147
+ def py2_tarxz (filename ):
148
+ with tempfile .TemporaryFile () as tmp :
149
+ subprocess .check_call (["xz" , "-dc" , filename ], stdout = tmp .fileno ())
150
+ tmp .seek (0 )
151
+ with closing (tarfile .TarFile (fileobj = tmp )) as tf :
152
+ yield tf
153
+
154
+ def unpack_tarball (tar_filename , dest ):
155
+ if sys .version_info [0 ] < 3 and tar_filename .endswith ('.xz' ):
156
+ # Py 2.7 lacks lzma support
157
+ tar_cm = py2_tarxz (tar_filename )
158
+ else :
159
+ tar_cm = closing (tarfile .open (tar_filename ))
160
+
161
+ base_dir = None
162
+ with tar_cm as tarc :
163
+ for member in tarc :
164
+ base_name = member .name .split ('/' )[0 ]
165
+ if base_dir is None :
166
+ base_dir = base_name
167
+ elif base_dir != base_name :
168
+ print ('Unexpected path in %s: %s' % (tar_filename , base_name ))
169
+ tarc .extractall (dest )
170
+ return os .path .join (dest , base_dir )
171
+
172
+ unpack_tarball (unsafe_filename_tar , "/tmp/unpack" )
173
+
174
+
175
+ tarball = unsafe_filename_tar
176
+ with tarfile .open (name = tarball ) as tar :
177
+ for entry in tar :
178
+ tar ._extract_member (entry , entry .name )
179
+
180
+
181
+ tarball = unsafe_filename_tar
182
+ with tarfile .open (name = tarball ) as tar :
183
+ for entry in tar :
184
+ tar .extract (entry , "/tmp/unpack/" )
185
+
186
+
187
+ tarball = unsafe_filename_tar
188
+ tar = tarfile .open (tarball )
189
+ tar .extractall ("/tmp/unpack/" )
190
+
191
+
192
+ tarball = unsafe_filename_tar
193
+ with tarfile .open (tarball , "r" ) as tar :
194
+ tar .extractall (path = "/tmp/unpack/" , members = tar )
195
+
196
+
197
+ def members_filter4 (tarfile ):
198
+ result = []
199
+ for member in tarfile .getmembers ():
200
+ if member .issym () or member .islnk ():
201
+ print ('Symlink to external resource' )
202
+ continue
203
+ result .append (member )
204
+ return result
205
+ tar = tarfile .open (unsafe_filename_tar )
206
+ tar .extractall (path = tempfile .mkdtemp (), members = members_filter4 (tar ))
207
+ tar .close ()
208
+
209
+
210
+ with tarfile .open (unsafe_filename_tar , "r" ) as tar :
211
+ tar .extractall (path = "/tmp/unpack" )
212
+
213
+
214
+ def members_filter5 (tarfile ):
215
+ result = []
216
+ for member in tarfile .getmembers ():
217
+ if member .issym ():
218
+ print ('Symlink to external resource' )
219
+ continue
220
+ result .append (member )
221
+ return result
222
+ tar = tarfile .open (unsafe_filename_tar )
223
+ tar .extractall (path = tempfile .mkdtemp (), members = members_filter5 (tar ))
224
+ tar .close ()
225
+
226
+
227
+ filename = unsafe_filename_tar
228
+ tmp_dir = "/tmp/"
229
+
230
+ read_type = "r:gz" if filename .endswith ("tgz" ) else "r"
231
+ with tarfile .open (filename , read_type ) as corpus_tar :
232
+ members = []
233
+ for f in corpus_tar :
234
+ if not os .path .isfile (os .path .join (tmp_dir , f .name )):
235
+ members .append (f )
236
+ corpus_tar .extractall (tmp_dir , members = members )
237
+
238
+
239
+ def members_filter6 (tarfile ):
240
+ result = []
241
+ for member in tarfile .getmembers ():
242
+ if not member .isreg ():
243
+ print ('Symlink to external resource' )
244
+ continue
245
+ result .append (member )
246
+ return result
247
+ tar = tarfile .open (filename )
248
+ tar .extractall (path = tempfile .mkdtemp (), members = members_filter6 (tar ))
249
+ tar .close ()
250
+
251
+
252
+ archive_path = unsafe_filename_tar
253
+ target_dir = "/tmp/unpack"
254
+ tarfile .open (archive_path , "r" ).extractall (path = target_dir )
255
+
256
+
257
+ tarball = unsafe_filename_tar
258
+ with tarfile .open (tarball ) as tar :
259
+ for entry in tar :
260
+ if entry .isfile ():
261
+ tar .extract (entry , "/tmp/unpack/" )
262
+
263
+
264
+ with tarfile .open (unsafe_filename_tar ) as tar :
265
+ for entry in tar :
266
+ if entry .name .startswith ("/" ):
267
+ raise ValueError ("Illegal tar archive entry" )
268
+ tar .extract (entry , "/tmp/unpack/" )
269
+
270
+ tarball = unsafe_filename_tar
271
+ with tarfile .TarFile (tarball , mode = "r" ) as tar :
272
+ for entry in tar :
273
+ if entry .isfile ():
274
+ tar .extract (entry , "/tmp/unpack/" )
275
+
276
+ with tarfile .open (unsafe_filename_tar ) as tar :
277
+ for entry in tar :
278
+ if os .path .isabs (entry .name ):
279
+ raise ValueError ("Illegal tar archive entry" )
280
+ tar .extract (entry , "/tmp/unpack/" )
281
+
282
+
283
+ with tarfile .TarFile (unsafe_filename_tar , mode = "r" ) as tar :
284
+ tar .extractall (path = "/tmp/unpack" )
285
+
286
+
287
+ tar = tarfile .open (filename )
288
+ tar .extractall (path = tempfile .mkdtemp (), members = tar .getmembers ())
289
+ tar .close ()
290
+
291
+
292
+ tar = tarfile .open (unsafe_filename_tar )
293
+ tar .extractall (path = tempfile .mkdtemp (), members = None )
294
+
295
+
296
+ tar .extractall (path = tempfile .mkdtemp (), members = members_filter4 (tar ))
297
+ tar .close ()
298
+
299
+
300
+ with tarfile .TarFile (unsafe_filename_tar , mode = "r" ) as tar :
301
+ tar .extractall (path = "/tmp/unpack/" , members = tar )
302
+
303
+
304
+ tar = tarfile .open (unsafe_filename_tar )
305
+ result = []
306
+ for member in tar :
307
+ if member .issym ():
308
+ raise ValueError ("But it is a symlink" )
309
+ result .append (member )
310
+ tar .extractall (path = tempfile .mkdtemp (), members = result )
311
+ tar .close ()
312
+
313
+
314
+ archive_path = unsafe_filename_tar
315
+ target_dir = "/tmp/unpack"
316
+ tarfile .TarFile (unsafe_filename_tar , mode = "r" ).extractall (path = target_dir )
0 commit comments