Handle VFS reads into trapped memory regions

pread will refuse to read into any trapped regions so implement a manual path with a staging buffer and memcpy for such cases
This commit is contained in:
Billy Laws 2022-05-10 18:33:55 +01:00
parent 1609fd2a32
commit d2acec24f5

View File

@ -21,11 +21,28 @@ namespace skyline::vfs {
} }
size_t OsBacking::ReadImpl(span<u8> output, size_t offset) { size_t OsBacking::ReadImpl(span<u8> output, size_t offset) {
auto ret{pread64(fd, output.data(), output.size(), static_cast<off64_t>(offset))}; size_t bytesRead{};
if (ret < 0) while (bytesRead < output.size()) {
throw exception("Failed to read from fd: {}", strerror(errno)); auto ret{pread64(fd, output.data() + bytesRead, output.size() - bytesRead, static_cast<off64_t>(offset + bytesRead))};
if (ret < 0) {
if (errno == EFAULT) {
// If EFAULT is returned then we're reading into a trapped region so create a temporary buffer and read into that instead
// This is required since pread doesn't trigger signal handlers itself
std::vector<u8> buffer(output.size() - bytesRead);
ret = pread64(fd, buffer.data(), buffer.size(), static_cast<off64_t>(offset + bytesRead));
if (ret >= 0) {
output.subspan(bytesRead).copy_from(buffer);
bytesRead += static_cast<size_t>(ret);
continue;
}
}
return static_cast<size_t>(ret); throw exception("Failed to read from fd: {}", strerror(errno));
} else {
bytesRead += static_cast<size_t>(ret);
}
}
return output.size();
} }
size_t OsBacking::WriteImpl(span<u8> input, size_t offset) { size_t OsBacking::WriteImpl(span<u8> input, size_t offset) {