From 534457d5f0860ce44d4db4aed109ccc9f2c74174 Mon Sep 17 00:00:00 2001 From: Manuel de la Pena Saenz Date: Fri, 21 Feb 2025 18:25:28 -0500 Subject: [PATCH] [CI] Fix xharness local run. In PR https://github.com/dotnet/macios/pull/22154 in an attempt to fix some CodeQL warnings we broke the local execution of xharness. The reason is the following, CodeQL complained about sanitizing the local path and in an attempt to remove the warning a test to make sure that the local path does not have a '/' was added. The issue is that our requests, when we run xharness locally, will return localpaths of the form: '/20250221_181807/index.html' that is because the request is for 'http://localhost:51234/20250221_181807/index.html'. In webapps, the path of the request ALWAYS starts with '/' even when the request is for 'http://localhost:51234' (which returns '/'). In an attemp to fix xharness AND keep CodeQL happy I have made the following changes: 1. Ensure that the full path is one of the allowed ones. 2. If the path is not one of the allowed ones, check if it is and allowed file. 2. Do not try to check for '/' or '\' but verify that the path instead get the path directory and ensure that is the one for the logs and no other. This should fix xharness and keep CodeQL happy. --- tests/xharness/Jenkins/TestServer.cs | 43 ++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/tests/xharness/Jenkins/TestServer.cs b/tests/xharness/Jenkins/TestServer.cs index d739cdccfd9..62962488e31 100644 --- a/tests/xharness/Jenkins/TestServer.cs +++ b/tests/xharness/Jenkins/TestServer.cs @@ -11,8 +11,32 @@ using Xharness.Jenkins.TestTasks; namespace Xharness.Jenkins { - + class TestServer { + + static IReadOnlySet AllowedPaths = new HashSet (StringComparer.Ordinal) { + "/", + "/index.html", + "/set-option", + "/select", + "/deselect", + "/stop", + "/run", + "/build", + "/reload-devices", + "/reload-simulators", + "/quit", + "/favicon.ico", + "/index.html", + }; + + static IReadOnlySet AllowedFiles = new HashSet (StringComparer.Ordinal) { + "index.html", + "xharness.css", + "xharness.js", + }; + + public Task RunAsync (Jenkins jenkins, HtmlReportWriter htmlReportWriter) { @@ -95,8 +119,23 @@ IEnumerable find_tasks (StreamWriter writer, string ids) } string serveFile = null; + // do not allow requests that are not http or https + if (request.Url.Scheme != Uri.UriSchemeHttp && request.Url.Scheme != Uri.UriSchemeHttps) { + response.StatusCode = 400; + response.StatusDescription = "Bad Request"; + response.OutputStream.Write (System.Text.Encoding.UTF8.GetBytes ("Invalid local path")); + return; + } var localPath = request.Url.LocalPath; - if (localPath.Contains ("..") || localPath.Contains ("/") || localPath.Contains ("\\")) { + var file = Path.GetFileName (localPath); + var directoryName = Path.GetDirectoryName (localPath); + var jenkinsDirectoryName = $"/{Path.GetFileName (jenkins.LogDirectory)}"; + + // for the request to be valid the local path has to be one of the following + // 1. local path should be one of the supported ones + // 2. Be index.html + // 3. Its directory name be the same as the log directory name, no other directory is allowed + if (!AllowedPaths.Contains (localPath) && !AllowedFiles.Contains (file) && !directoryName.StartsWith (jenkinsDirectoryName)) { // Validate that we're not requested to serve any file on the file system. // Ref: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/2351243 response.StatusCode = 400;