components/openstack/horizon/patches/01-CVE-2014-0157.patch
branchs11-update
changeset 3178 77584387a894
equal deleted inserted replaced
3175:1ff833d174d4 3178:77584387a894
       
     1 Upstream patch for CVE-2014-0157.  This issue is fixed in Icehouse
       
     2 2014.1 and Havana 2013.2.4.
       
     3 
       
     4 From 54ec015f720a4379e8ffc34345b3a7bf36b6f15b Mon Sep 17 00:00:00 2001
       
     5 From: CristianFiorentino <[email protected]>
       
     6 Date: Mon, 10 Mar 2014 17:36:31 -0300
       
     7 Subject: [PATCH] Introduces escaping in Horizon/Orchestration
       
     8 
       
     9 1) Escape help_text a second time to avoid bootstrap tooltip XSS issue
       
    10 
       
    11 The "Description" parameter in a Heat template is used to populate
       
    12 a help_text tooltip in the dynamically generated Heat form. Bootstrap
       
    13 inserts this tooltip into the DOM using .html() which undoes any
       
    14 escaping we do in Django (it should be using .text()).
       
    15 
       
    16 This was fixed by forcing the help_text content to be escaped a second
       
    17 time. The issue itself is mitigated in bootstrap.js release 2.0.3
       
    18 (ours is currently 2.0.1).
       
    19 
       
    20 2) Properly escape untrusted Heat template 'outputs'
       
    21 
       
    22 The 'outputs' parameter in a Heat template was included in a Django
       
    23 template with HTML autoescaping turned off. Malicious HTML content
       
    24 could be included in a Heat template and would be rendered by Horizon
       
    25 when details about a created stack were displayed.
       
    26 
       
    27 This was fixed by not disabling autoescaping and explicitly escaping
       
    28 untrusted values in any strings that are later marked "safe" to render
       
    29 without further escaping.
       
    30 
       
    31 Conflicts:
       
    32 	openstack_dashboard/dashboards/project/stacks/mappings.py
       
    33 
       
    34 Change-Id: Icd9f9d9ca77068b12227d77469773a325c840001
       
    35 Closes-Bug: #1289033
       
    36 Co-Authored-By: Kieran Spear <[email protected]>
       
    37 ---
       
    38  horizon/templates/horizon/common/_form_fields.html |    7 ++++++-
       
    39  .../dashboards/project/stacks/mappings.py          |   10 ++++++++--
       
    40  .../stacks/templates/stacks/_detail_overview.html  |    3 +--
       
    41  .../dashboards/project/stacks/tests.py             |   17 +++++++++++------
       
    42  4 files changed, 26 insertions(+), 11 deletions(-)
       
    43 
       
    44 diff --git a/horizon/templates/horizon/common/_form_fields.html b/horizon/templates/horizon/common/_form_fields.html
       
    45 index 3567614..f6fb98f 100644
       
    46 --- a/horizon/templates/horizon/common/_form_fields.html
       
    47 +++ b/horizon/templates/horizon/common/_form_fields.html
       
    48 @@ -14,7 +14,12 @@
       
    49          <span class="help-inline">{{ error }}</span>
       
    50        {% endfor %}
       
    51      {% endif %}
       
    52 -    <span class="help-block">{{ field.help_text }}</span>
       
    53 +    {% comment %}
       
    54 +    Escape help_text a second time here, to avoid an XSS issue in bootstrap.js.
       
    55 +    This can most likely be removed once we upgrade bootstrap.js past 2.0.2.
       
    56 +    Note: the spaces are necessary here.
       
    57 +    {% endcomment %}
       
    58 +    <span class="help-block">{% filter force_escape %} {{ field.help_text }} {% endfilter %} </span>
       
    59      <div class="input">
       
    60        {{ field }}
       
    61      </div>
       
    62 diff --git a/openstack_dashboard/dashboards/project/stacks/mappings.py b/openstack_dashboard/dashboards/project/stacks/mappings.py
       
    63 index 0353291..f1389c5 100644
       
    64 --- a/openstack_dashboard/dashboards/project/stacks/mappings.py
       
    65 +++ b/openstack_dashboard/dashboards/project/stacks/mappings.py
       
    66 @@ -19,6 +19,8 @@ import urlparse
       
    67  
       
    68  from django.core.urlresolvers import reverse  # noqa
       
    69  from django.template.defaultfilters import register  # noqa
       
    70 +from django.utils import html
       
    71 +from django.utils import safestring
       
    72  
       
    73  from openstack_dashboard.api import swift
       
    74  
       
    75 @@ -76,11 +78,15 @@ def stack_output(output):
       
    76      if not output:
       
    77          return u''
       
    78      if isinstance(output, dict) or isinstance(output, list):
       
    79 -        return u'<pre>%s</pre>' % json.dumps(output, indent=2)
       
    80 +        json_string = json.dumps(output, indent=2)
       
    81 +        safe_output = u'<pre>%s</pre>' % html.escape(json_string)
       
    82 +        return safestring.mark_safe(safe_output)
       
    83      if isinstance(output, basestring):
       
    84          parts = urlparse.urlsplit(output)
       
    85          if parts.netloc and parts.scheme in ('http', 'https'):
       
    86 -            return u'<a href="%s" target="_blank">%s</a>' % (output, output)
       
    87 +            url = html.escape(output)
       
    88 +            safe_link = u'<a href="%s" target="_blank">%s</a>' % (url, url)
       
    89 +            return safestring.mark_safe(safe_link)
       
    90      return unicode(output)
       
    91  
       
    92  
       
    93 diff --git a/openstack_dashboard/dashboards/project/stacks/templates/stacks/_detail_overview.html b/openstack_dashboard/dashboards/project/stacks/templates/stacks/_detail_overview.html
       
    94 index f4756e0..33fe783 100644
       
    95 --- a/openstack_dashboard/dashboards/project/stacks/templates/stacks/_detail_overview.html
       
    96 +++ b/openstack_dashboard/dashboards/project/stacks/templates/stacks/_detail_overview.html
       
    97 @@ -36,9 +36,8 @@
       
    98      <dt>{{ output.output_key }}</dt>
       
    99      <dd>{{ output.description }}</dd>
       
   100      <dd>
       
   101 -    {% autoescape off %}
       
   102      {{ output.output_value|stack_output }}
       
   103 -    {% endautoescape %}</dd>
       
   104 +    </dd>
       
   105      {% endfor %}
       
   106    </dl>
       
   107  </div>
       
   108 diff --git a/openstack_dashboard/dashboards/project/stacks/tests.py b/openstack_dashboard/dashboards/project/stacks/tests.py
       
   109 index 408d86f..986e3e0 100644
       
   110 --- a/openstack_dashboard/dashboards/project/stacks/tests.py
       
   111 +++ b/openstack_dashboard/dashboards/project/stacks/tests.py
       
   112 @@ -16,6 +16,7 @@ import json
       
   113  
       
   114  from django.core.urlresolvers import reverse  # noqa
       
   115  from django import http
       
   116 +from django.utils import html
       
   117  
       
   118  from mox import IsA  # noqa
       
   119  
       
   120 @@ -77,12 +78,16 @@ class MappingsTests(test.TestCase):
       
   121          self.assertEqual(u'foo', mappings.stack_output('foo'))
       
   122          self.assertEqual(u'', mappings.stack_output(None))
       
   123  
       
   124 -        self.assertEqual(
       
   125 -            u'<pre>[\n  "one", \n  "two", \n  "three"\n]</pre>',
       
   126 -            mappings.stack_output(['one', 'two', 'three']))
       
   127 -        self.assertEqual(
       
   128 -            u'<pre>{\n  "foo": "bar"\n}</pre>',
       
   129 -            mappings.stack_output({'foo': 'bar'}))
       
   130 +        outputs = ['one', 'two', 'three']
       
   131 +        expected_text = """[\n  "one", \n  "two", \n  "three"\n]"""
       
   132 +
       
   133 +        self.assertEqual(u'<pre>%s</pre>' % html.escape(expected_text),
       
   134 +                         mappings.stack_output(outputs))
       
   135 +
       
   136 +        outputs = {'foo': 'bar'}
       
   137 +        expected_text = """{\n  "foo": "bar"\n}"""
       
   138 +        self.assertEqual(u'<pre>%s</pre>' % html.escape(expected_text),
       
   139 +                         mappings.stack_output(outputs))
       
   140  
       
   141          self.assertEqual(
       
   142              u'<a href="http://www.example.com/foo" target="_blank">'
       
   143 -- 
       
   144 1.7.9.5
       
   145