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 <werwolv98@gmail.com>
This commit is contained in:
kur$
2025-08-09 20:58:36 +03:00
committed by GitHub
parent 4e5b2675a0
commit 6b4fef806c
2 changed files with 19 additions and 6 deletions

View File

@@ -20,6 +20,7 @@
#include <wolv/io/fs.hpp>
#include <wolv/io/file.hpp>
#include <wolv/utils/string.hpp>
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<std::filesystem::directory_entry> 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;
}
}

View File

@@ -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