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