Gentoo Archives: gentoo-commits

From: "Matt Thode (prometheanfire)" <prometheanfire@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] gentoo-x86 commit in sys-cluster/nova/files: nova-folsom-3-CVE-2013-0335.patch
Date: Tue, 26 Feb 2013 21:44:09
Message-Id: 20130226214405.8BC9B2171E@flycatcher.gentoo.org
1 prometheanfire 13/02/26 21:44:05
2
3 Added: nova-folsom-3-CVE-2013-0335.patch
4 Log:
5 sys-cluster/nova - fixing bug 459364 CVE-2013-0335
6
7 (Portage version: 2.1.11.50/cvs/Linux x86_64, signed Manifest commit with key 0x2471eb3e40ac5ac3)
8
9 Revision Changes Path
10 1.1 sys-cluster/nova/files/nova-folsom-3-CVE-2013-0335.patch
11
12 file : http://sources.gentoo.org/viewvc.cgi/gentoo-x86/sys-cluster/nova/files/nova-folsom-3-CVE-2013-0335.patch?rev=1.1&view=markup
13 plain: http://sources.gentoo.org/viewvc.cgi/gentoo-x86/sys-cluster/nova/files/nova-folsom-3-CVE-2013-0335.patch?rev=1.1&content-type=text/plain
14
15 Index: nova-folsom-3-CVE-2013-0335.patch
16 ===================================================================
17 From 05a3374992bc8ba53ddc9c491b51c4b59eed0a72 Mon Sep 17 00:00:00 2001
18 From: John Herndon <john.herndon@××.com>
19 Date: Fri, 22 Feb 2013 20:43:58 +0000
20 Subject: [PATCH] VNC Token Validation
21
22 Force console auth service to flush all tokens
23 associated with an instance when it is deleted.
24 This will fix a bug where the console for the
25 wrong instance can be connected to via the console
26 if the correct circumstances occur. This change also
27 makes a call to veriry vnc console tokens when a
28 user attempts to connect to a console. This ensures
29 the user is connecting to the correct console.
30
31 bug 1125378
32 Change-Id: I0d83ec6c4dbfef1af912a200ee15f8052f72da96
33 ---
34 nova/common/memorycache.py | 5 +++
35 nova/compute/api.py | 3 +-
36 nova/compute/manager.py | 12 ++++++
37 nova/compute/rpcapi.py | 7 ++++
38 nova/consoleauth/manager.py | 41 +++++++++++++++++-
39 nova/consoleauth/rpcapi.py | 10 ++++-
40 nova/tests/compute/test_compute.py | 52 ++++++++++++++++++++++-
41 nova/tests/compute/test_rpcapi.py | 5 +++
42 nova/tests/consoleauth/test_consoleauth.py | 67 +++++++++++++++++++++++++++++-
43 nova/tests/consoleauth/test_rpcapi.py | 6 ++-
44 10 files changed, 200 insertions(+), 8 deletions(-)
45
46 diff --git a/nova/common/memorycache.py b/nova/common/memorycache.py
47 index 502f833..3a1935e 100644
48 --- a/nova/common/memorycache.py
49 +++ b/nova/common/memorycache.py
50 @@ -62,3 +62,8 @@ class Client(object):
51 new_value = int(value) + delta
52 self.cache[key] = (self.cache[key][0], str(new_value))
53 return new_value
54 +
55 + def delete(self, key, time=0):
56 + """Deletes the value associated with a key."""
57 + if key in self.cache:
58 + del self.cache[key]
59 diff --git a/nova/compute/api.py b/nova/compute/api.py
60 index df7b215..3860226 100644
61 --- a/nova/compute/api.py
62 +++ b/nova/compute/api.py
63 @@ -1853,7 +1853,8 @@ class API(base.Base):
64
65 self.consoleauth_rpcapi.authorize_console(context,
66 connect_info['token'], console_type, connect_info['host'],
67 - connect_info['port'], connect_info['internal_access_path'])
68 + connect_info['port'], connect_info['internal_access_path'],
69 + instance["uuid"])
70
71 return {'url': connect_info['access_url']}
72
73 diff --git a/nova/compute/manager.py b/nova/compute/manager.py
74 index 90de5a4..5b0d1ea 100644
75 --- a/nova/compute/manager.py
76 +++ b/nova/compute/manager.py
77 @@ -52,6 +52,7 @@ from nova.compute import rpcapi as compute_rpcapi
78 from nova.compute import task_states
79 from nova.compute import utils as compute_utils
80 from nova.compute import vm_states
81 +from nova import consoleauth
82 import nova.context
83 from nova import exception
84 from nova import flags
85 @@ -235,6 +236,7 @@ class ComputeManager(manager.SchedulerDependentManager):
86 self.compute_api = compute.API()
87 self.compute_rpcapi = compute_rpcapi.ComputeAPI()
88 self.scheduler_rpcapi = scheduler_rpcapi.SchedulerAPI()
89 + self.consoleauth_rpcapi = consoleauth.rpcapi.ConsoleAuthAPI()
90
91 super(ComputeManager, self).__init__(service_name="compute",
92 *args, **kwargs)
93 @@ -926,6 +928,10 @@ class ComputeManager(manager.SchedulerDependentManager):
94 self._notify_about_instance_usage(context, instance, "delete.end",
95 system_metadata=system_meta)
96
97 + if FLAGS.vnc_enabled:
98 + self.consoleauth_rpcapi.delete_tokens_for_instance(context,
99 + instance["uuid"])
100 +
101 @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
102 @wrap_instance_fault
103 def terminate_instance(self, context, instance):
104 @@ -1989,6 +1995,12 @@ class ComputeManager(manager.SchedulerDependentManager):
105 return connection_info
106
107 @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
108 + @wrap_instance_fault
109 + def validate_console_port(self, ctxt, instance, port, console_type):
110 + console_info = self.driver.get_vnc_console(instance)
111 + return console_info['port'] == port
112 +
113 + @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id())
114 @reverts_task_state
115 @wrap_instance_fault
116 def reserve_block_device_name(self, context, instance, device):
117 diff --git a/nova/compute/rpcapi.py b/nova/compute/rpcapi.py
118 index 2e3873c..afec290 100644
119 --- a/nova/compute/rpcapi.py
120 +++ b/nova/compute/rpcapi.py
121 @@ -259,6 +259,13 @@ class ComputeAPI(nova.openstack.common.rpc.proxy.RpcProxy):
122 instance=instance_p, console_type=console_type),
123 topic=_compute_topic(self.topic, ctxt, None, instance))
124
125 + def validate_console_port(self, ctxt, instance, port, console_type):
126 + instance_p = jsonutils.to_primitive(instance)
127 + return self.call(ctxt, self.make_msg('validate_console_port',
128 + instance=instance_p, port=port, console_type=console_type),
129 + topic=_compute_topic(self.topic, ctxt,
130 + None, instance))
131 +
132 def host_maintenance_mode(self, ctxt, host_param, mode, host):
133 '''Set host maintenance mode
134
135 diff --git a/nova/consoleauth/manager.py b/nova/consoleauth/manager.py
136 index 61efdd0..e715f98 100644
137 --- a/nova/consoleauth/manager.py
138 +++ b/nova/consoleauth/manager.py
139 @@ -20,6 +20,8 @@
140
141 import time
142
143 +from nova.compute import rpcapi as compute_rpcapi
144 +from nova.db import api as db
145 from nova import flags
146 from nova import manager
147 from nova.openstack.common import cfg
148 @@ -56,10 +58,21 @@ class ConsoleAuthManager(manager.Manager):
149 from nova.common import memorycache as memcache
150 self.mc = memcache.Client(FLAGS.memcached_servers,
151 debug=0)
152 + self.compute_rpcapi = compute_rpcapi.ComputeAPI()
153 +
154 + def _get_tokens_for_instance(self, instance_uuid):
155 + tokens_str = self.mc.get(instance_uuid.encode('UTF-8'))
156 + if not tokens_str:
157 + tokens = []
158 + else:
159 + tokens = jsonutils.loads(tokens_str)
160 + return tokens
161
162 def authorize_console(self, context, token, console_type, host, port,
163 - internal_access_path):
164 + internal_access_path, instance_uuid=None):
165 +
166 token_dict = {'token': token,
167 + 'instance_uuid': instance_uuid,
168 'console_type': console_type,
169 'host': host,
170 'port': port,
171 @@ -67,11 +80,35 @@ class ConsoleAuthManager(manager.Manager):
172 'last_activity_at': time.time()}
173 data = jsonutils.dumps(token_dict)
174 self.mc.set(token.encode('UTF-8'), data, FLAGS.console_token_ttl)
175 + if instance_uuid is not None:
176 + tokens = self._get_tokens_for_instance(instance_uuid)
177 + tokens.append(token)
178 + self.mc.set(instance_uuid.encode('UTF-8'),
179 + jsonutils.dumps(tokens))
180 +
181 LOG.audit(_("Received Token: %(token)s, %(token_dict)s)"), locals())
182
183 + def _validate_token(self, context, token):
184 + instance_uuid = token['instance_uuid']
185 + if instance_uuid is None:
186 + return False
187 + instance = db.instance_get_by_uuid(context, instance_uuid)
188 + return self.compute_rpcapi.validate_console_port(context,
189 + instance,
190 + token['port'],
191 + token['console_type'])
192 +
193 def check_token(self, context, token):
194 token_str = self.mc.get(token.encode('UTF-8'))
195 token_valid = (token_str is not None)
196 LOG.audit(_("Checking Token: %(token)s, %(token_valid)s)"), locals())
197 if token_valid:
198 - return jsonutils.loads(token_str)
199 + token = jsonutils.loads(token_str)
200 + if self._validate_token(context, token):
201 + return token
202 +
203 + def delete_tokens_for_instance(self, context, instance_uuid):
204 + tokens = self._get_tokens_for_instance(instance_uuid)
205 + for token in tokens:
206 + self.mc.delete(token)
207 + self.mc.delete(instance_uuid.encode('UTF-8'))
208 diff --git a/nova/consoleauth/rpcapi.py b/nova/consoleauth/rpcapi.py
209 index 2fafe3f..b3b34c1 100644
210 --- a/nova/consoleauth/rpcapi.py
211 +++ b/nova/consoleauth/rpcapi.py
212 @@ -49,14 +49,20 @@ class ConsoleAuthAPI(nova.openstack.common.rpc.proxy.RpcProxy):
213 default_version=self.BASE_RPC_API_VERSION)
214
215 def authorize_console(self, ctxt, token, console_type, host, port,
216 - internal_access_path):
217 + internal_access_path, instance_uuid=None):
218 # The remote side doesn't return anything, but we want to block
219 # until it completes.
220 return self.call(ctxt,
221 self.make_msg('authorize_console',
222 token=token, console_type=console_type,
223 host=host, port=port,
224 - internal_access_path=internal_access_path))
225 + internal_access_path=internal_access_path,
226 + instance_uuid=instance_uuid))
227
228 def check_token(self, ctxt, token):
229 return self.call(ctxt, self.make_msg('check_token', token=token))
230 +
231 + def delete_tokens_for_instance(self, ctxt, instance_uuid):
232 + return self.call(ctxt,
233 + self.make_msg('delete_tokens_for_instance',
234 + instance_uuid=instance_uuid))
235 diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py
236 index 10b89fd..b745798 100644
237 --- a/nova/tests/compute/test_compute.py
238 +++ b/nova/tests/compute/test_compute.py
239 @@ -1372,6 +1372,24 @@ class ComputeTestCase(BaseTestCase):
240 self.compute._delete_instance(self.context,
241 instance=jsonutils.to_primitive(instance))
242
243 + def test_delete_instance_deletes_console_auth_tokens(self):
244 + instance = self._create_fake_instance()
245 + self.flags(vnc_enabled=True)
246 +
247 + self.tokens_deleted = False
248 +
249 + def fake_delete_tokens(*args, **kwargs):
250 + self.tokens_deleted = True
251 +
252 + cauth_rpcapi = self.compute.consoleauth_rpcapi
253 + self.stubs.Set(cauth_rpcapi, 'delete_tokens_for_instance',
254 + fake_delete_tokens)
255 +
256 + self.compute._delete_instance(self.context,
257 + instance=jsonutils.to_primitive(instance))
258 +
259 + self.assertTrue(self.tokens_deleted)
260 +
261 def test_instance_termination_exception_sets_error(self):
262 """Test that we handle InstanceTerminationFailure
263 which is propagated up from the underlying driver.
264 @@ -4505,7 +4523,9 @@ class ComputeAPITestCase(BaseTestCase):
265 'console_type': fake_console_type,
266 'host': 'fake_console_host',
267 'port': 'fake_console_port',
268 - 'internal_access_path': 'fake_access_path'}
269 + 'internal_access_path': 'fake_access_path',
270 + 'instance_uuid': fake_instance["uuid"]}
271 +
272 fake_connect_info2 = copy.deepcopy(fake_connect_info)
273 fake_connect_info2['access_url'] = 'fake_console_url'
274
275 @@ -4539,6 +4559,36 @@ class ComputeAPITestCase(BaseTestCase):
276
277 db.instance_destroy(self.context, instance['uuid'])
278
279 + def test_validate_console_port(self):
280 + self.flags(vnc_enabled=True)
281 + instance = jsonutils.to_primitive(self._create_fake_instance())
282 +
283 + def fake_driver_get_console(*args, **kwargs):
284 + return {'host': "fake_host", 'port': "5900",
285 + 'internal_access_path': None}
286 + self.stubs.Set(self.compute.driver, "get_vnc_console",
287 + fake_driver_get_console)
288 +
289 + self.assertTrue(self.compute.validate_console_port(self.context,
290 + instance,
291 + "5900",
292 + "novnc"))
293 +
294 + def test_validate_console_port_wrong_port(self):
295 + self.flags(vnc_enabled=True)
296 + instance = jsonutils.to_primitive(self._create_fake_instance())
297 +
298 + def fake_driver_get_console(*args, **kwargs):
299 + return {'host': "fake_host", 'port': "5900",
300 + 'internal_access_path': None}
301 + self.stubs.Set(self.compute.driver, "get_vnc_console",
302 + fake_driver_get_console)
303 +
304 + self.assertFalse(self.compute.validate_console_port(self.context,
305 + instance,
306 + "wrongport",
307 + "novnc"))
308 +
309 def test_console_output(self):
310 fake_instance = {'uuid': 'fake_uuid',
311 'host': 'fake_compute_host'}
312 diff --git a/nova/tests/compute/test_rpcapi.py b/nova/tests/compute/test_rpcapi.py
313 index 559a56a..c42047b 100644
314 --- a/nova/tests/compute/test_rpcapi.py
315 +++ b/nova/tests/compute/test_rpcapi.py
316 @@ -168,6 +168,11 @@ class ComputeRpcAPITestCase(test.TestCase):
317 self._test_compute_api('get_vnc_console', 'call',
318 instance=self.fake_instance, console_type='type')
319
320 + def test_validate_console_port(self):
321 + self._test_compute_api('validate_console_port', 'call',
322 + instance=self.fake_instance, port="5900",
323 + console_type="novnc")
324 +
325 def test_host_maintenance_mode(self):
326 self._test_compute_api('host_maintenance_mode', 'call',
327 host_param='param', mode='mode', host='host')
328 diff --git a/nova/tests/consoleauth/test_consoleauth.py b/nova/tests/consoleauth/test_consoleauth.py
329 index da50eb8..4bea85a 100644
330 --- a/nova/tests/consoleauth/test_consoleauth.py
331 +++ b/nova/tests/consoleauth/test_consoleauth.py
332 @@ -45,8 +45,73 @@ class ConsoleauthTestCase(test.TestCase):
333 """Test that tokens expire correctly."""
334 token = 'mytok'
335 self.flags(console_token_ttl=1)
336 +
337 + def fake_validate_token(*args, **kwargs):
338 + return True
339 + self.stubs.Set(self.manager,
340 + "_validate_token",
341 + fake_validate_token)
342 +
343 self.manager.authorize_console(self.context, token, 'novnc',
344 - '127.0.0.1', 'host', '')
345 + '127.0.0.1', '8080', 'host', "1234")
346 self.assertTrue(self.manager.check_token(self.context, token))
347 time.sleep(1.1)
348 self.assertFalse(self.manager.check_token(self.context, token))
349 +
350 + def test_multiple_tokens_for_instance(self):
351 + tokens = ["token" + str(i) for i in xrange(10)]
352 + instance = "12345"
353 +
354 + def fake_validate_token(*args, **kwargs):
355 + return True
356 +
357 + self.stubs.Set(self.manager, "_validate_token",
358 + fake_validate_token)
359 + for token in tokens:
360 + self.manager.authorize_console(self.context, token, 'novnc',
361 + '127.0.0.1', '8080', 'host',
362 + instance)
363 +
364 + for token in tokens:
365 + self.assertTrue(self.manager.check_token(self.context, token))
366 +
367 + def test_delete_tokens_for_instance(self):
368 + instance = "12345"
369 + tokens = ["token" + str(i) for i in xrange(10)]
370 +
371 + def fake_validate_token(*args, **kwargs):
372 + return True
373 + self.stubs.Set(self.manager, "_validate_token",
374 + fake_validate_token)
375 +
376 + for token in tokens:
377 + self.manager.authorize_console(self.context, token, 'novnc',
378 + '127.0.0.1', '8080', 'host',
379 + instance)
380 + self.manager.delete_tokens_for_instance(self.context, instance)
381 + stored_tokens = self.manager._get_tokens_for_instance(instance)
382 +
383 + self.assertEqual(len(stored_tokens), 0)
384 +
385 + for token in tokens:
386 + self.assertFalse(self.manager.check_token(self.context, token))
387 +
388 + def test_wrong_token_has_port(self):
389 + token = 'mytok'
390 +
391 + def fake_validate_token(*args, **kwargs):
392 + return False
393 +
394 + self.stubs.Set(self.manager, "_validate_token",
395 + fake_validate_token)
396 +
397 + self.manager.authorize_console(self.context, token, 'novnc',
398 + '127.0.0.1', '8080', 'host',
399 + instance_uuid='instance')
400 + self.assertFalse(self.manager.check_token(self.context, token))
401 +
402 + def test_console_no_instance_uuid(self):
403 + self.manager.authorize_console(self.context, "token", 'novnc',
404 + '127.0.0.1', '8080', 'host',
405 + instance_uuid=None)
406 + self.assertFalse(self.manager.check_token(self.context, "token"))
407 diff --git a/nova/tests/consoleauth/test_rpcapi.py b/nova/tests/consoleauth/test_rpcapi.py
408 index 10484c7..c1e7a46 100644
409 --- a/nova/tests/consoleauth/test_rpcapi.py
410 +++ b/nova/tests/consoleauth/test_rpcapi.py
411 @@ -68,7 +68,11 @@ class ConsoleAuthRpcAPITestCase(test.TestCase):
412 def test_authorize_console(self):
413 self._test_consoleauth_api('authorize_console', token='token',
414 console_type='ctype', host='h', port='p',
415 - internal_access_path='iap')
416 + internal_access_path='iap', instance_uuid="1234")
417
418 def test_check_token(self):
419 self._test_consoleauth_api('check_token', token='t')
420 +
421 + def test_delete_tokens_for_instnace(self):
422 + self._test_consoleauth_api('delete_tokens_for_instance',
423 + instance_uuid="instance")
424 --
425 1.7.12.4