Limit memory & CPU when running qemu-img info

It was found that a modified or corrupted image file can cause a DoS
on the host when getting image info with qemu-img.

This uses the newer 'prlimit' parameter for oslo.concurrency execute
to set an address space limit of 1GB and CPU time limit of 2 seconds
when running the qemu-img info command.

Change-Id: If5b7129b266ef065642bc7898ce9dcf93722a053
Closes-bug: #1449062
(cherry picked from commit 8547444775)
This commit is contained in:
Sean McGinnis 2016-09-22 15:31:37 -05:00
parent ca42539a5b
commit 455b318ced
3 changed files with 19 additions and 4 deletions

View File

@ -54,13 +54,18 @@ image_helper_opts = [cfg.StrOpt('image_conversion_dir',
CONF = cfg.CONF CONF = cfg.CONF
CONF.register_opts(image_helper_opts) CONF.register_opts(image_helper_opts)
QEMU_IMG_LIMITS = processutils.ProcessLimits(
cpu_time=2,
address_space=1 * units.Gi)
def qemu_img_info(path, run_as_root=True): def qemu_img_info(path, run_as_root=True):
"""Return a object containing the parsed output from qemu-img info.""" """Return a object containing the parsed output from qemu-img info."""
cmd = ('env', 'LC_ALL=C', 'qemu-img', 'info', path) cmd = ('env', 'LC_ALL=C', 'qemu-img', 'info', path)
if os.name == 'nt': if os.name == 'nt':
cmd = cmd[2:] cmd = cmd[2:]
out, _err = utils.execute(*cmd, run_as_root=run_as_root) out, _err = utils.execute(*cmd, run_as_root=run_as_root,
prlimit=QEMU_IMG_LIMITS)
return imageutils.QemuImgInfo(out) return imageutils.QemuImgInfo(out)

View File

@ -38,7 +38,8 @@ class TestQemuImgInfo(test.TestCase):
output = image_utils.qemu_img_info(test_path) output = image_utils.qemu_img_info(test_path)
mock_exec.assert_called_once_with('env', 'LC_ALL=C', 'qemu-img', mock_exec.assert_called_once_with('env', 'LC_ALL=C', 'qemu-img',
'info', test_path, run_as_root=True) 'info', test_path, run_as_root=True,
prlimit=image_utils.QEMU_IMG_LIMITS)
self.assertEqual(mock_info.return_value, output) self.assertEqual(mock_info.return_value, output)
@mock.patch('cinder.openstack.common.imageutils.QemuImgInfo') @mock.patch('cinder.openstack.common.imageutils.QemuImgInfo')
@ -51,7 +52,8 @@ class TestQemuImgInfo(test.TestCase):
output = image_utils.qemu_img_info(test_path, run_as_root=False) output = image_utils.qemu_img_info(test_path, run_as_root=False)
mock_exec.assert_called_once_with('env', 'LC_ALL=C', 'qemu-img', mock_exec.assert_called_once_with('env', 'LC_ALL=C', 'qemu-img',
'info', test_path, run_as_root=False) 'info', test_path, run_as_root=False,
prlimit=image_utils.QEMU_IMG_LIMITS)
self.assertEqual(mock_info.return_value, output) self.assertEqual(mock_info.return_value, output)
@mock.patch('cinder.image.image_utils.os') @mock.patch('cinder.image.image_utils.os')
@ -66,7 +68,8 @@ class TestQemuImgInfo(test.TestCase):
output = image_utils.qemu_img_info(test_path) output = image_utils.qemu_img_info(test_path)
mock_exec.assert_called_once_with('qemu-img', 'info', test_path, mock_exec.assert_called_once_with('qemu-img', 'info', test_path,
run_as_root=True) run_as_root=True,
prlimit=image_utils.QEMU_IMG_LIMITS)
self.assertEqual(mock_info.return_value, output) self.assertEqual(mock_info.return_value, output)
@mock.patch('cinder.utils.execute') @mock.patch('cinder.utils.execute')

View File

@ -0,0 +1,7 @@
---
security:
- The qemu-img tool now has resource limits applied
which prevent it from using more than 1GB of address
space or more than 2 seconds of CPU time. This provides
protection against denial of service attacks from
maliciously crafted or corrupted disk images.