kern: add new KCapability checks before creating process

This commit is contained in:
Michael Scire 2022-03-22 14:45:29 -07:00
parent 29a53bc572
commit a39448905a
3 changed files with 48 additions and 5 deletions

View file

@ -116,7 +116,7 @@ namespace ams::kern {
}; };
enum class RegionType : u32 { enum class RegionType : u32 {
None = 0, NoMapping = 0,
KernelTraceBuffer = 1, KernelTraceBuffer = 1,
OnMemoryBootImage = 2, OnMemoryBootImage = 2,
DTB = 3, DTB = 3,
@ -219,6 +219,10 @@ namespace ams::kern {
Result SetHandleTableCapability(const util::BitPack32 cap); Result SetHandleTableCapability(const util::BitPack32 cap);
Result SetDebugFlagsCapability(const util::BitPack32 cap); Result SetDebugFlagsCapability(const util::BitPack32 cap);
template<typename F>
static Result ProcessMapRegionCapability(const util::BitPack32 cap, F f);
static Result CheckMapRegion(const util::BitPack32 cap);
Result SetCapability(const util::BitPack32 cap, u32 &set_flags, u32 &set_svc, KProcessPageTable *page_table); Result SetCapability(const util::BitPack32 cap, u32 &set_flags, u32 &set_svc, KProcessPageTable *page_table);
Result SetCapabilities(const u32 *caps, s32 num_caps, KProcessPageTable *page_table); Result SetCapabilities(const u32 *caps, s32 num_caps, KProcessPageTable *page_table);
Result SetCapabilities(svc::KUserPointer<const u32 *> user_caps, s32 num_caps, KProcessPageTable *page_table); Result SetCapabilities(svc::KUserPointer<const u32 *> user_caps, s32 num_caps, KProcessPageTable *page_table);
@ -229,6 +233,8 @@ namespace ams::kern {
Result Initialize(const u32 *caps, s32 num_caps, KProcessPageTable *page_table); Result Initialize(const u32 *caps, s32 num_caps, KProcessPageTable *page_table);
Result Initialize(svc::KUserPointer<const u32 *> user_caps, s32 num_caps, KProcessPageTable *page_table); Result Initialize(svc::KUserPointer<const u32 *> user_caps, s32 num_caps, KProcessPageTable *page_table);
static Result CheckCapabilities(svc::KUserPointer<const u32 *> user_caps, s32 num_caps);
constexpr u64 GetCoreMask() const { return m_core_mask; } constexpr u64 GetCoreMask() const { return m_core_mask; }
constexpr u64 GetPriorityMask() const { return m_priority_mask; } constexpr u64 GetPriorityMask() const { return m_priority_mask; }
constexpr s32 GetHandleTableSize() const { return m_handle_table_size; } constexpr s32 GetHandleTableSize() const { return m_handle_table_size; }

View file

@ -156,9 +156,10 @@ namespace ams::kern {
R_RETURN(page_table->MapIo(phys_addr, size, KMemoryPermission_UserReadWrite)); 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. */ /* Define the allowed memory regions. */
constexpr KMemoryRegionType MemoryRegions[] = { constexpr const KMemoryRegionType MemoryRegions[] = {
KMemoryRegionType_None, KMemoryRegionType_None,
KMemoryRegionType_KernelTraceBuffer, KMemoryRegionType_KernelTraceBuffer,
KMemoryRegionType_OnMemoryBootImage, KMemoryRegionType_OnMemoryBootImage,
@ -173,12 +174,12 @@ namespace ams::kern {
const auto type = types[i]; const auto type = types[i];
const auto perm = ro[i] ? KMemoryPermission_UserRead : KMemoryPermission_UserReadWrite; const auto perm = ro[i] ? KMemoryPermission_UserRead : KMemoryPermission_UserReadWrite;
switch (type) { switch (type) {
case RegionType::None: case RegionType::NoMapping:
break; break;
case RegionType::KernelTraceBuffer: case RegionType::KernelTraceBuffer:
case RegionType::OnMemoryBootImage: case RegionType::OnMemoryBootImage:
case RegionType::DTB: case RegionType::DTB:
R_TRY(page_table->MapRegion(MemoryRegions[static_cast<u32>(type)], perm)); R_TRY(f(MemoryRegions[static_cast<u32>(type)], perm));
break; break;
default: default:
R_THROW(svc::ResultNotFound()); R_THROW(svc::ResultNotFound());
@ -188,6 +189,22 @@ namespace ams::kern {
R_SUCCEED(); 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) { Result KCapabilities::SetInterruptPairCapability(const util::BitPack32 cap) {
/* Extract interrupts. */ /* Extract interrupts. */
const u32 ids[2] = { cap.Get<InterruptPair::InterruptId0>(), cap.Get<InterruptPair::InterruptId1>(), }; const u32 ids[2] = { cap.Get<InterruptPair::InterruptId0>(), cap.Get<InterruptPair::InterruptId1>(), };
@ -320,4 +337,21 @@ namespace ams::kern {
R_SUCCEED(); 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();
}
} }

View file

@ -192,6 +192,9 @@ namespace ams::kern::svc {
const bool is_application = (params.flags & ams::svc::CreateProcessFlag_IsApplication) != 0; const bool is_application = (params.flags & ams::svc::CreateProcessFlag_IsApplication) != 0;
R_UNLESS(!optimize_allocs || is_application, svc::ResultBusy()); R_UNLESS(!optimize_allocs || is_application, svc::ResultBusy());
/* Check that the user-provided capabilities are accessible and refer to valid regions. */
R_TRY(KCapabilities::CheckCapabilities(user_caps, num_caps));
/* Get the current handle table. */ /* Get the current handle table. */
auto &handle_table = GetCurrentProcess().GetHandleTable(); auto &handle_table = GetCurrentProcess().GetHandleTable();