mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-24 15:50:29 +01:00
kern: add new KCapability checks before creating process
This commit is contained in:
parent
14e768cd10
commit
8cb3cfd835
@ -116,7 +116,7 @@ namespace ams::kern {
|
||||
};
|
||||
|
||||
enum class RegionType : u32 {
|
||||
None = 0,
|
||||
NoMapping = 0,
|
||||
KernelTraceBuffer = 1,
|
||||
OnMemoryBootImage = 2,
|
||||
DTB = 3,
|
||||
@ -219,6 +219,10 @@ namespace ams::kern {
|
||||
Result SetHandleTableCapability(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 SetCapabilities(const u32 *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(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 GetPriorityMask() const { return m_priority_mask; }
|
||||
constexpr s32 GetHandleTableSize() const { return m_handle_table_size; }
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -192,6 +192,9 @@ namespace ams::kern::svc {
|
||||
const bool is_application = (params.flags & ams::svc::CreateProcessFlag_IsApplication) != 0;
|
||||
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. */
|
||||
auto &handle_table = GetCurrentProcess().GetHandleTable();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user