From 1ae7497b6a8a6aca45e6fc9831f764729af82af0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20W=C3=BCthrich?= Date: Fri, 9 Aug 2024 16:21:07 +0200 Subject: fileapi: Restrict reply object file path lengths Fixes: #23389 --- Source/cmFileAPI.cxx | 23 +++++++++++++++++++++- Tests/RunCMake/FileAPI/cmakeFiles-v1-check.py | 6 ++++++ Tests/RunCMake/FileAPI/codemodel-v2-check.py | 3 +++ .../FileAPI/codemodel-v2-data/directories/dir.json | 3 ++- .../directories/dir_very-long.json | 11 +++++++++++ .../codemodel-v2-data/projects/codemodel-v2.json | 1 + Tests/RunCMake/FileAPI/dir/CMakeLists.txt | 1 + .../RunCMake/FileAPI/dir/very-long/CMakeLists.txt | 0 8 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir_very-long.json create mode 100644 Tests/RunCMake/FileAPI/dir/very-long/CMakeLists.txt diff --git a/Source/cmFileAPI.cxx b/Source/cmFileAPI.cxx index ba2167b..1b2f365 100644 --- a/Source/cmFileAPI.cxx +++ b/Source/cmFileAPI.cxx @@ -200,7 +200,28 @@ std::string cmFileAPI::WriteJsonFile( } // Compute the final name for the file. - fileName = prefix + "-" + computeSuffix(tmpFile) + ".json"; + std::string suffix = computeSuffix(tmpFile); + std::string suffixWithExtension = cmStrCat("-", suffix, ".json"); + fileName = cmStrCat(prefix, suffixWithExtension); + + // Truncate the file name length + // eCryptFS has a maximal file name length recommendation of 140 + size_t const maxFileNameLength = 140; + size_t const fileNameLength = fileName.size(); + if (fileNameLength > maxFileNameLength) { + size_t const newHashLength = 20; + size_t const newSuffixLength = + suffixWithExtension.size() - suffix.size() + newHashLength; + size_t const overLength = + fileNameLength - maxFileNameLength + newSuffixLength; + size_t const startPos = fileNameLength - overLength; + std::string const toBeRemoved = fileName.substr(startPos, overLength); + suffix = cmCryptoHash(cmCryptoHash::AlgoSHA256) + .HashString(toBeRemoved) + .substr(0, newHashLength); + suffixWithExtension = cmStrCat("-", suffix, ".json"); + fileName.replace(startPos, overLength, suffixWithExtension); + } // Create the destination. std::string file = this->APIv1 + "/reply"; diff --git a/Tests/RunCMake/FileAPI/cmakeFiles-v1-check.py b/Tests/RunCMake/FileAPI/cmakeFiles-v1-check.py index 9410c7e..54ca394 100644 --- a/Tests/RunCMake/FileAPI/cmakeFiles-v1-check.py +++ b/Tests/RunCMake/FileAPI/cmakeFiles-v1-check.py @@ -76,6 +76,12 @@ def check_object_cmakeFiles(o): "isCMake": None, }, { + "path": "^dir/very-long/CMakeLists\\.txt$", + "isGenerated": None, + "isExternal": None, + "isCMake": None, + }, + { "path": "^dir/dirtest\\.cmake$", "isGenerated": None, "isExternal": None, diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-check.py b/Tests/RunCMake/FileAPI/codemodel-v2-check.py index 36f9d33..b7b0090 100644 --- a/Tests/RunCMake/FileAPI/codemodel-v2-check.py +++ b/Tests/RunCMake/FileAPI/codemodel-v2-check.py @@ -94,6 +94,8 @@ def check_directory(c): assert is_string(actual["jsonFile"]) filepath = os.path.join(reply_dir, actual["jsonFile"]) + maximum_filename_length = 140 + assert len(actual["jsonFile"]) <= maximum_filename_length with open(filepath) as f: d = json.load(f) @@ -747,6 +749,7 @@ def gen_check_directories(c, g): read_codemodel_json_data("directories/object.json"), read_codemodel_json_data("directories/dir.json"), read_codemodel_json_data("directories/dir_dir.json"), + read_codemodel_json_data("directories/dir_very-long.json"), read_codemodel_json_data("directories/external.json"), read_codemodel_json_data("directories/fileset.json"), read_codemodel_json_data("directories/subdir.json"), diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir.json index 2a3756e..dfa1e8b 100644 --- a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir.json +++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir.json @@ -3,7 +3,8 @@ "build": "^dir$", "parentSource": "^\\.$", "childSources": [ - "^dir/dir$" + "^dir/dir$", + "^dir/very-long$" ], "targetIds": null, "projectName": "codemodel-v2", diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir_very-long.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir_very-long.json new file mode 100644 index 0000000..117f356 --- /dev/null +++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/directories/dir_very-long.json @@ -0,0 +1,11 @@ +{ + "source": "^dir/very-long", + "build": "^dir/very-long-directory-name-in-order-to-test-that-the-fileapi-codemodel-v2-directory-object-is-placed-in-a-json-file-on-disk-with-a-shortened-name$", + "parentSource": "^dir$", + "childSources": null, + "targetIds": null, + "projectName": "codemodel-v2", + "minimumCMakeVersion": "3.13", + "hasInstallRule": null, + "installers": [] +} diff --git a/Tests/RunCMake/FileAPI/codemodel-v2-data/projects/codemodel-v2.json b/Tests/RunCMake/FileAPI/codemodel-v2-data/projects/codemodel-v2.json index 8d2712d..9309407 100644 --- a/Tests/RunCMake/FileAPI/codemodel-v2-data/projects/codemodel-v2.json +++ b/Tests/RunCMake/FileAPI/codemodel-v2-data/projects/codemodel-v2.json @@ -15,6 +15,7 @@ "^\\.$", "^dir$", "^dir/dir$", + "^dir/very-long$", "^fileset$", "^subdir$" ], diff --git a/Tests/RunCMake/FileAPI/dir/CMakeLists.txt b/Tests/RunCMake/FileAPI/dir/CMakeLists.txt index 780445d..70b2ba7 100644 --- a/Tests/RunCMake/FileAPI/dir/CMakeLists.txt +++ b/Tests/RunCMake/FileAPI/dir/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(dir) +add_subdirectory(very-long very-long-directory-name-in-order-to-test-that-the-fileapi-codemodel-v2-directory-object-is-placed-in-a-json-file-on-disk-with-a-shortened-name) diff --git a/Tests/RunCMake/FileAPI/dir/very-long/CMakeLists.txt b/Tests/RunCMake/FileAPI/dir/very-long/CMakeLists.txt new file mode 100644 index 0000000..e69de29 -- cgit v0.12