mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +00:00
Loader: Implement Kernel Capability parsing/validation.
This commit is contained in:
parent
0e11788e43
commit
c9a40f358a
3 changed files with 264 additions and 1 deletions
|
@ -117,4 +117,263 @@ Result NpdmUtils::LoadNpdm(u64 tid, NpdmInfo *out) {
|
|||
rc = 0;
|
||||
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
Result NpdmUtils::ValidateCapabilityAgainstRestrictions(u32 *restrict_caps, size_t num_restrict_caps, u32 *&cur_cap, size_t &caps_remaining) {
|
||||
Result rc = 0;
|
||||
u32 desc = *cur_cap++;
|
||||
caps_remaining--;
|
||||
unsigned int low_bits = 0;
|
||||
while (desc & 1) {
|
||||
desc >>= 1;
|
||||
low_bits++;
|
||||
}
|
||||
desc >>= 1;
|
||||
u32 r_desc = 0;
|
||||
switch (low_bits) {
|
||||
case 3: /* Kernel flags. */
|
||||
rc = 0xCE09;
|
||||
for (size_t i = 0; i < num_restrict_caps; i++) {
|
||||
if ((restrict_caps[i] & 0xF) == 0x7) {
|
||||
r_desc = restrict_caps[i] >> 4;
|
||||
u32 highest_thread_prio = desc & 0x3F;
|
||||
u32 r_highest_thread_prio = r_desc & 0x3F;
|
||||
desc >>= 6;
|
||||
r_desc >>= 6;
|
||||
u32 lowest_thread_prio = desc & 0x3F;
|
||||
u32 r_lowest_thread_prio = r_desc & 0x3F;
|
||||
desc >>= 6;
|
||||
r_desc >>= 6;
|
||||
u32 lowest_cpu_id = desc & 0xFF;
|
||||
u32 r_lowest_cpu_id = r_desc & 0xFF;
|
||||
desc >>= 8;
|
||||
r_desc >>= 8;
|
||||
u32 highest_cpu_id = desc & 0xFF;
|
||||
u32 r_highest_cpu_id = r_desc & 0xFF;
|
||||
if (highest_thread_prio > r_highest_thread_prio) {
|
||||
break;
|
||||
}
|
||||
if (lowest_thread_prio > highest_thread_prio) {
|
||||
break;
|
||||
}
|
||||
if (lowest_thread_prio < r_lowest_thread_prio) {
|
||||
break;
|
||||
}
|
||||
if (lowest_cpu_id < r_lowest_cpu_id) {
|
||||
break;
|
||||
}
|
||||
if (lowest_cpu_id > r_highest_cpu_id) {
|
||||
break;
|
||||
}
|
||||
if (highest_cpu_id > r_highest_cpu_id) {
|
||||
break;
|
||||
}
|
||||
/* Valid! */
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4: /* Syscall mask. */
|
||||
rc = 0xD009;
|
||||
for (size_t i = 0; i < num_restrict_caps; i++) {
|
||||
if ((restrict_caps[i] & 0x1F) == 0xF) {
|
||||
r_desc = restrict_caps[i] >> 5;
|
||||
u32 syscall_base = (desc >> 24);
|
||||
u32 r_syscall_base = (r_desc >> 24);
|
||||
if (syscall_base != r_syscall_base) {
|
||||
continue;
|
||||
}
|
||||
u32 syscall_mask = desc & 0xFFFFFF;
|
||||
u32 r_syscall_mask = r_desc & 0xFFFFFF;
|
||||
if ((r_syscall_mask & syscall_mask) != syscall_mask) {
|
||||
break;
|
||||
}
|
||||
/* Valid! */
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 6: /* Map IO/Normal. */ {
|
||||
rc = 0xD409;
|
||||
if (caps_remaining == 0) {
|
||||
break;
|
||||
}
|
||||
u32 next_cap = *cur_cap++;
|
||||
caps_remaining--;
|
||||
if ((next_cap & 0x7F) != 0x3F) {
|
||||
break;
|
||||
}
|
||||
u32 next_desc = next_cap >> 7;
|
||||
u32 base_addr = desc & 0xFFFFFF;
|
||||
u32 base_size = next_desc & 0xFFFFFF;
|
||||
/* Size check the mapping. */
|
||||
if (base_size >> 20) {
|
||||
break;
|
||||
}
|
||||
u32 base_end = base_addr + base_size;
|
||||
/* Validate it's possible to validate this mapping. */
|
||||
if (num_restrict_caps < 2) {
|
||||
break;
|
||||
}
|
||||
for (size_t i = 0; i < num_restrict_caps - 1; i++) {
|
||||
if ((restrict_caps[i] & 0x7F) == 0x3F) {
|
||||
r_desc = restrict_caps[i] >> 7;
|
||||
if ((restrict_caps[i+1] & 0x7F) != 0x3F) {
|
||||
break;
|
||||
}
|
||||
u32 r_next_desc = restrict_caps[i++] >> 7;
|
||||
u32 r_base_addr = r_desc & 0xFFFFFF;
|
||||
u32 r_base_size = r_next_desc & 0xFFFFFF;
|
||||
/* Size check the mapping. */
|
||||
if (r_base_size >> 20) {
|
||||
break;
|
||||
}
|
||||
u32 r_base_end = r_base_addr + r_base_size;
|
||||
/* Validate is_io matches. */
|
||||
if (((r_desc >> 24) & 1) ^ ((desc >> 24) & 1)) {
|
||||
continue;
|
||||
}
|
||||
/* Validate is_ro matches. */
|
||||
if (((r_next_desc >> 24) & 1) ^ ((next_desc >> 24) & 1)) {
|
||||
continue;
|
||||
}
|
||||
/* Validate bounds. */
|
||||
if (base_addr < r_base_addr || base_end > r_base_end) {
|
||||
continue;
|
||||
}
|
||||
/* Valid! */
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 7: /* Map Normal Page. */
|
||||
rc = 0xD609;
|
||||
for (size_t i = 0; i < num_restrict_caps; i++) {
|
||||
if ((restrict_caps[i] & 0xFF) == 0x7F) {
|
||||
r_desc = restrict_caps[i] >> 8;
|
||||
if (r_desc != desc) {
|
||||
continue;
|
||||
}
|
||||
/* Valid! */
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 11: /* IRQ Pair. */
|
||||
rc = 0x0;
|
||||
for (unsigned int irq_i = 0; irq_i < 2; irq_i++) {
|
||||
u32 irq = desc & 0x3FF;
|
||||
desc >>= 10;
|
||||
if (irq != 0x3FF) {
|
||||
bool found = false;
|
||||
for (size_t i = 0; i < num_restrict_caps && !found; i++) {
|
||||
if ((restrict_caps[i] & 0xFFF) == 0x7FF) {
|
||||
r_desc = restrict_caps[i] >> 12;
|
||||
u32 r_irq_0 = r_desc & 0x3FF;
|
||||
r_desc >>= 10;
|
||||
u32 r_irq_1 = r_desc & 0x3FF;
|
||||
found |= irq == r_irq_0 || irq == r_irq_1;
|
||||
found |= r_irq_0 == 0x3FF && r_irq_1 == 0x3FF;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
rc = 0xDE09;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 13: /* App Type. */
|
||||
rc = 0xE209;
|
||||
if (num_restrict_caps) {
|
||||
for (size_t i = 0; i < num_restrict_caps; i++) {
|
||||
if ((restrict_caps[i] & 0x3FFF) == 0x1FFF) {
|
||||
r_desc = restrict_caps[i] >> 14;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
r_desc = 0;
|
||||
}
|
||||
if (desc == r_desc) {
|
||||
/* Valid! */
|
||||
rc = 0;
|
||||
}
|
||||
break;
|
||||
case 14: /* Kernel Release Version. */
|
||||
rc = 0xE409;
|
||||
if (num_restrict_caps) {
|
||||
for (size_t i = 0; i < num_restrict_caps; i++) {
|
||||
if ((restrict_caps[i] & 0x7FFF) == 0x3FFF) {
|
||||
r_desc = restrict_caps[i] >> 15;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
r_desc = 0;
|
||||
}
|
||||
if (desc == r_desc) {
|
||||
/* Valid! */
|
||||
rc = 0;
|
||||
}
|
||||
break;
|
||||
case 15: /* Handle Table Size. */
|
||||
rc = 0xE609;
|
||||
for (size_t i = 0; i < num_restrict_caps; i++) {
|
||||
if ((restrict_caps[i] & 0xFFFF) == 0x7FFF) {
|
||||
r_desc = restrict_caps[i] >> 16;
|
||||
desc &= 0x3FF;
|
||||
r_desc &= 0x3FF;
|
||||
if (desc <= r_desc) {
|
||||
break;
|
||||
}
|
||||
/* Valid! */
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 16: /* Debug Flags. */
|
||||
rc = 0xE809;
|
||||
if (num_restrict_caps) {
|
||||
for (size_t i = 0; i < num_restrict_caps; i++) {
|
||||
if ((restrict_caps[i] & 0x1FFFF) == 0xFFFF) {
|
||||
r_desc = restrict_caps[i] >> 17;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
r_desc = 0;
|
||||
}
|
||||
if ((desc & ~r_desc) == 0) {
|
||||
/* Valid! */
|
||||
rc = 0;
|
||||
}
|
||||
break;
|
||||
case 32: /* Empty Descriptor. */
|
||||
rc = 0;
|
||||
break;
|
||||
default: /* Unrecognized Descriptor. */
|
||||
rc = 0xC809;
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result NpdmUtils::ValidateCapabilities(u32 *acid_caps, size_t num_acid_caps, u32 *aci0_caps, size_t num_aci0_caps) {
|
||||
Result rc = 0;
|
||||
size_t remaining = num_aci0_caps;
|
||||
u32 *cur_cap = aci0_caps;
|
||||
while (num_aci0_caps) {
|
||||
if (R_FAILED((rc = ValidateCapabilityAgainstRestrictions(acid_caps, num_acid_caps, cur_cap, remaining)))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -77,6 +77,9 @@ class NpdmUtils {
|
|||
static_assert(sizeof(NpdmAcid) == 0x240, "Incorrectly defined NpdmAcid!");
|
||||
static_assert(sizeof(NpdmAci0) == 0x40, "Incorrectly defined NpdmAci0!");
|
||||
|
||||
static Result ValidateCapabilityAgainstRestrictions(u32 *restrict_caps, size_t num_restrict_caps, u32 *&cur_cap, size_t &caps_remaining);
|
||||
static Result ValidateCapabilities(u32 *acid_caps, size_t num_acid_caps, u32 *aci0_caps, size_t num_aci0_caps);
|
||||
|
||||
static Result LoadNpdm(u64 tid, NpdmInfo *out);
|
||||
static Result LoadNpdmFromCache(u64 tid, NpdmInfo *out);
|
||||
};
|
|
@ -32,6 +32,7 @@ Result ProcessCreation::CreateProcess(Handle *out_process_h, u64 index, char *nc
|
|||
}
|
||||
|
||||
/* TODO: Parse and verify ACI0 kernel caps vs ACID kernel caps. */
|
||||
rc = NpdmUtils::ValidateCapabilities((u32 *)info.acid_kac, info.acid->kac_size/sizeof(u32), (u32 *)info.aci0_kac, info.aci0->kac_size/sizeof(u32));
|
||||
|
||||
/* TODO: Read in all NSO headers, see what NSOs are present. */
|
||||
|
||||
|
|
Loading…
Reference in a new issue