[Python-modules-commits] r9207 - in packages/python-django/branches/lenny/debian (2 files)

lamby at users.alioth.debian.org lamby at users.alioth.debian.org
Wed Jul 29 12:08:10 UTC 2009


    Date: Wednesday, July 29, 2009 @ 12:07:50
  Author: lamby
Revision: 9207

Add patch to fix issue with a maliciously crafted URL gaining access to any file on the filesystem (Closes: #539134)

Added:
  packages/python-django/branches/lenny/debian/patches/01-539134-sanitise-static-media.diff
Modified:
  packages/python-django/branches/lenny/debian/changelog

Modified: packages/python-django/branches/lenny/debian/changelog
===================================================================
--- packages/python-django/branches/lenny/debian/changelog	2009-07-29 11:09:45 UTC (rev 9206)
+++ packages/python-django/branches/lenny/debian/changelog	2009-07-29 12:07:50 UTC (rev 9207)
@@ -1,3 +1,25 @@
+python-django (1.0.2-1+lenny1) stable-security; urgency=high
+
+  * Add patch to fix issue with a maliciously crafted URL gaining access to
+    any file on the filesystem (Closes: #539134)
+    
+    Upstream writes:
+  
+      Django includes a lightweight, WSGI-based web server for use in
+      learning Django and in testing new applications during early stages of
+      development. For sake of convenience, this web server automatically
+      maps certain URLs corresponding to the static media files used by the
+      Django administrative application.
+     
+      The handler which maps these URLs did not properly check the requested
+      URL to verify that it corresponds to a static media file used by
+      Django. As such, a carefully-crafted URL can cause the development
+      server to serve any file to which it has read access.
+
+             <http://www.djangoproject.com/weblog/2009/jul/28/security/>
+
+ -- Chris Lamb <lamby at debian.org>  Wed, 29 Jul 2009 13:11:14 +0200
+
 python-django (1.0.2-1) unstable; urgency=low
 
   [ Chris Lamb ]

Added: packages/python-django/branches/lenny/debian/patches/01-539134-sanitise-static-media.diff
===================================================================
--- packages/python-django/branches/lenny/debian/patches/01-539134-sanitise-static-media.diff	                        (rev 0)
+++ packages/python-django/branches/lenny/debian/patches/01-539134-sanitise-static-media.diff	2009-07-29 12:07:50 UTC (rev 9207)
@@ -0,0 +1,149 @@
+Source: http://code.djangoproject.com/changeset/11353
+
+ -- Chris Lamb <lamby at debian.org>  Wed, 29 Jul 2009 13:17:43 +0200
+
+Index: ./django/core/servers/basehttp.py
+===================================================================
+--- ./django/core/servers/basehttp.py (revision 10691)
++++ ./django/core/servers/basehttp.py (revision 11353)
+@@ -17,4 +17,5 @@
+ 
+ from django.utils.http import http_date
++from django.utils._os import safe_join
+ 
+ __version__ = "0.1"
+@@ -622,8 +623,22 @@
+         if not media_dir:
+             import django
+-            self.media_dir = django.__path__[0] + '/contrib/admin/media'
++            self.media_dir = \
++                os.path.join(django.__path__[0], 'contrib', 'admin', 'media')
+         else:
+             self.media_dir = media_dir
+         self.media_url = settings.ADMIN_MEDIA_PREFIX
++
++    def file_path(self, url):
++        """
++        Returns the path to the media file on disk for the given URL.
++
++        The passed URL is assumed to begin with ADMIN_MEDIA_PREFIX.  If the
++        resultant file path is outside the media directory, then a ValueError
++        is raised.
++        """
++        # Remove ADMIN_MEDIA_PREFIX.
++        relative_url = url[len(self.media_url):]
++        relative_path = urllib.url2pathname(relative_url)
++        return safe_join(self.media_dir, relative_path)
+ 
+     def __call__(self, environ, start_response):
+@@ -637,10 +652,16 @@
+ 
+         # Find the admin file and serve it up, if it exists and is readable.
+-        relative_url = environ['PATH_INFO'][len(self.media_url):]
+-        file_path = os.path.join(self.media_dir, relative_url)
++        try:
++            file_path = self.file_path(environ['PATH_INFO'])
++        except ValueError: # Resulting file path was not valid.
++            status = '404 NOT FOUND'
++            headers = {'Content-type': 'text/plain'}
++            output = ['Page not found: %s' % environ['PATH_INFO']]
++            start_response(status, headers.items())
++            return output
+         if not os.path.exists(file_path):
+             status = '404 NOT FOUND'
+             headers = {'Content-type': 'text/plain'}
+-            output = ['Page not found: %s' % file_path]
++            output = ['Page not found: %s' % environ['PATH_INFO']]
+         else:
+             try:
+@@ -649,5 +670,5 @@
+                 status = '401 UNAUTHORIZED'
+                 headers = {'Content-type': 'text/plain'}
+-                output = ['Permission denied: %s' % file_path]
++                output = ['Permission denied: %s' % environ['PATH_INFO']]
+             else:
+                 # This is a very simple implementation of conditional GET with
+Index: ./django/core/management/commands/runserver.py
+===================================================================
+--- ./django/core/management/commands/runserver.py (revision 8749)
++++ ./django/core/management/commands/runserver.py (revision 11353)
+@@ -57,6 +57,5 @@
+ 
+             try:
+-                path = admin_media_path or django.__path__[0] + '/contrib/admin/media'
+-                handler = AdminMediaHandler(WSGIHandler(), path)
++                handler = AdminMediaHandler(WSGIHandler(), admin_media_path)
+                 run(addr, int(port), handler)
+             except WSGIServerException, e:
+Index: ./tests/regressiontests/servers/tests.py
+===================================================================
+--- ./tests/regressiontests/servers/tests.py (revision 11353)
++++ ./tests/regressiontests/servers/tests.py (revision 11353)
+@@ -0,0 +1,67 @@
++"""
++Tests for django.core.servers.
++"""
++
++import os
++
++import django
++from django.test import TestCase
++from django.core.handlers.wsgi import WSGIHandler
++from django.core.servers.basehttp import AdminMediaHandler
++
++
++class AdminMediaHandlerTests(TestCase):
++
++    def setUp(self):
++        self.admin_media_file_path = \
++            os.path.join(django.__path__[0], 'contrib', 'admin', 'media')
++        self.handler = AdminMediaHandler(WSGIHandler())
++
++    def test_media_urls(self):
++        """
++        Tests that URLs that look like absolute file paths after the
++        settings.ADMIN_MEDIA_PREFIX don't turn into absolute file paths.
++        """
++        # Cases that should work on all platforms.
++        data = (
++            ('/media/css/base.css', ('css', 'base.css')),
++        )
++        # Cases that should raise an exception.
++        bad_data = ()
++
++        # Add platform-specific cases.
++        if os.sep == '/':
++            data += (
++                # URL, tuple of relative path parts.
++                ('/media/\\css/base.css', ('\\css', 'base.css')),
++            )
++            bad_data += (
++                '/media//css/base.css',
++                '/media////css/base.css',
++                '/media/../css/base.css',
++            )
++        elif os.sep == '\\':
++            bad_data += (
++                '/media/C:\css/base.css',
++                '/media//\\css/base.css',
++                '/media/\\css/base.css',
++                '/media/\\\\css/base.css'
++            )
++        for url, path_tuple in data:
++            try:
++                output = self.handler.file_path(url)
++            except ValueError:
++                self.fail("Got a ValueError exception, but wasn't expecting"
++                          " one. URL was: %s" % url)
++            rel_path = os.path.join(*path_tuple)
++            desired = os.path.normcase(
++                os.path.join(self.admin_media_file_path, rel_path))
++            self.assertEqual(output, desired,
++                "Got: %s, Expected: %s, URL was: %s" % (output, desired, url))
++        for url in bad_data:
++            try:
++                output = self.handler.file_path(url)
++            except ValueError:
++                continue
++            self.fail('URL: %s should have caused a ValueError exception.'
++                      % url)




More information about the Python-modules-commits mailing list