File 4461-inets-httpd-Assure-relative-paths-can-not-be-used-to.patch of Package erlang

From 39f14943f2aaa2c551d6402c73583fe213d6ed87 Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin <ingela@erlang.org>
Date: Thu, 18 Feb 2021 11:40:16 +0100
Subject: [PATCH] inets,httpd: Assure relative paths can not be used to bypass
 server root directory

Use of uri_string:percent_decode in commmit 5f83a9d719afac0718bff524df6654c9fc94aad5
needs to be combined with uri_string:normalize to assure valid paths.

Solves CVE-2021-27563
---
 lib/inets/src/http_server/mod_alias.erl | 24 ++++++++-----
 lib/inets/test/httpd_SUITE.erl          | 45 +++++++++++++++++++++++++
 2 files changed, 61 insertions(+), 8 deletions(-)

diff --git a/lib/inets/src/http_server/mod_alias.erl b/lib/inets/src/http_server/mod_alias.erl
index 35da39c53c..cb2d2c1ef4 100644
--- a/lib/inets/src/http_server/mod_alias.erl
+++ b/lib/inets/src/http_server/mod_alias.erl
@@ -195,22 +195,30 @@ append_index(RealName, [Index | Rest]) ->
 
 %% path
 
-path(Data, ConfigDB, RequestURI) ->
-	InitPath =
+path(Data, ConfigDB, RequestURI0) ->
     case proplists:get_value(real_name, Data) of
 	undefined ->
-            {Prefix, DocumentRoot} = which_document_root(ConfigDB), 
-            {Path, _AfterPath} = 
+            {Prefix, DocumentRoot} = which_document_root(ConfigDB),
+            RequestURI = percent_decode_path(RequestURI0),
+            {Path, _AfterPath} =    
                 httpd_util:split_path(DocumentRoot ++ RequestURI),
             Prefix ++ Path;
 	{Path, _AfterPath} ->
 	    Path
-    end,
-	case uri_string:percent_decode(InitPath) of
-		{error, _} -> InitPath;
-		P -> P
     end.
 
+percent_decode_path(InitPath) ->
+    case uri_string:percent_decode(InitPath) of
+        {error, _} ->
+            InitPath;
+        Path0 -> %% Protect against vulnerabilities
+            case uri_string:normalize(Path0) of
+                {error, _, _} ->
+                    InitPath;
+                Path ->
+                    Path
+            end
+    end.
 %%
 %% Configuration
 %%
diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl
index e4efeb1b81..027932caa2 100644
--- a/lib/inets/test/httpd_SUITE.erl
+++ b/lib/inets/test/httpd_SUITE.erl
@@ -155,6 +155,7 @@ http_head() ->
 http_get() ->
     [alias, 
      get, 
+     bad_dot_paths,
      %%actions, Add configuration so that this test mod_action
      esi, 
      bad_hex, 
@@ -473,6 +474,50 @@ get(Config) when is_list(Config) ->
 					{header, "Date"},
 					{header, "Server"},
 					{version, Version}]).
+
+bad_dot_paths() ->
+    [{doc, "Do not allow ..-paths to acesse files outside of doc root"}].
+bad_dot_paths(Config) when is_list(Config) -> 
+    Version = proplists:get_value(http_version, Config),
+    Host = proplists:get_value(host, Config),
+    Type = proplists:get_value(type, Config),
+    
+    BadDotPath0 = "/..%2f..%2f...%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc/passwd ",
+    BadDotPath1 = "/..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc/passwd ",
+    BadDotPath2 = "/%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/passwd ",
+    
+    ok = httpd_test_lib:verify_request(proplists:get_value(type, Config), Host, 
+				       proplists:get_value(port, Config),  
+				       transport_opts(Type, Config),
+				       proplists:get_value(node, Config),
+				       http_request("GET " ++ BadDotPath0 , Version, Host),
+				       [{statuscode, 404},
+					{header, "Content-Type", "text/html"},
+					{header, "Date"},
+					{header, "Server"},
+					{version, Version}]),
+    
+    ok = httpd_test_lib:verify_request(proplists:get_value(type, Config), Host, 
+				       proplists:get_value(port, Config),  
+				       transport_opts(Type, Config),
+				       proplists:get_value(node, Config),
+				       http_request("GET " ++ BadDotPath1, Version, Host),
+				       [{statuscode, 404},
+					{header, "Content-Type", "text/html"},
+					{header, "Date"},
+					{header, "Server"},
+					{version, Version}]),
+    
+    ok = httpd_test_lib:verify_request(proplists:get_value(type, Config), Host,
+				       proplists:get_value(port, Config),
+				       transport_opts(Type, Config),
+				       proplists:get_value(node, Config),
+				       http_request("GET " ++ BadDotPath2, Version, Host),
+				       [{statuscode, 404},
+					{header, "Content-Type", "text/html"},
+					{header, "Date"},
+					{header, "Server"},
+					{version, Version}]).
     
 basic_auth_1_1(Config) when is_list(Config) -> 
     basic_auth([{http_version, "HTTP/1.1"} | Config]).
-- 
2.26.2

openSUSE Build Service is sponsored by