kern: add new KCapability checks before creating process

This commit is contained in:
Michael Scire 2022-03-22 14:45:29 -07:00 committed by SciresM
parent 14e768cd10
commit 8cb3cfd835
3 changed files with 48 additions and 5 deletions

View file

@ -156,9 +156,10 @@ namespace ams::kern {
R_RETURN(page_table->MapIo(phys_addr, size, KMemoryPermission_UserReadWrite));
}
Result KCapabilities::MapRegion(const util::BitPack32 cap, KProcessPageTable *page_table) {
template<typename F>
ALWAYS_INLINE Result KCapabilities::ProcessMapRegionCapability(const util::BitPack32 cap, F f) {
/* Define the allowed memory regions. */
constexpr KMemoryRegionType MemoryRegions[] = {
constexpr const KMemoryRegionType MemoryRegions[] = {
KMemoryRegionType_None,
KMemoryRegionType_KernelTraceBuffer,
KMemoryRegionType_OnMemoryBootImage,
@ -173,12 +174,12 @@ namespace ams::kern {
const auto type = types[i];
const auto perm = ro[i] ? KMemoryPermission_UserRead : KMemoryPermission_UserReadWrite;
switch (type) {
case RegionType::None:
case RegionType::NoMapping:
break;
case RegionType::KernelTraceBuffer:
case RegionType::OnMemoryBootImage:
case RegionType::DTB:
R_TRY(page_table->MapRegion(MemoryRegions[static_cast<u32>(type)], perm));
R_TRY(f(MemoryRegions[static_cast<u32>(type)], perm));
break;
default:
R_THROW(svc::ResultNotFound());
@ -188,6 +189,22 @@ namespace ams::kern {
R_SUCCEED();
}
Result KCapabilities::MapRegion(const util::BitPack32 cap, KProcessPageTable *page_table) {
/* Map each region into the process's page table. */
R_RETURN(ProcessMapRegionCapability(cap, [page_table] ALWAYS_INLINE_LAMBDA (KMemoryRegionType region_type, KMemoryPermission perm) -> Result {
R_RETURN(page_table->MapRegion(region_type, perm));
}));
}
Result KCapabilities::CheckMapRegion(const util::BitPack32 cap) {
/* Check that each region has a physical backing store. */
R_RETURN(ProcessMapRegionCapability(cap, [] ALWAYS_INLINE_LAMBDA (KMemoryRegionType region_type, KMemoryPermission perm) -> Result {
MESOSPHERE_UNUSED(perm);
R_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().FindFirstDerived(region_type) != nullptr, svc::ResultOutOfRange());
R_SUCCEED();
}));
}
Result KCapabilities::SetInterruptPairCapability(const util::BitPack32 cap) {
/* Extract interrupts. */
const u32 ids[2] = { cap.Get<InterruptPair::InterruptId0>(), cap.Get<InterruptPair::InterruptId1>(), };
@ -320,4 +337,21 @@ namespace ams::kern {
R_SUCCEED();
}
Result KCapabilities::CheckCapabilities(svc::KUserPointer<const u32 *> user_caps, s32 num_caps) {
for (s32 i = 0; i < num_caps; ++i) {
/* Read the cap from userspace. */
u32 cap0;
R_TRY(user_caps.CopyArrayElementTo(std::addressof(cap0), i));
/* Check the capability refers to a valid region. */
const util::BitPack32 cap = { cap0 };
if (GetCapabilityType(cap) == CapabilityType::MapRegion) {
R_TRY(CheckMapRegion(cap));
}
}
R_SUCCEED();
}
}