summary refs log tree commit diff
path: root/pkgs/development/python-modules/sanic/22.3.2-CVE-2022-35920.patch
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/development/python-modules/sanic/22.3.2-CVE-2022-35920.patch')
-rw-r--r--pkgs/development/python-modules/sanic/22.3.2-CVE-2022-35920.patch141
1 files changed, 141 insertions, 0 deletions
diff --git a/pkgs/development/python-modules/sanic/22.3.2-CVE-2022-35920.patch b/pkgs/development/python-modules/sanic/22.3.2-CVE-2022-35920.patch
new file mode 100644
index 00000000000..694c69602c1
--- /dev/null
+++ b/pkgs/development/python-modules/sanic/22.3.2-CVE-2022-35920.patch
@@ -0,0 +1,141 @@
+Based on upstream 9d415e4ec63d31b3749fd540e2c2ac7c98dedcdd and
+2fa28f1711a8e59c6f4d3468e9c2f8b6991188a2, adjusted to apply to
+v22.3.2, raise the same exception as before and not remove any
+imports.
+
+diff --git a/sanic/mixins/routes.py b/sanic/mixins/routes.py
+index 9e2cf96..e0cf86b 100644
+--- a/sanic/mixins/routes.py
++++ b/sanic/mixins/routes.py
+@@ -3,7 +3,7 @@ from contextlib import suppress
+ from functools import partial, wraps
+ from inspect import getsource, signature
+ from mimetypes import guess_type
+-from os import path
++from os import path, sep
+ from pathlib import PurePath
+ from re import sub
+ from textwrap import dedent
+@@ -775,23 +775,23 @@ class RouteMixin(metaclass=SanicMeta):
+         content_type=None,
+         __file_uri__=None,
+     ):
+-        # Using this to determine if the URL is trying to break out of the path
+-        # served.  os.path.realpath seems to be very slow
+-        if __file_uri__ and "../" in __file_uri__:
+-            raise InvalidUsage("Invalid URL")
+         # Merge served directory and requested file if provided
+-        # Strip all / that in the beginning of the URL to help prevent python
+-        # from herping a derp and treating the uri as an absolute path
+-        root_path = file_path = file_or_directory
++        root_path = file_path = path.abspath(unquote(file_or_directory))
++
+         if __file_uri__:
+-            file_path = path.join(
+-                file_or_directory, sub("^[/]*", "", __file_uri__)
+-            )
++            # Strip all / that in the beginning of the URL to help prevent
++            # python from herping a derp and treating the uri as an
++            # absolute path
++            unquoted_file_uri = unquote(__file_uri__).lstrip("/")
++
++            segments = unquoted_file_uri.split("/")
++            if ".." in segments or any(sep in segment for segment in segments):
++                raise InvalidUsage("Invalid URL")
++
++            file_path = path.join(file_or_directory, unquoted_file_uri)
++            file_path = path.abspath(file_path)
+ 
+-        # URL decode the path sent by the browser otherwise we won't be able to
+-        # match filenames which got encoded (filenames with spaces etc)
+-        file_path = path.abspath(unquote(file_path))
+-        if not file_path.startswith(path.abspath(unquote(root_path))):
++        if not file_path.startswith(root_path):
+             error_logger.exception(
+                 f"File not found: path={file_or_directory}, "
+                 f"relative_url={__file_uri__}"
+diff --git a/tests/test_static.py b/tests/test_static.py
+index 36a98e1..aeb625b 100644
+--- a/tests/test_static.py
++++ b/tests/test_static.py
+@@ -1,6 +1,7 @@
+ import inspect
+ import logging
+ import os
++import sys
+ 
+ from collections import Counter
+ from pathlib import Path
+@@ -8,7 +9,7 @@ from time import gmtime, strftime
+ 
+ import pytest
+ 
+-from sanic import text
++from sanic import Sanic, text
+ from sanic.exceptions import FileNotFound
+ 
+ 
+@@ -21,6 +22,22 @@ def static_file_directory():
+     return static_directory
+ 
+ 
++@pytest.fixture(scope="module")
++def double_dotted_directory_file(static_file_directory: str):
++    """Generate double dotted directory and its files"""
++    if sys.platform == "win32":
++        raise Exception("Windows doesn't support double dotted directories")
++
++    file_path = Path(static_file_directory) / "dotted.." / "dot.txt"
++    double_dotted_dir = file_path.parent
++    Path.mkdir(double_dotted_dir, exist_ok=True)
++    with open(file_path, "w") as f:
++        f.write("DOT\n")
++    yield file_path
++    Path.unlink(file_path)
++    Path.rmdir(double_dotted_dir)
++
++
+ def get_file_path(static_file_directory, file_name):
+     return os.path.join(static_file_directory, file_name)
+ 
+@@ -578,3 +595,40 @@ def test_resource_type_dir(app, static_file_directory):
+ def test_resource_type_unknown(app, static_file_directory, caplog):
+     with pytest.raises(ValueError):
+         app.static("/static", static_file_directory, resource_type="unknown")
++
++
++@pytest.mark.skipif(
++    sys.platform == "win32",
++    reason="Windows does not support double dotted directories",
++)
++def test_dotted_dir_ok(
++    app: Sanic, static_file_directory: str, double_dotted_directory_file: Path
++):
++    app.static("/foo", static_file_directory)
++    dot_relative_path = str(
++        double_dotted_directory_file.relative_to(static_file_directory)
++    )
++    _, response = app.test_client.get("/foo/" + dot_relative_path)
++    assert response.status == 200
++    assert response.body == b"DOT\n"
++
++
++def test_breakout(app: Sanic, static_file_directory: str):
++    app.static("/foo", static_file_directory)
++
++    _, response = app.test_client.get("/foo/..%2Fstatic/test.file")
++    assert response.status == 400
++
++
++@pytest.mark.skipif(
++    sys.platform != "win32", reason="Block backslash on Windows only"
++)
++def test_double_backslash_prohibited_on_win32(
++    app: Sanic, static_file_directory: str
++):
++    app.static("/foo", static_file_directory)
++
++    _, response = app.test_client.get("/foo/static/..\\static/test.file")
++    assert response.status == 400
++    _, response = app.test_client.get("/foo/static\\../static/test.file")
++    assert response.status == 400