Allow for oslo.concurrency 2.3.0

Currently, stable/liberty has a minimum version constraint on
oslo.concurrency of 2.3.0. The code needed in oslo.concurrency to avoid
CVE-2015-5162 is only present in 2.6.1 and newer versions. This hack is
shamelessly stolen from Nova (I135b5242af1bfdcb0ea09a6fcda21fc03a6fbe7d)
to avoid breaking operators who chose to deploy with the minimum allowed
version of oslo.concurrency.

Change-Id: Iff51c59041e23fa158f7939891c46e9a150883fc
(cherry picked from commit e3ac9c61d0)
This commit is contained in:
Ian Cordasco 2016-12-07 09:52:30 -06:00 committed by Matt Riedemann
parent 46d92cb0ba
commit 9496b9dd83
6 changed files with 96 additions and 15 deletions

View File

@ -152,13 +152,17 @@ class _ImportToFS(task.Task):
path = self.store.add(image_id, data, 0, context=None)[0]
trycmd_kwargs = {}
if utils.QEMU_IMG_PROC_LIMITS is not None:
trycmd_kwargs['prlimit'] = utils.QEMU_IMG_PROC_LIMITS
try:
# NOTE(flaper87): Consider moving this code to a common
# place that other tasks can consume as well.
stdout, stderr = putils.trycmd('qemu-img', 'info',
'--output=json', path,
prlimit=utils.QEMU_IMG_PROC_LIMITS,
log_errors=putils.LOG_ALL_ERRORS)
log_errors=putils.LOG_ALL_ERRORS,
**trycmd_kwargs)
except OSError as exc:
with excutils.save_and_reraise_exception():
msg = (_LE('Failed to execute security checks on the image '

View File

@ -44,12 +44,15 @@ class _Introspect(utils.OptionalTask):
:param image_id: Glance image ID
:param file_path: Path to the file being introspected
"""
trycmd_kwargs = {}
if utils.QEMU_IMG_PROC_LIMITS is not None:
trycmd_kwargs['prlimit'] = utils.QEMU_IMG_PROC_LIMITS
try:
stdout, stderr = putils.trycmd('qemu-img', 'info',
'--output=json', file_path,
prlimit=utils.QEMU_IMG_PROC_LIMITS,
log_errors=putils.LOG_ALL_ERRORS)
log_errors=putils.LOG_ALL_ERRORS,
**trycmd_kwargs)
except OSError as exc:
# NOTE(flaper87): errno == 2 means the executable file
# was not found. For now, log an error and move forward

View File

@ -23,14 +23,22 @@ from glance import i18n
LOG = logging.getLogger(__name__)
_LW = i18n._LW
_LE = i18n._LE
# NOTE(hemanthm): As reported in the bug #1449062, "qemu-img info" calls can
# be exploited to craft DoS attacks by providing malicious input. The process
# limits defined here are protections against such attacks. This essentially
# limits the CPU time and address space used by the process that executes
# "qemu-img info" command to 2 seconds and 1 GB respectively.
QEMU_IMG_PROC_LIMITS = putils.ProcessLimits(cpu_time=2,
address_space=1 * units.Gi)
QEMU_IMG_PROC_LIMITS = None
try:
# NOTE(hemanthm): As reported in the bug #1449062, "qemu-img info" calls
# can be exploited to craft DoS attacks by providing malicious input. The
# process limits defined here are protections against such attacks. This
# essentially limits the CPU time and address space used by the process
# that executes "qemu-img info" command to 2 seconds and 1 GB
# respectively.
QEMU_IMG_PROC_LIMITS = putils.ProcessLimits(cpu_time=2,
address_space=1 * units.Gi)
except Exception:
LOG.error(_LE('Please upgrade to oslo.concurrency version 2.6.1 -- '
'the version presently installed prevents fixing the '
'vulnerability CVE-2015-5162.'))
class OptionalTask(task.Task):

View File

@ -408,6 +408,35 @@ class TestImportTask(test_utils.BaseTestCase):
self.assertTrue(os.path.exists(tmp_image_path))
self._assert_qemu_process_limits(tmock)
def test_import_to_fs_ignores_process_limits(self):
import_fs = import_flow._ImportToFS(self.task.task_id,
self.task_type,
self.task_repo,
'http://example.com/image.qcow2')
with mock.patch.object(script_utils, 'get_image_data_iter') as dmock:
with mock.patch('glance.async.utils.QEMU_IMG_PROC_LIMITS', None):
dmock.return_value = "test"
with mock.patch.object(putils, 'trycmd') as tmock:
tmock.return_value = (json.dumps({
'format': 'qcow2',
}), None)
image_id = UUID1
path = import_fs.execute(image_id)
reader, size = glance_store.get_from_backend(path)
self.assertEqual(4, size)
self.assertEqual(dmock.return_value, "".join(reader))
image_path = os.path.join(self.work_dir, image_id)
tmp_image_path = os.path.join(self.work_dir, image_path)
self.assertTrue(os.path.exists(tmp_image_path))
# NOTE(sigmavirus234): Assert that process limits are
# being ignores for older oslo.concurrency versions.
kw_args = tmock.call_args[1]
self.assertNotIn('prlimit', kw_args)
def test_delete_from_fs(self):
delete_fs = import_flow._DeleteFromFS(self.task.task_id,
self.task_type)

View File

@ -97,6 +97,42 @@ class TestImportTask(test_utils.BaseTestCase):
self.assertEqual(async_utils.QEMU_IMG_PROC_LIMITS,
kw_args.get('prlimit'))
def test_introspect_quietly_refuses_to_apply_process_limits(self):
image_create = introspect._Introspect(self.task.task_id,
self.task_type,
self.img_repo)
self.task_repo.get.return_value = self.task
image_id = mock.sentinel.image_id
image = mock.MagicMock(image_id=image_id)
self.img_repo.get.return_value = image
with mock.patch.object(processutils, 'execute') as exc_mock:
with mock.patch('glance.async.utils.QEMU_IMG_PROC_LIMITS', None):
result = json.dumps({
"virtual-size": 10737418240,
"filename": "/tmp/image.qcow2",
"cluster-size": 65536,
"format": "qcow2",
"actual-size": 373030912,
"format-specific": {
"type": "qcow2",
"data": {
"compat": "0.10"
}
},
"dirty-flag": False
})
exc_mock.return_value = (result, None)
image_create.execute(image, '/test/path.qcow2')
self.assertEqual(10737418240, image.virtual_size)
# NOTE(sigmavirus24): Assert that process limits are being
# ignored when oslo.concurrency is too old.
kw_args = exc_mock.call_args[1]
self.assertNotIn('prlimit', kw_args)
def test_introspect_no_image(self):
image_create = introspect._Introspect(self.task.task_id,
self.task_type,

View File

@ -1,10 +1,11 @@
---
security:
- All ``qemu-img info`` calls are now run under resource
- All ``qemu-img info`` calls will be run under resource
limitations that limit the CPU time and address space
usage of the process running the command to 2 seconds
and 1 GB respectively. This addresses the bug
https://bugs.launchpad.net/glance/+bug/1449062
usage of the process if oslo.concurrency is at least
version 2.6.1. ``qemu-img info`` calls are now limited
to 2 seconds and 1 GB respectively. This addresses the
bug https://bugs.launchpad.net/glance/+bug/1449062
Current usage of "qemu-img" is limited to Glance tasks.
In the Mitaka release, tasks by default will only be