Fixup VFS error checking

Many users of VFS didn't check for nullptr or 0 results leading to
various potential issues, to mitigate this introduce error checking to
VFS by default. The original variants can still be used through the
*Unchecked family of functions.
This commit is contained in:
Billy Laws 2021-03-05 15:20:26 +00:00 committed by ◱ Mark
parent 87ac25c1a1
commit 6390561f0f
8 changed files with 61 additions and 16 deletions

View File

@ -16,10 +16,11 @@ namespace skyline::loader {
if (exeFs == nullptr) if (exeFs == nullptr)
throw exception("Cannot load a null ExeFS"); throw exception("Cannot load a null ExeFS");
auto nsoFile{exeFs->OpenFile("rtld")}; if (!exeFs->FileExists("rtld"))
if (nsoFile == nullptr)
throw exception("Cannot load an ExeFS that doesn't contain rtld"); throw exception("Cannot load an ExeFS that doesn't contain rtld");
auto nsoFile{exeFs->OpenFile("rtld")};
state.process->memory.InitializeVmm(process->npdm.meta.flags.type); state.process->memory.InitializeVmm(process->npdm.meta.flags.type);
auto loadInfo{NsoLoader::LoadNso(loader, nsoFile, process, state, 0, "rtld.nso")}; auto loadInfo{NsoLoader::LoadNso(loader, nsoFile, process, state, 0, "rtld.nso")};

View File

@ -50,7 +50,7 @@ namespace skyline::loader {
// Use the first icon file available // Use the first icon file available
for (const auto &entry : root->Read()) { for (const auto &entry : root->Read()) {
if (entry.name.rfind("icon") == 0) { if (entry.name.rfind("icon") == 0) {
icon = controlRomFs->OpenFile(entry.name); icon = controlRomFs->OpenFileUnchecked(entry.name);
break; break;
} }
} }

View File

@ -23,7 +23,7 @@ namespace skyline::service::fssrv {
return result::InvalidSize; return result::InvalidSize;
} }
response.Push<u32>(static_cast<u32>(backing->Read(request.outputBuf.at(0), offset))); response.Push<u32>(static_cast<u32>(backing->ReadUnchecked(request.outputBuf.at(0), offset)));
return {}; return {};
} }

View File

@ -38,7 +38,7 @@ namespace skyline::service::fssrv {
if (!backing->FileExists(path)) if (!backing->FileExists(path))
return result::PathDoesNotExist; return result::PathDoesNotExist;
auto file{backing->OpenFile(path, mode)}; auto file{backing->OpenFileUnchecked(path, mode)};
if (file == nullptr) if (file == nullptr)
return result::UnexpectedFailure; return result::UnexpectedFailure;
else else

View File

@ -53,14 +53,30 @@ namespace skyline::vfs {
* @param offset The offset to start reading from * @param offset The offset to start reading from
* @return The amount of bytes read * @return The amount of bytes read
*/ */
size_t Read(span <u8> output, size_t offset = 0) { size_t ReadUnchecked(span <u8> output, size_t offset = 0) {
if (!mode.read) if (!mode.read)
throw exception("Attempting to read a backing that is not readable"); throw exception("Attempting to read a backing that is not readable");
if ((static_cast<ssize_t>(size) - offset) < output.size()) return ReadImpl(output, offset);
};
/**
* @brief Read bytes from the backing at a particular offset to a buffer and check to ensure the full size was read
* @param output The object to write the data read to
* @param offset The offset to start reading from
* @return The amount of bytes read
*/
size_t Read(span <u8> output, size_t offset = 0) {
if (offset > size)
throw exception("Offset cannot be past the end of a backing");
if ((size - offset) < output.size())
throw exception("Trying to read past the end of a backing: 0x{:X}/0x{:X} (Offset: 0x{:X})", output.size(), size, offset); throw exception("Trying to read past the end of a backing: 0x{:X}/0x{:X} (Offset: 0x{:X})", output.size(), size, offset);
return ReadImpl(output, offset); if (ReadUnchecked(output, offset) != size)
throw exception("Failed to read the requested size from backing");
return size;
}; };
/** /**

View File

@ -25,7 +25,7 @@ namespace skyline::vfs {
size_t sectorOffset{offset % SectorSize}; size_t sectorOffset{offset % SectorSize};
if (sectorOffset == 0) { if (sectorOffset == 0) {
size_t read{backing->Read(output, offset)}; size_t read{backing->ReadUnchecked(output, offset)};
if (read != size) if (read != size)
return 0; return 0;
{ {
@ -38,7 +38,7 @@ namespace skyline::vfs {
size_t sectorStart{offset - sectorOffset}; size_t sectorStart{offset - sectorOffset};
std::vector<u8> blockBuf(SectorSize); std::vector<u8> blockBuf(SectorSize);
size_t read{backing->Read(blockBuf, sectorStart)}; size_t read{backing->ReadUnchecked(blockBuf, sectorStart)};
if (read != SectorSize) if (read != SectorSize)
return 0; return 0;
{ {
@ -53,6 +53,6 @@ namespace skyline::vfs {
size_t readInBlock{SectorSize - sectorOffset}; size_t readInBlock{SectorSize - sectorOffset};
std::memcpy(output.data(), blockBuf.data() + sectorOffset, readInBlock); std::memcpy(output.data(), blockBuf.data() + sectorOffset, readInBlock);
return readInBlock + Read(output.subspan(readInBlock), offset + readInBlock); return readInBlock + ReadUnchecked(output.subspan(readInBlock), offset + readInBlock);
} }
} }

View File

@ -62,15 +62,29 @@ namespace skyline::vfs {
* @brief Opens a file from the specified path in the filesystem * @brief Opens a file from the specified path in the filesystem
* @param path The path to the file * @param path The path to the file
* @param mode The mode to open the file with * @param mode The mode to open the file with
* @return A shared pointer to a Backing object of the file * @return A shared pointer to a Backing object of the file (may be nullptr)
*/ */
std::shared_ptr<Backing> OpenFile(const std::string &path, Backing::Mode mode = {true, false, false}) { std::shared_ptr<Backing> OpenFileUnchecked(const std::string &path, Backing::Mode mode = {true, false, false}) {
if (!mode.write && !mode.read) if (!mode.write && !mode.read)
throw exception("Cannot open a file with a mode that is neither readable nor writable"); throw exception("Cannot open a file with a mode that is neither readable nor writable");
return OpenFileImpl(path, mode); return OpenFileImpl(path, mode);
} }
/**
* @brief Opens a file from the specified path in the filesystem and throws an exception if opening fails
* @param path The path to the file
* @param mode The mode to open the file with
* @return A shared pointer to a Backing object of the file
*/
std::shared_ptr<Backing> OpenFile(const std::string &path, Backing::Mode mode = {true, false, false}) {
auto file{OpenFileUnchecked(path, mode)};
if (file == nullptr)
throw exception("Failed to open file: {}", path);
return file;
}
/** /**
* @brief Queries the type of the entry given by path * @brief Queries the type of the entry given by path
* @param path The path to the entry * @param path The path to the entry
@ -104,13 +118,27 @@ namespace skyline::vfs {
* @brief Opens a directory from the specified path in the filesystem * @brief Opens a directory from the specified path in the filesystem
* @param path The path to the directory * @param path The path to the directory
* @param listMode The list mode for the directory * @param listMode The list mode for the directory
* @return A shared pointer to a Directory object of the directory * @return A shared pointer to a Directory object of the directory (may be nullptr)
*/ */
std::shared_ptr<Directory> OpenDirectory(const std::string &path, Directory::ListMode listMode = {true, true}) { std::shared_ptr<Directory> OpenDirectoryUnchecked(const std::string &path, Directory::ListMode listMode = {true, true}) {
if (!listMode.raw) if (!listMode.raw)
throw exception("Cannot open a directory with an empty listMode"); throw exception("Cannot open a directory with an empty listMode");
return OpenDirectoryImpl(path, listMode); return OpenDirectoryImpl(path, listMode);
}; };
/**
* @brief Opens a directory from the specified path in the filesystem and throws an exception if opening fails
* @param path The path to the directory
* @param listMode The list mode for the directory
* @return A shared pointer to a Directory object of the directory
*/
std::shared_ptr<Directory> OpenDirectory(const std::string &path, Directory::ListMode listMode = {true, true}) {
auto dir{OpenDirectoryUnchecked(path, listMode)};
if (dir == nullptr)
throw exception("Failed to open directory: {}", path);
return dir;
};
}; };
} }

View File

@ -16,7 +16,7 @@ namespace skyline::vfs {
protected: protected:
size_t ReadImpl(span <u8> output, size_t offset) override { size_t ReadImpl(span <u8> output, size_t offset) override {
return backing->Read(output, baseOffset + offset); return backing->ReadUnchecked(output, baseOffset + offset);
} }
public: public: