[FS] Add app data folder, add path safety checks

This commit is contained in:
wheremyfoodat 2023-01-16 01:06:43 +02:00
parent c16bf5c8aa
commit b1f2be98fa
6 changed files with 77 additions and 12 deletions

View file

@ -5,6 +5,7 @@
#include <SDL.h>
#include "cpu.hpp"
#include "io_file.hpp"
#include "memory.hpp"
#include "opengl.hpp"
#include "PICA/gpu.hpp"
@ -43,6 +44,12 @@ public:
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
window = SDL_CreateWindow("Alber", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL);
glContext = SDL_GL_CreateContext(window);
// Get path for saving files (AppData on Windows, /home/user/.local/share/ApplcationName on Linux, etc)
char* appData = SDL_GetPrefPath(nullptr, "Alber");
IOFile::setAppDataDir(appData);
SDL_free(appData);
reset();
}

View file

@ -1,6 +1,8 @@
#pragma once
#include <cassert>
#include <optional>
#include <string>
#include <type_traits>
#include <vector>
#include "helpers.hpp"
#include "memory.hpp"
@ -93,6 +95,51 @@ protected:
using Handle = u32;
Memory& mem;
// Returns if a specified 3DS path in UTF16 or ASCII format is safe or not
// A 3DS path is considered safe if its first character is '/' which means we're not trying to access anything outside the root of the fs
// And if it doesn't contain enough instances of ".." (Indicating "climb up a folder" in filesystems) to let the software climb up the directory tree
// And access files outside of the emulator's app data folder
template <u32 format>
bool isPathSafe(const FSPath& path) {
static_assert(format == PathType::ASCII || format == PathType::UTF16);
using String = std::conditional<format == PathType::UTF16, std::u16string, std::string>::type; // String type for the path
using Char = String::value_type; // Char type for the path
String pathString, dots;
if constexpr (std::is_same<String, std::u16string>()) {
pathString = path.utf16_string;
dots = u"..";
} else {
pathString = path.string;
dots = "..";
}
// If the path string doesn't begin with / then that means it's accessing outside the FS root, which is invalid & unsafe
if (pathString[0] != Char('/')) return false;
// Counts how many folders sans the root our file is nested under.
// If it's < 0 at any point of parsing, then the path is unsafe and tries to crawl outside our file sandbox.
// If it's 0 then this is the FS root.
// If it's > 0 then we're in a subdirectory of the root.
int level = 0;
// Split the string on / characters and see how many of the substrings are ".."
size_t pos = 0;
while ((pos = pathString.find(Char('/'))) != String::npos) {
String token = pathString.substr(0, pos);
pathString.erase(0, pos + 1);
if (token == dots) {
level--;
if (level < 0) return false;
} else {
level++;
}
}
return true;
}
public:
virtual std::string name() = 0;
virtual u64 getFreeBytes() = 0;

View file

@ -19,6 +19,7 @@
class IOFile {
FILE* handle = nullptr;
static inline std::filesystem::path appData = ""; // Directory for holding app data. AppData on Windows
public:
bool isOpen() {
@ -81,4 +82,11 @@ public:
bool rewind() {
return seek(0, SEEK_SET);
}
static void setAppDataDir(const char* dir) {
if (!dir) Helpers::panic("Failed to set app data directory");
appData = std::filesystem::path(dir);
}
static std::filesystem::path getAppData() { return IOFile::appData; }
};