Merge pull request #4638 from MarcZX100/codex/carry-win-getdents-throw-3327

fix(libkernel): throw for oversized directory entries
This commit is contained in:
Adrià 2026-10-13 17:32:31 +02:00 committed by GitHub
commit 068ab2aba6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 9 additions and 22 deletions

View File

@ -20,6 +20,7 @@
#include <map>
#include <memory>
#include <mutex>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
@ -137,8 +138,7 @@ int ReadDirectoryDescriptor(int fd, char* buf, int nbytes) {
while (state.cursor < state.entries.size()) {
const auto& [name, type] = state.entries[state.cursor];
if (name.size() > 255) {
if (used == 0) return SCE_KERNEL_ERROR_ENAMETOOLONG;
break;
throw std::runtime_error("Directory entry name exceeds the guest 255-byte limit");
}
const std::size_t record = (8 + name.size() + 1 + 3) & ~std::size_t{3};
if (used + record > static_cast<std::size_t>(nbytes)) {

View File

@ -10,6 +10,7 @@
#include <cstring>
#include <filesystem>
#include <fstream>
#include <stdexcept>
#include <string>
extern "C" {
@ -17,9 +18,6 @@ int APS5_VABI sceKernelOpen(const char*, int, std::uint16_t);
int APS5_VABI sceKernelClose(int);
int APS5_VABI sceKernelGetdents(int, char*, int);
int APS5_VABI sceKernelGetdirentries(int, char*, int, std::int64_t*);
int APS5_VABI getdents_nid_postfix(int, char*, int);
int APS5_VABI getdirentries_nid_postfix(int, char*, int, std::int64_t*);
int* APS5_VABI __error_nid_postfix();
}
static void Check(bool value, int line) {
@ -82,24 +80,13 @@ static void CheckOversizedName() {
const int directory = sceKernelOpen(root.string().c_str(), SCE_KERNEL_O_RDONLY | SCE_KERNEL_O_DIRECTORY, 0);
Require(directory >= 0);
std::array<char, 512> buffer;
buffer.fill('x');
Require(sceKernelGetdents(directory, buffer.data(), static_cast<int>(buffer.size())) == 24);
Require(std::strcmp(buffer.data() + 8, ".") == 0);
Require(std::strcmp(buffer.data() + 20, "..") == 0);
Require(std::all_of(buffer.begin() + 24, buffer.end(), [](char byte) { return byte == 'x'; }));
for (int attempt = 0; attempt < 2; ++attempt) {
buffer.fill('x');
Require(sceKernelGetdents(directory, buffer.data(), static_cast<int>(buffer.size())) == SCE_KERNEL_ERROR_ENAMETOOLONG);
Require(std::all_of(buffer.begin(), buffer.end(), [](char byte) { return byte == 'x'; }));
bool threw = false;
try {
sceKernelGetdents(directory, buffer.data(), static_cast<int>(buffer.size()));
} catch (const std::runtime_error&) {
threw = true;
}
*__error_nid_postfix() = 0;
Require(getdents_nid_postfix(directory, buffer.data(), static_cast<int>(buffer.size())) == -1);
Require(*__error_nid_postfix() == 63);
*__error_nid_postfix() = 0;
std::int64_t base = -1;
Require(getdirentries_nid_postfix(directory, buffer.data(), static_cast<int>(buffer.size()), &base) == -1);
Require(*__error_nid_postfix() == 63);
Require(std::all_of(buffer.begin(), buffer.end(), [](char byte) { return byte == 'x'; }));
Require(threw);
Require(sceKernelClose(directory) == 0);
std::filesystem::remove_all(root);
}