Sophie

Sophie

distrib > Mageia > 7 > i586 > media > core-updates-src > by-pkgid > eb62fb6fe1ba344916f947b1825ba785 > files > 7

python-pip-19.0.3-1.3.mga7.src.rpm

commit a4c735b14a62f9cb864533808ac63936704f2ace
Author: gzpan123 <gzpan123@gmail.com>
Date:   Wed Apr 17 21:25:45 2019 +0800

    FIX #6413 pip install <url> allow directory traversal

diff --git a/src/pip/_internal/download.py b/src/pip/_internal/download.py
index c98fae5d3..6a54f8940 100644
--- a/src/pip/_internal/download.py
+++ b/src/pip/_internal/download.py
@@ -59,7 +59,8 @@ __all__ = ['get_file_content',
            'is_url', 'url_to_path', 'path_to_url',
            'is_archive_file', 'unpack_vcs_link',
            'unpack_file_url', 'is_vcs_url', 'is_file_url',
-           'unpack_http_url', 'unpack_url']
+           'unpack_http_url', 'unpack_url',
+           'parse_content_disposition', 'sanitize_content_filename']
 
 
 logger = logging.getLogger(__name__)
@@ -882,6 +882,29 @@
         write_delete_marker_file(location)
 
 
+def sanitize_content_filename(filename):
+    # type: (str) -> str
+    """
+    Sanitize the "filename" value from a Content-Disposition header.
+    """
+    return os.path.basename(filename)
+
+
+def parse_content_disposition(content_disposition, default_filename):
+    # type: (str, str) -> str
+    """
+    Parse the "filename" value from a Content-Disposition header, and
+    return the default filename if the result is empty.
+    """
+    _type, params = cgi.parse_header(content_disposition)
+    filename = params.get('filename')
+    if filename:
+        # We need to sanitize the filename to prevent directory traversal
+        # in case the filename contains ".." path parts.
+        filename = sanitize_content_filename(filename)
+    return filename or default_filename
+
+
 def _download_http_url(
     link,  # type: Link
     session,  # type: PipSession
@@ -880,10 +904,7 @@ def _download_http_url(
     # Have a look at the Content-Disposition header for a better guess
     content_disposition = resp.headers.get('content-disposition')
     if content_disposition:
-        type, params = cgi.parse_header(content_disposition)
-        # We use ``or`` here because we don't want to use an "empty" value
-        # from the filename param.
-        filename = params.get('filename') or filename
+        filename = parse_content_disposition(content_disposition, filename)
     ext = splitext(filename)[1]
     if not ext:
         ext = mimetypes.guess_extension(content_type)