chore: jail CDirectory to the basepath and prevent accessing data outside of the main directory

This commit is contained in:
Almamu 2025-04-07 11:13:54 +02:00
parent 29fb78b695
commit 1b33eff462
3 changed files with 50 additions and 36 deletions

View File

@ -1,5 +1,6 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <cstring>
#include <utility> #include <utility>
#include "CAssetLoadException.h" #include "CAssetLoadException.h"
@ -7,15 +8,28 @@
using namespace WallpaperEngine::Assets; using namespace WallpaperEngine::Assets;
CDirectory::CDirectory (std::filesystem::path basepath) : m_basepath (std::move (basepath)) { CDirectory::CDirectory (const std::filesystem::path& basepath) {
// ensure the specified path exists // ensure the specified path exists
struct stat buffer {}; struct stat buffer {};
if (stat (this->m_basepath.c_str (), &buffer) != 0) // resolve the path to it's real location
throw CAssetLoadException (this->m_basepath, "Cannot find directory"); char* finalpath = realpath (basepath.c_str (), nullptr);
if (!S_ISDIR (buffer.st_mode)) if (finalpath == nullptr) {
throw CAssetLoadException (this->m_basepath, "Expected directory but found a file"); throw CAssetLoadException (basepath, "Cannot resolve to real path in the filesystem");
}
if (stat (finalpath, &buffer) != 0) {
throw CAssetLoadException (basepath, "Cannot find directory");
}
if (!S_ISDIR (buffer.st_mode)) {
throw CAssetLoadException (basepath, "Expected directory but found a file");
}
this->m_basepath = finalpath;
// the value returned from realpath has to be free'd
free (finalpath);
} }
std::filesystem::path CDirectory::resolveRealFile (const std::string& filename) const { std::filesystem::path CDirectory::resolveRealFile (const std::string& filename) const {
@ -25,8 +39,28 @@ std::filesystem::path CDirectory::resolveRealFile (const std::string& filename)
const uint8_t* CDirectory::readFile (const std::string& filename, uint32_t* length) const { const uint8_t* CDirectory::readFile (const std::string& filename, uint32_t* length) const {
const std::filesystem::path final = std::filesystem::path (this->m_basepath) / filename; const std::filesystem::path final = std::filesystem::path (this->m_basepath) / filename;
// resolve real path and ensure it's within the bounds
char* finalpath = realpath (final.c_str (), nullptr);
if (finalpath == nullptr) {
throw CAssetLoadException (filename, "Cannot find file");
}
// ensure it's within the basepath
size_t baseLength = strlen (finalpath);
if (baseLength < this->m_basepath.string ().size()) {
free (finalpath);
throw CAssetLoadException (filename, "File is not a child of the given directory");
}
if (strncmp (this->m_basepath.c_str (), finalpath, this->m_basepath.string ().size ()) != 0) {
free (finalpath);
throw CAssetLoadException (filename, "File is not a child of the given directory");
}
// first check the cache, if the file is there already just return the data in there // first check the cache, if the file is there already just return the data in there
const auto it = this->m_cache.find (final); const auto it = this->m_cache.find (finalpath);
if (it != this->m_cache.end ()) { if (it != this->m_cache.end ()) {
if (length != nullptr) if (length != nullptr)
@ -35,12 +69,12 @@ const uint8_t* CDirectory::readFile (const std::string& filename, uint32_t* leng
return it->second.address; return it->second.address;
} }
// TODO: PREVENT ESCAPING THE BASE PATH ON INITIALIZATION FILE* fp = fopen (finalpath, "rb");
FILE* fp = fopen (final.c_str (), "rb"); if (fp == nullptr) {
free (finalpath);
if (fp == nullptr) throw CAssetLoadException (filename, "Cannot open file for reading");
throw CAssetLoadException (filename, "Cannot find file"); }
// go to the end, get the position and return to the beginning // go to the end, get the position and return to the beginning
fseek (fp, 0, SEEK_END); fseek (fp, 0, SEEK_END);
@ -55,8 +89,11 @@ const uint8_t* CDirectory::readFile (const std::string& filename, uint32_t* leng
throw CAssetLoadException (filename, "Unexpected error when reading the file"); throw CAssetLoadException (filename, "Unexpected error when reading the file");
} }
if (length != nullptr) if (length != nullptr) {
*length = size; *length = size;
}
free (finalpath);
return contents; return contents;
} }

View File

@ -14,7 +14,7 @@ namespace WallpaperEngine::Assets {
*/ */
class CDirectory final : public CContainer { class CDirectory final : public CContainer {
public: public:
explicit CDirectory (std::filesystem::path basepath); explicit CDirectory (const std::filesystem::path& basepath);
/** @inheritdoc */ /** @inheritdoc */
[[nodiscard]] std::filesystem::path resolveRealFile (const std::string& filename) const override; [[nodiscard]] std::filesystem::path resolveRealFile (const std::string& filename) const override;

View File

@ -46,29 +46,6 @@ if (process_type.empty()) {
command_line->AppendSwitch("use-mock-keychain"); command_line->AppendSwitch("use-mock-keychain");
#endif #endif
}*/ }*/
// TODO: ADD FLAGS
/*"--disable-features",
"IsolateOrigins,HardwareMediaKeyHandling,WebContentsOcclusion,RendererCodeIntegrityEnabled,site-per-process",
"--disable-gpu-shader-disk-cache",
"--disable-site-isolation-trials",
"--disable-web-security",
"--remote-allow-origins",
"*",
//"--force-device-scale-factor",
//"1", // this can also be 2
//"--high-dpi-support",
//"1",
"--autoplay-policy",
"no-user-gesture-required",
"--disable-background-timer-throttling",
"--disable-backgrounding-occluded-windows",
"--disable-background-media-suspend",
"--disable-renderer-backgrounding",
"--disable-test-root-certs",
"--disable-bundled-ppapi-flash",
"--disable-breakpad",
"--disable-field-trial-config",
"--no-experiments"*/
} }
void CBrowserApp::OnBeforeChildProcessLaunch(CefRefPtr<CefCommandLine> command_line) { void CBrowserApp::OnBeforeChildProcessLaunch(CefRefPtr<CefCommandLine> command_line) {