Sanitize EC2 manifests and image tarballs

Prevent potential directory traversal with malicious EC2 image tarballs,
by making sure the tarfile is safe before unpacking it. Fixes bug 894755

Prevent potential directory traversal with malicious file names in
EC2 image manifests. Fixes bug 885167

Change-Id: If6109047307bd6e654ee9d1254f0d7f31cf741c1
This commit is contained in:
Thierry Carrez 2011-12-01 17:54:16 +01:00
parent 1c0859283f
commit ad3241929e
5 changed files with 23 additions and 1 deletions

View File

@ -37,6 +37,7 @@ include nova/tests/bundle/1mb.part.0
include nova/tests/bundle/1mb.part.1
include nova/tests/api/ec2/public_key/*
include nova/tests/db/nova.austin.sqlite
include nova/tests/image/*.tar.gz
include plugins/xenapi/README
include plugins/xenapi/etc/xapi.d/plugins/objectstore
include plugins/xenapi/etc/xapi.d/plugins/pluginlib_nova.py

View File

@ -155,7 +155,7 @@ class S3ImageService(object):
@staticmethod
def _download_file(bucket, filename, local_dir):
key = bucket.get_key(filename)
local_filename = os.path.join(local_dir, filename)
local_filename = os.path.join(local_dir, os.path.basename(filename))
key.get_contents_to_filename(local_filename)
return local_filename
@ -387,8 +387,19 @@ class S3ImageService(object):
{'image_file': encrypted_filename,
'err': err})
@staticmethod
def _test_for_malicious_tarball(path, filename):
"""Raises exception if extracting tarball would escape extract path"""
tar_file = tarfile.open(filename, 'r|gz')
for n in tar_file.getnames():
if not os.path.abspath(os.path.join(path, n)).startswith(path):
tar_file.close()
raise exception.Error(_('Unsafe filenames in image'))
tar_file.close()
@staticmethod
def _untarzip_image(path, filename):
S3ImageService._test_for_malicious_tarball(path, filename)
tar_file = tarfile.open(filename, 'r|gz')
tar_file.extractall(path)
image_file = tar_file.getnames()[0]

BIN
nova/tests/image/abs.tar.gz Normal file

Binary file not shown.

BIN
nova/tests/image/rel.tar.gz Normal file

Binary file not shown.

View File

@ -15,6 +15,8 @@
# License for the specific language governing permissions and limitations
# under the License.
import os
from nova import context
import nova.db.api
from nova import exception
@ -130,3 +132,11 @@ class TestS3ImageService(test.TestCase):
{'device_name': '/dev/sdb0',
'no_device': True}]
self.assertEqual(block_device_mapping, expected_bdm)
def test_s3_malicious_tarballs(self):
self.assertRaises(exception.Error,
self.image_service._test_for_malicious_tarball,
"/unused", os.path.join(os.path.dirname(__file__), 'abs.tar.gz'))
self.assertRaises(exception.Error,
self.image_service._test_for_malicious_tarball,
"/unused", os.path.join(os.path.dirname(__file__), 'rel.tar.gz'))