3
0
Fork 0
forked from suyu/suyu

Merge pull request #2161 from lioncash/handle-table

kernel/handle_table: Allow process capabilities to limit the handle table size
This commit is contained in:
bunnei 2019-02-27 11:22:26 -05:00 committed by GitHub
commit eb5a3dd1c7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 63 additions and 19 deletions

View file

@ -14,6 +14,7 @@ constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED{ErrorModule::Kernel, 7};
constexpr ResultCode ERR_INVALID_CAPABILITY_DESCRIPTOR{ErrorModule::Kernel, 14}; constexpr ResultCode ERR_INVALID_CAPABILITY_DESCRIPTOR{ErrorModule::Kernel, 14};
constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101}; constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101};
constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102}; constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102};
constexpr ResultCode ERR_OUT_OF_MEMORY{ErrorModule::Kernel, 104};
constexpr ResultCode ERR_HANDLE_TABLE_FULL{ErrorModule::Kernel, 105}; constexpr ResultCode ERR_HANDLE_TABLE_FULL{ErrorModule::Kernel, 105};
constexpr ResultCode ERR_INVALID_ADDRESS_STATE{ErrorModule::Kernel, 106}; constexpr ResultCode ERR_INVALID_ADDRESS_STATE{ErrorModule::Kernel, 106};
constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS{ErrorModule::Kernel, 108}; constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS{ErrorModule::Kernel, 108};

View file

@ -14,32 +14,47 @@
namespace Kernel { namespace Kernel {
namespace { namespace {
constexpr u16 GetSlot(Handle handle) { constexpr u16 GetSlot(Handle handle) {
return handle >> 15; return static_cast<u16>(handle >> 15);
} }
constexpr u16 GetGeneration(Handle handle) { constexpr u16 GetGeneration(Handle handle) {
return handle & 0x7FFF; return static_cast<u16>(handle & 0x7FFF);
} }
} // Anonymous namespace } // Anonymous namespace
HandleTable::HandleTable() { HandleTable::HandleTable() {
next_generation = 1;
Clear(); Clear();
} }
HandleTable::~HandleTable() = default; HandleTable::~HandleTable() = default;
ResultCode HandleTable::SetSize(s32 handle_table_size) {
if (static_cast<u32>(handle_table_size) > MAX_COUNT) {
return ERR_OUT_OF_MEMORY;
}
// Values less than or equal to zero indicate to use the maximum allowable
// size for the handle table in the actual kernel, so we ignore the given
// value in that case, since we assume this by default unless this function
// is called.
if (handle_table_size > 0) {
table_size = static_cast<u16>(handle_table_size);
}
return RESULT_SUCCESS;
}
ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
DEBUG_ASSERT(obj != nullptr); DEBUG_ASSERT(obj != nullptr);
u16 slot = next_free_slot; const u16 slot = next_free_slot;
if (slot >= generations.size()) { if (slot >= table_size) {
LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use."); LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use.");
return ERR_HANDLE_TABLE_FULL; return ERR_HANDLE_TABLE_FULL;
} }
next_free_slot = generations[slot]; next_free_slot = generations[slot];
u16 generation = next_generation++; const u16 generation = next_generation++;
// Overflow count so it fits in the 15 bits dedicated to the generation in the handle. // Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
// Horizon OS uses zero to represent an invalid handle, so skip to 1. // Horizon OS uses zero to represent an invalid handle, so skip to 1.
@ -64,10 +79,11 @@ ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
} }
ResultCode HandleTable::Close(Handle handle) { ResultCode HandleTable::Close(Handle handle) {
if (!IsValid(handle)) if (!IsValid(handle)) {
return ERR_INVALID_HANDLE; return ERR_INVALID_HANDLE;
}
u16 slot = GetSlot(handle); const u16 slot = GetSlot(handle);
objects[slot] = nullptr; objects[slot] = nullptr;
@ -77,10 +93,10 @@ ResultCode HandleTable::Close(Handle handle) {
} }
bool HandleTable::IsValid(Handle handle) const { bool HandleTable::IsValid(Handle handle) const {
std::size_t slot = GetSlot(handle); const std::size_t slot = GetSlot(handle);
u16 generation = GetGeneration(handle); const u16 generation = GetGeneration(handle);
return slot < MAX_COUNT && objects[slot] != nullptr && generations[slot] == generation; return slot < table_size && objects[slot] != nullptr && generations[slot] == generation;
} }
SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const { SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const {
@ -97,7 +113,7 @@ SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const {
} }
void HandleTable::Clear() { void HandleTable::Clear() {
for (u16 i = 0; i < MAX_COUNT; ++i) { for (u16 i = 0; i < table_size; ++i) {
generations[i] = i + 1; generations[i] = i + 1;
objects[i] = nullptr; objects[i] = nullptr;
} }

View file

@ -49,6 +49,20 @@ public:
HandleTable(); HandleTable();
~HandleTable(); ~HandleTable();
/**
* Sets the number of handles that may be in use at one time
* for this handle table.
*
* @param handle_table_size The desired size to limit the handle table to.
*
* @returns an error code indicating if initialization was successful.
* If initialization was not successful, then ERR_OUT_OF_MEMORY
* will be returned.
*
* @pre handle_table_size must be within the range [0, 1024]
*/
ResultCode SetSize(s32 handle_table_size);
/** /**
* Allocates a handle for the given object. * Allocates a handle for the given object.
* @return The created Handle or one of the following errors: * @return The created Handle or one of the following errors:
@ -103,14 +117,21 @@ private:
*/ */
std::array<u16, MAX_COUNT> generations; std::array<u16, MAX_COUNT> generations;
/**
* The limited size of the handle table. This can be specified by process
* capabilities in order to restrict the overall number of handles that
* can be created in a process instance
*/
u16 table_size = static_cast<u16>(MAX_COUNT);
/** /**
* Global counter of the number of created handles. Stored in `generations` when a handle is * Global counter of the number of created handles. Stored in `generations` when a handle is
* created, and wraps around to 1 when it hits 0x8000. * created, and wraps around to 1 when it hits 0x8000.
*/ */
u16 next_generation; u16 next_generation = 1;
/// Head of the free slots linked list. /// Head of the free slots linked list.
u16 next_free_slot; u16 next_free_slot = 0;
}; };
} // namespace Kernel } // namespace Kernel

View file

@ -99,7 +99,13 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
vm_manager.Reset(metadata.GetAddressSpaceType()); vm_manager.Reset(metadata.GetAddressSpaceType());
const auto& caps = metadata.GetKernelCapabilities(); const auto& caps = metadata.GetKernelCapabilities();
return capabilities.InitializeForUserProcess(caps.data(), caps.size(), vm_manager); const auto capability_init_result =
capabilities.InitializeForUserProcess(caps.data(), caps.size(), vm_manager);
if (capability_init_result.IsError()) {
return capability_init_result;
}
return handle_table.SetSize(capabilities.GetHandleTableSize());
} }
void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {

View file

@ -96,7 +96,7 @@ void ProcessCapabilities::InitializeForMetadatalessProcess() {
interrupt_capabilities.set(); interrupt_capabilities.set();
// Allow using the maximum possible amount of handles // Allow using the maximum possible amount of handles
handle_table_size = static_cast<u32>(HandleTable::MAX_COUNT); handle_table_size = static_cast<s32>(HandleTable::MAX_COUNT);
// Allow all debugging capabilities. // Allow all debugging capabilities.
is_debuggable = true; is_debuggable = true;
@ -337,7 +337,7 @@ ResultCode ProcessCapabilities::HandleHandleTableFlags(u32 flags) {
return ERR_RESERVED_VALUE; return ERR_RESERVED_VALUE;
} }
handle_table_size = (flags >> 16) & 0x3FF; handle_table_size = static_cast<s32>((flags >> 16) & 0x3FF);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }

View file

@ -156,7 +156,7 @@ public:
} }
/// Gets the number of total allowable handles for the process' handle table. /// Gets the number of total allowable handles for the process' handle table.
u32 GetHandleTableSize() const { s32 GetHandleTableSize() const {
return handle_table_size; return handle_table_size;
} }
@ -252,7 +252,7 @@ private:
u64 core_mask = 0; u64 core_mask = 0;
u64 priority_mask = 0; u64 priority_mask = 0;
u32 handle_table_size = 0; s32 handle_table_size = 0;
u32 kernel_version = 0; u32 kernel_version = 0;
ProgramType program_type = ProgramType::SysModule; ProgramType program_type = ProgramType::SysModule;