Skip to content

Commit 6b86b85

Browse files
committed
Test for unsafe files in tarfile.extractall
In addition to that, mark bifrost unbuildable since it's failing on EPEL 9 enablement. Closes-Bug: #1990432 Change-Id: I650fcbc8f773fad8116338f6fb0cf7b4f4f17b33 (cherry picked from commit 3d008b7)
1 parent 4b3998d commit 6b86b85

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

kolla/image/build.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,14 @@ def update_buildargs(self):
468468

469469
def builder(self, image):
470470

471+
def _test_malicious_tarball(archive, path):
472+
tar_file = tarfile.open(archive, 'r|gz')
473+
for n in tar_file.getnames():
474+
if not os.path.abspath(os.path.join(path, n)).startswith(path):
475+
tar_file.close()
476+
self.logger.error(f'Unsafe filenames in archive {archive}')
477+
raise ArchivingError
478+
471479
def make_an_archive(items, arcname, item_child_path=None):
472480
if not item_child_path:
473481
item_child_path = arcname
@@ -480,8 +488,9 @@ def make_an_archive(items, arcname, item_child_path=None):
480488
archives.append(archive_path)
481489
if archives:
482490
for archive in archives:
491+
_test_malicious_tarball(archive, items_path)
483492
with tarfile.open(archive, 'r') as archive_tar:
484-
archive_tar.extractall(path=items_path)
493+
archive_tar.extractall(path=items_path) # nosec
485494
else:
486495
try:
487496
os.mkdir(items_path)

kolla/tests/test_build.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import os
1616
import requests
1717
import sys
18+
import tarfile
19+
import tempfile
1820
from unittest import mock
1921

2022
from kolla.cmd import build as build_cmd
@@ -298,6 +300,46 @@ def test_process_source(self, mock_get, mock_client,
298300
else:
299301
self.assertIsNotNone(get_result)
300302

303+
@mock.patch.dict(os.environ, clear=True)
304+
@mock.patch('docker.APIClient')
305+
def test_malicious_tar(self, mock_client):
306+
tmpdir = tempfile.mkdtemp()
307+
file_name = 'test.txt'
308+
archive_name = 'my_archive.tar.gz'
309+
file_path = os.path.join(tmpdir, file_name)
310+
archive_path = os.path.join(tmpdir, archive_name)
311+
# Ensure the file is read/write by the creator only
312+
saved_umask = os.umask(0o077)
313+
314+
try:
315+
with open(file_path, 'w') as f:
316+
f.write('Hello')
317+
318+
with tarfile.open(archive_path, 'w:gz') as tar:
319+
tar.add(file_path, arcname='../test.txt')
320+
321+
self.dc = mock_client
322+
self.image.plugins = [{
323+
'name': 'fake-image-base-plugin-test',
324+
'type': 'local',
325+
'enabled': True,
326+
'source': archive_path}
327+
]
328+
329+
push_queue = mock.Mock()
330+
builder = build.BuildTask(self.conf, self.image, push_queue)
331+
builder.run()
332+
self.assertFalse(builder.success)
333+
334+
except IOError:
335+
print('IOError')
336+
else:
337+
os.remove(file_path)
338+
os.remove(archive_path)
339+
finally:
340+
os.umask(saved_umask)
341+
os.rmdir(tmpdir)
342+
301343
@mock.patch('os.path.exists')
302344
@mock.patch('os.utime')
303345
@mock.patch('shutil.rmtree')

0 commit comments

Comments
 (0)