Loader: Implement NSO Extent calculation (note: ASLR currently disabled due to lack of entropy source.)

This commit is contained in:
Michael Scire 2018-04-24 04:41:29 -06:00
parent 6afd59d2a2
commit b11c2fe755
3 changed files with 103 additions and 1 deletions

View File

@ -85,5 +85,87 @@ Result NsoUtils::ValidateNsoLoadSet() {
}
}
return 0x0;
}
Result NsoUtils::CalculateNsoLoadExtents(u32 addspace_type, u32 args_size, NsoLoadExtents *extents) {
*extents = (const NsoUtils::NsoLoadExtents){0};
/* Calculate base offsets. */
for (unsigned int i = 0; i < NSO_NUM_MAX; i++) {
if (g_nso_present[i]) {
extents->nso_addresses[i] = extents->total_size;
u32 text_end = g_nso_headers[i].segments[0].dst_offset + g_nso_headers[i].segments[0].decomp_size;
u32 ro_end = g_nso_headers[i].segments[1].dst_offset + g_nso_headers[i].segments[1].decomp_size;
u32 rw_end = g_nso_headers[i].segments[2].dst_offset + g_nso_headers[i].segments[2].decomp_size + g_nso_headers[i].segments[2].align_or_total_size;
extents->nso_sizes[i] = text_end;
if (extents->nso_sizes[i] < ro_end) {
extents->nso_sizes[i] = ro_end;
}
if (extents->nso_sizes[i] < rw_end) {
extents->nso_sizes[i] = rw_end;
}
extents->nso_sizes[i] += 0xFFF;
extents->nso_sizes[i] &= ~0xFFFULL;
extents->total_size += extents->nso_sizes[i];
if (args_size && !extents->args_size) {
extents->args_address = extents->total_size;
/* What the fuck? Where does 0x9007 come from? */
extents->args_size = (2 * args_size + 0x9007);
extents->args_size &= ~0xFFFULL;
}
}
}
/* Calculate ASLR extents for address space type. */
u64 addspace_start, addspace_size, addspace_end;
if (kernelAbove200()) {
switch (addspace_type & 0xE) {
case 0:
case 4:
addspace_start = 0x200000ULL;
addspace_size = 0x3FE00000ULL;
break;
case 2:
addspace_start = 0x8000000ULL;
addspace_size = 0x78000000ULL;
break;
case 6:
addspace_start = 0x8000000ULL;
addspace_size = 0x7FF8000000ULL;
break;
default:
/* TODO: Panic. */
return 0xD001;
}
} else {
if (addspace_type & 2) {
addspace_start = 0x8000000ULL;
addspace_size = 0x78000000ULL;
} else {
addspace_start = 0x200000ULL;
addspace_size = 0x3FE00000ULL;
}
}
addspace_end = addspace_start + addspace_size;
if (addspace_start + extents->total_size > addspace_end) {
return 0xD001;
}
u64 aslr_slide = 0;
if (addspace_type & 0x20) {
/* TODO: Apply a random ASLR slide. */
}
extents->base_address = addspace_start + aslr_slide;
for (unsigned int i = 0; i < NSO_NUM_MAX; i++) {
if (g_nso_present[i]) {
extents->nso_addresses[i] += extents->base_address;
}
}
if (extents->args_address) {
extents->args_address += extents->base_address;
}
return 0x0;
}

View File

@ -28,6 +28,15 @@ class NsoUtils {
u8 section_hashes[3][0x20];
};
struct NsoLoadExtents {
u64 base_address;
u64 total_size;
u64 args_address;
u64 args_size;
u64 nso_addresses[NSO_NUM_MAX];
u64 nso_sizes[NSO_NUM_MAX];
};
static_assert(sizeof(NsoHeader) == 0x100, "Incorrectly defined NsoHeader!");
@ -72,4 +81,5 @@ class NsoUtils {
static bool IsNsoPresent(unsigned int index);
static Result LoadNsoHeaders(u64 title_id);
static Result ValidateNsoLoadSet();
static Result CalculateNsoLoadExtents(u32 addspace_type, u32 args_size, NsoLoadExtents *extents);
};

View File

@ -89,6 +89,7 @@ Result ProcessCreation::InitializeProcessInfo(NpdmUtils::NpdmInfo *npdm, Handle
Result ProcessCreation::CreateProcess(Handle *out_process_h, u64 index, char *nca_path, LaunchQueue::LaunchItem *launch_item, u64 arg_flags, Handle reslimit_h) {
NpdmUtils::NpdmInfo npdm_info = {0};
ProcessInfo process_info = {0};
NsoUtils::NsoLoadExtents nso_extents = {0};
Registration::Process *target_process;
Handle process_h = 0;
Result rc;
@ -141,7 +142,16 @@ Result ProcessCreation::CreateProcess(Handle *out_process_h, u64 index, char *nc
goto CREATE_PROCESS_END;
}
/* TODO: Figure out where NSOs will be mapped, and how much space they (and arguments) will take up. */
/* Figure out where NSOs will be mapped, and how much space they (and arguments) will take up. */
rc = NsoUtils::CalculateNsoLoadExtents(launch_item != NULL ? launch_item->arg_size : 0, process_info.process_flags, &nso_extents);
if (R_FAILED(rc)) {
goto CREATE_PROCESS_END;
}
/* Set Address Space information in ProcessInfo. */
process_info.code_addr = nso_extents.base_address;
process_info.code_num_pages = nso_extents.total_size + 0xFFF;
process_info.code_num_pages >>= 12;
/* Call svcCreateProcess(). */
rc = svcCreateProcess(&process_h, &process_info, (u32 *)npdm_info.aci0_kac, npdm_info.aci0->kac_size/sizeof(u32));