From 74f8769074f34e084411ded939ea856a0233c1de Mon Sep 17 00:00:00 2001 From: nussaiba shaikh Date: Fri, 16 Oct 2026 16:07:17 +0530 Subject: [PATCH] donate-cpu-server: do not serve files outside the result path --- test/tools/donate_cpu_server_test.py | 29 ++++++++++++++++++++++++++++ tools/donate-cpu-server.py | 5 +++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/test/tools/donate_cpu_server_test.py b/test/tools/donate_cpu_server_test.py index a9d9074a339..fdb5b415a76 100644 --- a/test/tools/donate_cpu_server_test.py +++ b/test/tools/donate_cpu_server_test.py @@ -15,3 +15,32 @@ def test_parse_req(): _test_parse_req("GET /head-uninitvar?pkgs=1 HTTP/1.1", '/head-uninitvar', {'pkgs': '1'}) _test_parse_req("GET /crash.html?pkgs=1 HTTP/1.1", '/crash.html', {'pkgs': '1'}) _test_parse_req("GET /head-uninitvar?pkgs=1&pkgs2=2 HTTP/1.1", '/head-uninitvar', {'pkgs': '1', 'pkgs2': '2'}) + +class _Connection: + def __init__(self): + self.data = b'' + + def send(self, data): + self.data += data + return len(data) + + def close(self): + pass + +def _http_get(result_path, url): + conn = _Connection() + donate_cpu_server.HttpClientThread(conn, 'GET {} HTTP/1.1'.format(url), str(result_path), []).run() + return conn.data.decode('utf-8') + +def test_file_outside_result_path(tmp_path): + result_path = tmp_path / 'donated-results' + result_path.mkdir() + (result_path / 'pkg').write_text('result data') + (tmp_path / 'secret.txt').write_text('secret data') + + resp = _http_get(result_path, '/pkg') + assert resp.startswith('HTTP/1.1 200 OK') and resp.endswith('result data') + + resp = _http_get(result_path, '/../secret.txt') + assert resp.startswith('HTTP/1.1 404 Not Found') + assert 'secret data' not in resp diff --git a/tools/donate-cpu-server.py b/tools/donate-cpu-server.py index 74647e32f70..a45b319dcf5 100755 --- a/tools/donate-cpu-server.py +++ b/tools/donate-cpu-server.py @@ -1275,8 +1275,9 @@ def run(self): text = clientsReport(self.resultPath) httpGetResponse(self.connection, text, 'text/html') else: - filename = self.resultPath + url - if not os.path.isfile(filename): + result_path = os.path.normpath(self.resultPath) + filename = os.path.normpath(result_path + url) + if os.path.commonpath([result_path, filename]) != result_path or not os.path.isfile(filename): print_ts('HTTP/1.1 404 Not Found') self.connection.send(b'HTTP/1.1 404 Not Found\r\n\r\n') else: