From 6b4fef806cbcf39fcbed06119da036449ae82a00 Mon Sep 17 00:00:00 2001 From: kur$ <87440352+1kurs1@users.noreply.github.com> Date: Sat, 9 Aug 2025 20:58:36 +0300 Subject: [PATCH] fix: Added protection against deleting symlinks (#2288) This PR improves the safety and reliability of the deleteOldFiles() function by: Preventing symlink attacks Uses std::filesystem::canonical() to resolve all paths, eliminating ./.. and symlinks Verifies each file is actually inside the target directory before deletion Safer file operations Explicitly skips non-regular files (directories/symlinks) --------- Co-authored-by: Nik --- main/gui/source/init/tasks.cpp | 22 +++++++++++++++++----- main/gui/source/window/linux_window.cpp | 3 ++- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/main/gui/source/init/tasks.cpp b/main/gui/source/init/tasks.cpp index 18616f9b9..cdf8c907d 100644 --- a/main/gui/source/init/tasks.cpp +++ b/main/gui/source/init/tasks.cpp @@ -20,6 +20,7 @@ #include #include +#include namespace hex::init { @@ -202,10 +203,19 @@ namespace hex::init { auto keepNewest = [&](u32 count, const paths::impl::DefaultPath &pathType) { for (const auto &path : pathType.write()) { try { + const auto canonicalPath = std::filesystem::canonical(path); std::vector files; - for (const auto& file : std::filesystem::directory_iterator(path)) - files.push_back(file); + for (const auto &file : std::filesystem::directory_iterator(canonicalPath)){ + // Skip symlinks and directories + if (!file.is_regular_file()) + continue; + + if (std::filesystem::canonical(file.path()).native().starts_with(canonicalPath.native())) + files.push_back(file); + else + log::warn("Skip file outside directory {}", file.path().string()); + } if (files.size() <= count) return; @@ -214,10 +224,12 @@ namespace hex::init { return std::filesystem::last_write_time(a) > std::filesystem::last_write_time(b); }); - for (auto it = files.begin() + count; it != files.end(); it += 1) - std::filesystem::remove(it->path()); + for (auto it = files.begin() + count; it != files.end(); ++it){ + if (it->is_regular_file()) + std::filesystem::remove(it->path()); + } } catch (std::filesystem::filesystem_error &e) { - log::error("Failed to clear old file! {}", e.what()); + log::error("Failed to clear old file in directory '{}'! {}", wolv::util::toUTF8String(path), e.what()); result = false; } } diff --git a/main/gui/source/window/linux_window.cpp b/main/gui/source/window/linux_window.cpp index 29b45563a..091974746 100644 --- a/main/gui/source/window/linux_window.cpp +++ b/main/gui/source/window/linux_window.cpp @@ -138,7 +138,8 @@ namespace hex { // Add plugin library folders to dll search path for (const auto &path : paths::Libraries.read()) { if (std::fs::exists(path)) - setenv("LD_LIBRARY_PATH", fmt::format("{};{}", hex::getEnvironmentVariable("LD_LIBRARY_PATH").value_or(""), path.string().c_str()).c_str(), true); + + setenv("LD_LIBRARY_PATH", fmt::format("{}:{}", hex::getEnvironmentVariable("LD_LIBRARY_PATH").value_or(""), path.string().c_str()).c_str(), true); } // Redirect stdout to log file if we're not running in a terminal