loader: refactor for R_TRY

This commit is contained in:
Michael Scire 2019-06-17 16:29:09 -07:00
parent ee40dcd76f
commit f9bf8923b1
24 changed files with 437 additions and 579 deletions

View file

@ -67,7 +67,6 @@ static std::map<u64, ContentManagement::ExternalContentSource> g_external_conten
Result ContentManagement::MountCode(u64 tid, FsStorageId sid) { Result ContentManagement::MountCode(u64 tid, FsStorageId sid) {
char path[FS_MAX_PATH] = {0}; char path[FS_MAX_PATH] = {0};
Result rc;
/* We defer SD card mounting, so if relevant ensure it is mounted. */ /* We defer SD card mounting, so if relevant ensure it is mounted. */
if (!g_has_initialized_fs_dev) { if (!g_has_initialized_fs_dev) {
@ -82,9 +81,7 @@ Result ContentManagement::MountCode(u64 tid, FsStorageId sid) {
return ResultSuccess; return ResultSuccess;
} }
if (R_FAILED(rc = ResolveContentPath(path, tid, sid))) { R_TRY(ResolveContentPath(path, tid, sid));
return rc;
}
/* Fix up path. */ /* Fix up path. */
for (unsigned int i = 0; i < FS_MAX_PATH && path[i] != '\x00'; i++) { for (unsigned int i = 0; i < FS_MAX_PATH && path[i] != '\x00'; i++) {
@ -95,20 +92,17 @@ Result ContentManagement::MountCode(u64 tid, FsStorageId sid) {
/* Always re-initialize fsp-ldr, in case it's closed */ /* Always re-initialize fsp-ldr, in case it's closed */
DoWithSmSession([&]() { DoWithSmSession([&]() {
rc = fsldrInitialize(); if (R_FAILED(fsldrInitialize())) {
std::abort();
}
}); });
if (R_FAILED(rc)) {
return rc;
}
ON_SCOPE_EXIT { fsldrExit(); }; ON_SCOPE_EXIT { fsldrExit(); };
if (R_FAILED(rc = fsldrOpenCodeFileSystem(tid, path, &g_CodeFileSystem))) { R_TRY(fsldrOpenCodeFileSystem(tid, path, &g_CodeFileSystem));
return rc;
}
fsdevMountDevice("code", g_CodeFileSystem); fsdevMountDevice("code", g_CodeFileSystem);
TryMountHblNspOnSd(); TryMountHblNspOnSd();
return rc; return ResultSuccess;
} }
Result ContentManagement::UnmountCode() { Result ContentManagement::UnmountCode() {
@ -139,14 +133,12 @@ void ContentManagement::TryMountHblNspOnSd() {
Result ContentManagement::MountCodeNspOnSd(u64 tid) { Result ContentManagement::MountCodeNspOnSd(u64 tid) {
char path[FS_MAX_PATH+1] = {0}; char path[FS_MAX_PATH+1] = {0};
snprintf(path, FS_MAX_PATH, "@Sdcard:/atmosphere/titles/%016lx/exefs.nsp", tid); snprintf(path, FS_MAX_PATH, "@Sdcard:/atmosphere/titles/%016lx/exefs.nsp", tid);
Result rc = fsOpenFileSystemWithId(&g_CodeFileSystem, 0, FsFileSystemType_ApplicationPackage, path);
if (R_SUCCEEDED(rc)) { R_TRY(fsOpenFileSystemWithId(&g_CodeFileSystem, 0, FsFileSystemType_ApplicationPackage, path));
fsdevMountDevice("code", g_CodeFileSystem); fsdevMountDevice("code", g_CodeFileSystem);
TryMountHblNspOnSd(); TryMountHblNspOnSd();
}
return rc; return ResultSuccess;
} }
Result ContentManagement::MountCodeForTidSid(Registration::TidSid *tid_sid) { Result ContentManagement::MountCodeForTidSid(Registration::TidSid *tid_sid) {
@ -154,39 +146,29 @@ Result ContentManagement::MountCodeForTidSid(Registration::TidSid *tid_sid) {
} }
Result ContentManagement::ResolveContentPath(char *out_path, u64 tid, FsStorageId sid) { Result ContentManagement::ResolveContentPath(char *out_path, u64 tid, FsStorageId sid) {
Result rc;
LrRegisteredLocationResolver reg;
LrLocationResolver lr;
char path[FS_MAX_PATH] = {0}; char path[FS_MAX_PATH] = {0};
/* Try to get the path from the registered resolver. */ /* Try to get the path from the registered resolver. */
if (R_FAILED(rc = lrOpenRegisteredLocationResolver(&reg))) { LrRegisteredLocationResolver reg;
return rc; R_TRY(lrOpenRegisteredLocationResolver(&reg));
} ON_SCOPE_EXIT { serviceClose(&reg.s); };
if (R_SUCCEEDED(rc = lrRegLrResolveProgramPath(&reg, tid, path))) { R_TRY_CATCH(lrRegLrResolveProgramPath(&reg, tid, path)) {
strncpy(out_path, path, FS_MAX_PATH); R_CATCH(ResultLrProgramNotFound) {
} else if (rc != ResultLrProgramNotFound) { /* Program wasn't found via registered resolver, fall back to the normal resolver. */
return rc; LrLocationResolver lr;
} R_TRY(lrOpenLocationResolver(sid, &lr));
ON_SCOPE_EXIT { serviceClose(&lr.s); };
serviceClose(&reg.s); R_TRY(lrLrResolveProgramPath(&lr, tid, path));
if (R_SUCCEEDED(rc)) {
return rc;
}
/* If getting the path from the registered resolver fails, fall back to the normal resolver. */ strncpy(out_path, path, FS_MAX_PATH);
if (R_FAILED(rc = lrOpenLocationResolver(sid, &lr))) { return ResultSuccess;
return rc; }
} } R_END_TRY_CATCH;
if (R_SUCCEEDED(rc = lrLrResolveProgramPath(&lr, tid, path))) { strncpy(out_path, path, FS_MAX_PATH);
strncpy(out_path, path, FS_MAX_PATH); return ResultSuccess;
}
serviceClose(&lr.s);
return rc;
} }
Result ContentManagement::ResolveContentPathForTidSid(char *out_path, Registration::TidSid *tid_sid) { Result ContentManagement::ResolveContentPathForTidSid(char *out_path, Registration::TidSid *tid_sid) {
@ -194,18 +176,11 @@ Result ContentManagement::ResolveContentPathForTidSid(char *out_path, Registrati
} }
Result ContentManagement::RedirectContentPath(const char *path, u64 tid, FsStorageId sid) { Result ContentManagement::RedirectContentPath(const char *path, u64 tid, FsStorageId sid) {
Result rc;
LrLocationResolver lr; LrLocationResolver lr;
R_TRY(lrOpenLocationResolver(sid, &lr));
ON_SCOPE_EXIT { serviceClose(&lr.s); };
if (R_FAILED(rc = lrOpenLocationResolver(sid, &lr))) { return lrLrRedirectProgramPath(&lr, tid, path);
return rc;
}
rc = lrLrRedirectProgramPath(&lr, tid, path);
serviceClose(&lr.s);
return rc;
} }
Result ContentManagement::RedirectContentPathForTidSid(const char *path, Registration::TidSid *tid_sid) { Result ContentManagement::RedirectContentPathForTidSid(const char *path, Registration::TidSid *tid_sid) {
@ -382,7 +357,7 @@ void ContentManagement::TryMountSdCard() {
can_mount = false; can_mount = false;
break; break;
} else { } else {
svcCloseHandle(tmp_hnd); svcCloseHandle(tmp_hnd);
} }
} }
}); });

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <switch.h> #include <switch.h>

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <switch.h> #include <switch.h>
#include <cstdio> #include <cstdio>
#include <algorithm> #include <algorithm>

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <switch.h> #include <switch.h>
@ -25,7 +25,7 @@ enum DebugMonitorServiceCmd {
Dmnt_Cmd_GetProcessModuleInfo = 2 Dmnt_Cmd_GetProcessModuleInfo = 2
}; };
class DebugMonitorService final : public IServiceObject { class DebugMonitorService final : public IServiceObject {
private: private:
/* Actual commands. */ /* Actual commands. */
Result AddTitleToLaunchQueue(u64 tid, InPointer<char> args, u32 args_size); Result AddTitleToLaunchQueue(u64 tid, InPointer<char> args, u32 args_size);

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <switch.h> #include <switch.h>

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include <algorithm> #include <algorithm>
@ -28,15 +28,15 @@ Result LaunchQueue::Add(u64 tid, const char *args, u64 arg_size) {
if (arg_size > LAUNCH_QUEUE_ARG_SIZE_MAX) { if (arg_size > LAUNCH_QUEUE_ARG_SIZE_MAX) {
return ResultLoaderTooLongArgument; return ResultLoaderTooLongArgument;
} }
int idx = GetFreeIndex(tid); int idx = GetFreeIndex(tid);
if (idx == LAUNCH_QUEUE_FULL) { if (idx == LAUNCH_QUEUE_FULL) {
return ResultLoaderTooManyArguments; return ResultLoaderTooManyArguments;
} }
g_launch_queue[idx].tid = tid; g_launch_queue[idx].tid = tid;
g_launch_queue[idx].arg_size = arg_size; g_launch_queue[idx].arg_size = arg_size;
std::copy(args, args + arg_size, g_launch_queue[idx].args); std::copy(args, args + arg_size, g_launch_queue[idx].args);
return ResultSuccess; return ResultSuccess;
} }
@ -46,7 +46,7 @@ Result LaunchQueue::AddCopy(u64 tid_base, u64 tid) {
if (idx == LAUNCH_QUEUE_FULL) { if (idx == LAUNCH_QUEUE_FULL) {
return ResultSuccess; return ResultSuccess;
} }
return Add(tid, g_launch_queue[idx].args, g_launch_queue[idx].arg_size); return Add(tid, g_launch_queue[idx].args, g_launch_queue[idx].arg_size);
} }
@ -55,12 +55,12 @@ Result LaunchQueue::AddItem(const LaunchItem *item) {
if (item->arg_size > LAUNCH_QUEUE_ARG_SIZE_MAX) { if (item->arg_size > LAUNCH_QUEUE_ARG_SIZE_MAX) {
return ResultLoaderTooLongArgument; return ResultLoaderTooLongArgument;
} }
int idx = GetFreeIndex(item->tid); int idx = GetFreeIndex(item->tid);
if (idx == LAUNCH_QUEUE_FULL) { if (idx == LAUNCH_QUEUE_FULL) {
return ResultLoaderTooManyArguments; return ResultLoaderTooManyArguments;
} }
g_launch_queue[idx] = *item; g_launch_queue[idx] = *item;
return ResultSuccess; return ResultSuccess;
} }

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <switch.h> #include <switch.h>
@ -22,16 +22,16 @@
#define LAUNCH_QUEUE_ARG_SIZE_MAX (0x8000) #define LAUNCH_QUEUE_ARG_SIZE_MAX (0x8000)
class LaunchQueue { class LaunchQueue {
public: public:
struct LaunchItem { struct LaunchItem {
u64 tid; u64 tid;
u64 arg_size; u64 arg_size;
char args[LAUNCH_QUEUE_ARG_SIZE_MAX]; char args[LAUNCH_QUEUE_ARG_SIZE_MAX];
}; };
static LaunchQueue::LaunchItem *GetItem(u64 tid); static LaunchQueue::LaunchItem *GetItem(u64 tid);
static Result Add(u64 tid, const char *args, u64 arg_size); static Result Add(u64 tid, const char *args, u64 arg_size);
static Result AddItem(const LaunchItem *item); static Result AddItem(const LaunchItem *item);
static Result AddCopy(u64 tid_base, u64 new_tid); static Result AddCopy(u64 tid_base, u64 new_tid);

View file

@ -116,10 +116,10 @@ int main(int argc, char **argv)
s_server_manager.AddWaitable(new ServiceServer<ProcessManagerService>("ldr:pm", 1)); s_server_manager.AddWaitable(new ServiceServer<ProcessManagerService>("ldr:pm", 1));
s_server_manager.AddWaitable(new ServiceServer<ShellService>("ldr:shel", 3)); s_server_manager.AddWaitable(new ServiceServer<ShellService>("ldr:shel", 3));
s_server_manager.AddWaitable(new ServiceServer<DebugMonitorService>("ldr:dmnt", 2)); s_server_manager.AddWaitable(new ServiceServer<DebugMonitorService>("ldr:dmnt", 2));
/* Loop forever, servicing our services. */ /* Loop forever, servicing our services. */
s_server_manager.Process(); s_server_manager.Process();
return 0; return 0;
} }

View file

@ -13,14 +13,14 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <switch.h> #include <switch.h>
#include <cstdio> #include <cstdio>
#include "ldr_map.hpp" #include "ldr_map.hpp"
Result MapUtils::LocateSpaceForMap(u64 *out, u64 out_size) { Result MapUtils::LocateSpaceForMap(u64 *out, u64 out_size) {
if ((GetRuntimeFirmwareVersion() >= FirmwareVersion_200)) { if (GetRuntimeFirmwareVersion() >= FirmwareVersion_200) {
return LocateSpaceForMapModern(out, out_size); return LocateSpaceForMapModern(out, out_size);
} else { } else {
return LocateSpaceForMapDeprecated(out, out_size); return LocateSpaceForMapDeprecated(out, out_size);
@ -32,31 +32,27 @@ Result MapUtils::LocateSpaceForMapModern(u64 *out, u64 out_size) {
AddressSpaceInfo address_space = {}; AddressSpaceInfo address_space = {};
u32 page_info = 0; u32 page_info = 0;
u64 cur_base = 0, cur_end = 0; u64 cur_base = 0, cur_end = 0;
Result rc;
R_TRY(GetAddressSpaceInfo(&address_space, CUR_PROCESS_HANDLE));
if (R_FAILED((rc = GetAddressSpaceInfo(&address_space, CUR_PROCESS_HANDLE)))) {
return rc;
}
cur_base = address_space.addspace_base; cur_base = address_space.addspace_base;
rc = ResultKernelOutOfMemory;
cur_end = cur_base + out_size; cur_end = cur_base + out_size;
if (cur_end <= cur_base) { if (cur_end <= cur_base) {
return rc; return ResultKernelOutOfMemory;
} }
while (true) { while (true) {
if (address_space.heap_size && (address_space.heap_base <= cur_end - 1 && cur_base <= address_space.heap_end - 1)) { if (address_space.heap_size && (address_space.heap_base <= cur_end - 1 && cur_base <= address_space.heap_end - 1)) {
/* If we overlap the heap region, go to the end of the heap region. */ /* If we overlap the heap region, go to the end of the heap region. */
if (cur_base == address_space.heap_end) { if (cur_base == address_space.heap_end) {
return rc; return ResultKernelOutOfMemory;
} }
cur_base = address_space.heap_end; cur_base = address_space.heap_end;
} else if (address_space.map_size && (address_space.map_base <= cur_end - 1 && cur_base <= address_space.map_end - 1)) { } else if (address_space.map_size && (address_space.map_base <= cur_end - 1 && cur_base <= address_space.map_end - 1)) {
/* If we overlap the map region, go to the end of the map region. */ /* If we overlap the map region, go to the end of the map region. */
if (cur_base == address_space.map_end) { if (cur_base == address_space.map_end) {
return rc; return ResultKernelOutOfMemory;
} }
cur_base = address_space.map_end; cur_base = address_space.map_end;
} else { } else {
@ -68,77 +64,52 @@ Result MapUtils::LocateSpaceForMapModern(u64 *out, u64 out_size) {
return ResultSuccess; return ResultSuccess;
} }
if (mem_info.addr + mem_info.size <= cur_base) { if (mem_info.addr + mem_info.size <= cur_base) {
return rc; return ResultKernelOutOfMemory;
} }
cur_base = mem_info.addr + mem_info.size; cur_base = mem_info.addr + mem_info.size;
if (cur_base >= address_space.addspace_end) { if (cur_base >= address_space.addspace_end) {
return rc; return ResultKernelOutOfMemory;
} }
} }
cur_end = cur_base + out_size; cur_end = cur_base + out_size;
if (cur_base + out_size <= cur_base) { if (cur_base + out_size <= cur_base) {
return rc; return ResultKernelOutOfMemory;
} }
} }
} }
Result MapUtils::LocateSpaceForMapDeprecated(u64 *out, u64 out_size) { Result MapUtils::LocateSpaceForMapDeprecated(u64 *out, u64 out_size) {
MemoryInfo mem_info = {}; MemoryInfo mem_info = {};
u32 page_info = 0; u32 page_info = 0;
Result rc;
u64 cur_base = 0x8000000ULL; u64 cur_base = 0x8000000ULL;
if (R_FAILED((rc = svcQueryMemory(&mem_info, &page_info, cur_base)))) { do {
return rc; R_TRY(svcQueryMemory(&mem_info, &page_info, cur_base));
}
rc = ResultKernelOutOfMemory;
while (true) {
if (mem_info.type == 0x10) {
return rc;
}
if (mem_info.type == 0 && mem_info.addr - cur_base + mem_info.size >= out_size) { if (mem_info.type == 0 && mem_info.addr - cur_base + mem_info.size >= out_size) {
*out = cur_base; *out = cur_base;
return ResultSuccess; return ResultSuccess;
} }
u64 mem_end = mem_info.addr + mem_info.size;
if (mem_end < cur_base) { const u64 mem_end = mem_info.addr + mem_info.size;
return rc; if (mem_info.type == 0x10 || mem_end < cur_base || (mem_end >> 31)) {
} return ResultKernelOutOfMemory;
if (mem_end >> 31) {
break;
} }
cur_base = mem_end; cur_base = mem_end;
if (R_FAILED((rc = svcQueryMemory(&mem_info, &page_info, cur_base)))) { } while (true);
return rc;
}
}
return rc;
} }
Result MapUtils::GetAddressSpaceInfo(AddressSpaceInfo *out, Handle process_h) { Result MapUtils::GetAddressSpaceInfo(AddressSpaceInfo *out, Handle process_h) {
Result rc; R_TRY(svcGetInfo(&out->heap_base, 4, process_h, 0));
if (R_FAILED((rc = svcGetInfo(&out->heap_base, 4, process_h, 0)))) { R_TRY(svcGetInfo(&out->heap_size, 5, process_h, 0));
return rc; R_TRY(svcGetInfo(&out->map_base, 2, process_h, 0));
} R_TRY(svcGetInfo(&out->map_size, 3, process_h, 0));
if (R_FAILED((rc = svcGetInfo(&out->heap_size, 5, process_h, 0)))) { R_TRY(svcGetInfo(&out->addspace_base, 12, process_h, 0));
return rc; R_TRY(svcGetInfo(&out->addspace_size, 13, process_h, 0));
}
if (R_FAILED((rc = svcGetInfo(&out->map_base, 2, process_h, 0)))) {
return rc;
}
if (R_FAILED((rc = svcGetInfo(&out->map_size, 3, process_h, 0)))) {
return rc;
}
if (R_FAILED((rc = svcGetInfo(&out->addspace_base, 12, process_h, 0)))) {
return rc;
}
if (R_FAILED((rc = svcGetInfo(&out->addspace_size, 13, process_h, 0)))) {
return rc;
}
out->heap_end = out->heap_base + out->heap_size; out->heap_end = out->heap_base + out->heap_size;
out->map_end = out->map_base + out->map_size; out->map_end = out->map_base + out->map_size;
out->addspace_end = out->addspace_base + out->addspace_size; out->addspace_end = out->addspace_base + out->addspace_size;
return ResultSuccess; return ResultSuccess;
} }

View file

@ -13,12 +13,12 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp> #include <stratosphere.hpp>
class MapUtils { class MapUtils {
public: public:
struct AddressSpaceInfo { struct AddressSpaceInfo {
u64 heap_base; u64 heap_base;
@ -47,29 +47,28 @@ class AutoCloseMap {
~AutoCloseMap() { ~AutoCloseMap() {
Close(); Close();
} }
void *GetMappedAddress() { void *GetMappedAddress() {
return this->mapped_address; return this->mapped_address;
} }
Result Open(Handle process_h, u64 address, u64 size) { Result Open(Handle process_h, u64 address, u64 size) {
Result rc;
u64 try_address; u64 try_address;
if (R_FAILED(rc = MapUtils::LocateSpaceForMap(&try_address, size))) {
return rc; /* Find an address to map at. */
} R_TRY(MapUtils::LocateSpaceForMap(&try_address, size));
if (R_FAILED((rc = svcMapProcessMemory((void *)try_address, process_h, address, size)))) { /* Actually map at address. */
return rc; void *try_map_address = reinterpret_cast<void *>(try_address);
} R_TRY(svcMapProcessMemory(try_map_address, process_h, address, size));
this->mapped_address = (void *)try_address; this->mapped_address = try_map_address;
this->process_handle = process_h; this->process_handle = process_h;
this->base_address = address; this->base_address = address;
this->size = size; this->size = size;
return ResultSuccess; return ResultSuccess;
} }
void Close() { void Close() {
if (this->mapped_address) { if (this->mapped_address) {
if (R_FAILED(svcUnmapProcessMemory(this->mapped_address, this->process_handle, this->base_address, this->size))) { if (R_FAILED(svcUnmapProcessMemory(this->mapped_address, this->process_handle, this->base_address, this->size))) {

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <switch.h> #include <switch.h>
#include <algorithm> #include <algorithm>
#include <cstdio> #include <cstdio>
@ -51,7 +51,7 @@ FILE *NpdmUtils::OpenNpdmFromExeFS() {
return fopen(g_npdm_path, "rb"); return fopen(g_npdm_path, "rb");
} }
FILE *NpdmUtils::OpenNpdmFromSdCard(u64 title_id) { FILE *NpdmUtils::OpenNpdmFromSdCard(u64 title_id) {
std::fill(g_npdm_path, g_npdm_path + FS_MAX_PATH, 0); std::fill(g_npdm_path, g_npdm_path + FS_MAX_PATH, 0);
snprintf(g_npdm_path, FS_MAX_PATH, "sdmc:/atmosphere/titles/%016lx/exefs/main.npdm", title_id); snprintf(g_npdm_path, FS_MAX_PATH, "sdmc:/atmosphere/titles/%016lx/exefs/main.npdm", title_id);
return fopen(g_npdm_path, "rb"); return fopen(g_npdm_path, "rb");
@ -63,12 +63,12 @@ FILE *NpdmUtils::OpenNpdm(u64 title_id) {
if ((ecs = ContentManagement::GetExternalContentSource(title_id)) != nullptr) { if ((ecs = ContentManagement::GetExternalContentSource(title_id)) != nullptr) {
return OpenNpdmFromECS(ecs); return OpenNpdmFromECS(ecs);
} }
/* First, check HBL. */ /* First, check HBL. */
if (ContentManagement::ShouldOverrideContentsWithHBL(title_id)) { if (ContentManagement::ShouldOverrideContentsWithHBL(title_id)) {
return OpenNpdmFromHBL(); return OpenNpdmFromHBL();
} }
/* Next, check other override. */ /* Next, check other override. */
if (ContentManagement::ShouldOverrideContentsWithSD(title_id)) { if (ContentManagement::ShouldOverrideContentsWithSD(title_id)) {
FILE *f_out = OpenNpdmFromSdCard(title_id); FILE *f_out = OpenNpdmFromSdCard(title_id);
@ -76,135 +76,124 @@ FILE *NpdmUtils::OpenNpdm(u64 title_id) {
return f_out; return f_out;
} }
} }
/* Last resort: real exefs. */ /* Last resort: real exefs. */
return OpenNpdmFromExeFS(); return OpenNpdmFromExeFS();
} }
Result NpdmUtils::LoadNpdmInternal(FILE *f_npdm, NpdmUtils::NpdmCache *cache) { Result NpdmUtils::LoadNpdmInternal(FILE *f_npdm, NpdmUtils::NpdmCache *cache) {
Result rc;
cache->info = {}; cache->info = {};
rc = ResultFsPathNotFound;
if (f_npdm == NULL) { if (f_npdm == NULL) {
/* For generic "Couldn't open the file" error, just say the file doesn't exist. */ /* For generic "Couldn't open the file" error, just say the file doesn't exist. */
return rc; return ResultFsPathNotFound;
} }
fseek(f_npdm, 0, SEEK_END); fseek(f_npdm, 0, SEEK_END);
size_t npdm_size = ftell(f_npdm); size_t npdm_size = ftell(f_npdm);
fseek(f_npdm, 0, SEEK_SET); fseek(f_npdm, 0, SEEK_SET);
rc = ResultLoaderTooLargeMeta;
if ((npdm_size > sizeof(cache->buffer)) || (fread(cache->buffer, 1, npdm_size, f_npdm) != npdm_size)) { if ((npdm_size > sizeof(cache->buffer)) || (fread(cache->buffer, 1, npdm_size, f_npdm) != npdm_size)) {
fclose(f_npdm); fclose(f_npdm);
return rc; return ResultLoaderTooLargeMeta;
} }
fclose(f_npdm); fclose(f_npdm);
rc = ResultLoaderInvalidMeta;
if (npdm_size < sizeof(NpdmUtils::NpdmHeader)) { if (npdm_size < sizeof(NpdmUtils::NpdmHeader)) {
return rc; return ResultLoaderInvalidMeta;
} }
/* For ease of access... */ /* For ease of access... */
cache->info.header = (NpdmUtils::NpdmHeader *)(cache->buffer); cache->info.header = (NpdmUtils::NpdmHeader *)(cache->buffer);
NpdmInfo *info = &cache->info; NpdmInfo *info = &cache->info;
if (info->header->magic != MAGIC_META) { if (info->header->magic != MAGIC_META) {
return rc; return ResultLoaderInvalidMeta;
} }
/* 7.0.0 added 0x10 as a valid bit to NPDM flags. */ /* 7.0.0 added 0x10 as a valid bit to NPDM flags. */
if (GetRuntimeFirmwareVersion() >= FirmwareVersion_700) { if (GetRuntimeFirmwareVersion() >= FirmwareVersion_700) {
if (info->header->mmu_flags > 0x1F) { if (info->header->mmu_flags > 0x1F) {
return rc; return ResultLoaderInvalidMeta;
} }
} else { } else {
if (info->header->mmu_flags > 0xF) { if (info->header->mmu_flags > 0xF) {
return rc; return ResultLoaderInvalidMeta;
} }
} }
if (info->header->aci0_offset < sizeof(NpdmUtils::NpdmHeader) || info->header->aci0_size < sizeof(NpdmUtils::NpdmAci0) || info->header->aci0_offset + info->header->aci0_size > npdm_size) { if (info->header->aci0_offset < sizeof(NpdmUtils::NpdmHeader) || info->header->aci0_size < sizeof(NpdmUtils::NpdmAci0) || info->header->aci0_offset + info->header->aci0_size > npdm_size) {
return rc; return ResultLoaderInvalidMeta;
} }
info->aci0 = (NpdmAci0 *)(cache->buffer + info->header->aci0_offset); info->aci0 = (NpdmAci0 *)(cache->buffer + info->header->aci0_offset);
if (info->aci0->magic != MAGIC_ACI0) { if (info->aci0->magic != MAGIC_ACI0) {
return rc; return ResultLoaderInvalidMeta;
} }
if (info->aci0->fah_size > info->header->aci0_size || info->aci0->fah_offset < sizeof(NpdmUtils::NpdmAci0) || info->aci0->fah_offset + info->aci0->fah_size > info->header->aci0_size) { if (info->aci0->fah_size > info->header->aci0_size || info->aci0->fah_offset < sizeof(NpdmUtils::NpdmAci0) || info->aci0->fah_offset + info->aci0->fah_size > info->header->aci0_size) {
return rc; return ResultLoaderInvalidMeta;
} }
info->aci0_fah = (void *)((uintptr_t)info->aci0 + info->aci0->fah_offset); info->aci0_fah = (void *)((uintptr_t)info->aci0 + info->aci0->fah_offset);
if (info->aci0->sac_size > info->header->aci0_size || info->aci0->sac_offset < sizeof(NpdmUtils::NpdmAci0) || info->aci0->sac_offset + info->aci0->sac_size > info->header->aci0_size) { if (info->aci0->sac_size > info->header->aci0_size || info->aci0->sac_offset < sizeof(NpdmUtils::NpdmAci0) || info->aci0->sac_offset + info->aci0->sac_size > info->header->aci0_size) {
return rc; return ResultLoaderInvalidMeta;
} }
info->aci0_sac = (void *)((uintptr_t)info->aci0 + info->aci0->sac_offset); info->aci0_sac = (void *)((uintptr_t)info->aci0 + info->aci0->sac_offset);
if (info->aci0->kac_size > info->header->aci0_size || info->aci0->kac_offset < sizeof(NpdmUtils::NpdmAci0) || info->aci0->kac_offset + info->aci0->kac_size > info->header->aci0_size) { if (info->aci0->kac_size > info->header->aci0_size || info->aci0->kac_offset < sizeof(NpdmUtils::NpdmAci0) || info->aci0->kac_offset + info->aci0->kac_size > info->header->aci0_size) {
return rc; return ResultLoaderInvalidMeta;
} }
info->aci0_kac = (void *)((uintptr_t)info->aci0 + info->aci0->kac_offset); info->aci0_kac = (void *)((uintptr_t)info->aci0 + info->aci0->kac_offset);
if (info->header->acid_offset < sizeof(NpdmUtils::NpdmHeader) || info->header->acid_size < sizeof(NpdmUtils::NpdmAcid) || info->header->acid_offset + info->header->acid_size > npdm_size) { if (info->header->acid_offset < sizeof(NpdmUtils::NpdmHeader) || info->header->acid_size < sizeof(NpdmUtils::NpdmAcid) || info->header->acid_offset + info->header->acid_size > npdm_size) {
return rc; return ResultLoaderInvalidMeta;
} }
info->acid = (NpdmAcid *)(cache->buffer + info->header->acid_offset); info->acid = (NpdmAcid *)(cache->buffer + info->header->acid_offset);
if (info->acid->magic != MAGIC_ACID) { if (info->acid->magic != MAGIC_ACID) {
return rc; return ResultLoaderInvalidMeta;
} }
/* TODO: Check if retail flag is set if not development hardware. */ /* TODO: Check if retail flag is set if not development hardware. */
if (info->acid->fac_size > info->header->acid_size || info->acid->fac_offset < sizeof(NpdmUtils::NpdmAcid) || info->acid->fac_offset + info->acid->fac_size > info->header->acid_size) { if (info->acid->fac_size > info->header->acid_size || info->acid->fac_offset < sizeof(NpdmUtils::NpdmAcid) || info->acid->fac_offset + info->acid->fac_size > info->header->acid_size) {
return rc; return ResultLoaderInvalidMeta;
} }
info->acid_fac = (void *)((uintptr_t)info->acid + info->acid->fac_offset); info->acid_fac = (void *)((uintptr_t)info->acid + info->acid->fac_offset);
if (info->acid->sac_size > info->header->acid_size || info->acid->sac_offset < sizeof(NpdmUtils::NpdmAcid) || info->acid->sac_offset + info->acid->sac_size > info->header->acid_size) { if (info->acid->sac_size > info->header->acid_size || info->acid->sac_offset < sizeof(NpdmUtils::NpdmAcid) || info->acid->sac_offset + info->acid->sac_size > info->header->acid_size) {
return rc; return ResultLoaderInvalidMeta;
} }
info->acid_sac = (void *)((uintptr_t)info->acid + info->acid->sac_offset); info->acid_sac = (void *)((uintptr_t)info->acid + info->acid->sac_offset);
if (info->acid->kac_size > info->header->acid_size || info->acid->kac_offset < sizeof(NpdmUtils::NpdmAcid) || info->acid->kac_offset + info->acid->kac_size > info->header->acid_size) { if (info->acid->kac_size > info->header->acid_size || info->acid->kac_offset < sizeof(NpdmUtils::NpdmAcid) || info->acid->kac_offset + info->acid->kac_size > info->header->acid_size) {
return rc; return ResultLoaderInvalidMeta;
} }
info->acid_kac = (void *)((uintptr_t)info->acid + info->acid->kac_offset); info->acid_kac = (void *)((uintptr_t)info->acid + info->acid->kac_offset);
rc = ResultSuccess; return ResultSuccess;
return rc;
} }
Result NpdmUtils::LoadNpdm(u64 tid, NpdmInfo *out) { Result NpdmUtils::LoadNpdm(u64 tid, NpdmInfo *out) {
Result rc; /* Load and validate the NPDM. */
R_TRY(LoadNpdmInternal(OpenNpdm(tid), &g_npdm_cache));
rc = LoadNpdmInternal(OpenNpdm(tid), &g_npdm_cache);
if (R_FAILED(rc)) {
return rc;
}
NpdmInfo *info = &g_npdm_cache.info; NpdmInfo *info = &g_npdm_cache.info;
/* Override the ACID/ACI0 title ID, in order to facilitate HBL takeover of any title. */ /* Override the ACID/ACI0 title ID, in order to facilitate HBL takeover of any title. */
info->acid->title_id_range_min = tid; info->acid->title_id_range_min = tid;
info->acid->title_id_range_max = tid; info->acid->title_id_range_max = tid;
info->aci0->title_id = tid; info->aci0->title_id = tid;
if (ContentManagement::ShouldOverrideContentsWithHBL(tid) && R_SUCCEEDED(LoadNpdmInternal(OpenNpdmFromExeFS(), &g_original_npdm_cache))) { if (ContentManagement::ShouldOverrideContentsWithHBL(tid) && R_SUCCEEDED(LoadNpdmInternal(OpenNpdmFromExeFS(), &g_original_npdm_cache))) {
NpdmInfo *original_info = &g_original_npdm_cache.info; NpdmInfo *original_info = &g_original_npdm_cache.info;
/* Fix pool partition. */ /* Fix pool partition. */
@ -226,17 +215,15 @@ Result NpdmUtils::LoadNpdm(u64 tid, NpdmInfo *out) {
} }
} }
} }
/* We validated! */ /* We validated! */
info->title_id = tid; info->title_id = tid;
*out = *info; *out = *info;
rc = ResultSuccess;
return ResultSuccess;
return rc;
} }
Result NpdmUtils::ValidateCapabilityAgainstRestrictions(u32 *restrict_caps, size_t num_restrict_caps, u32 *&cur_cap, size_t &caps_remaining) { Result NpdmUtils::ValidateCapabilityAgainstRestrictions(const u32 *restrict_caps, size_t num_restrict_caps, const u32 *&cur_cap, size_t &caps_remaining) {
Result rc = ResultSuccess;
u32 desc = *cur_cap++; u32 desc = *cur_cap++;
caps_remaining--; caps_remaining--;
unsigned int low_bits = 0; unsigned int low_bits = 0;
@ -248,7 +235,6 @@ Result NpdmUtils::ValidateCapabilityAgainstRestrictions(u32 *restrict_caps, size
u32 r_desc = 0; u32 r_desc = 0;
switch (low_bits) { switch (low_bits) {
case 3: /* Kernel flags. */ case 3: /* Kernel flags. */
rc = ResultLoaderInvalidCapabilityKernelFlags;
for (size_t i = 0; i < num_restrict_caps; i++) { for (size_t i = 0; i < num_restrict_caps; i++) {
if ((restrict_caps[i] & 0xF) == 0x7) { if ((restrict_caps[i] & 0xF) == 0x7) {
r_desc = restrict_caps[i] >> 4; r_desc = restrict_caps[i] >> 4;
@ -283,18 +269,16 @@ Result NpdmUtils::ValidateCapabilityAgainstRestrictions(u32 *restrict_caps, size
} }
if (highest_cpu_id > r_highest_cpu_id) { if (highest_cpu_id > r_highest_cpu_id) {
break; break;
} }
/* Valid! */ /* Valid! */
rc = ResultSuccess; return ResultSuccess;
break;
} }
} }
break; return ResultLoaderInvalidCapabilityKernelFlags;
case 4: /* Syscall mask. */ case 4: /* Syscall mask. */
rc = ResultLoaderInvalidCapabilitySyscallMask;
for (size_t i = 0; i < num_restrict_caps; i++) { for (size_t i = 0; i < num_restrict_caps; i++) {
if ((restrict_caps[i] & 0x1F) == 0xF) { if ((restrict_caps[i] & 0x1F) == 0xF) {
r_desc = restrict_caps[i] >> 5; r_desc = restrict_caps[i] >> 5;
u32 syscall_base = (desc >> 24); u32 syscall_base = (desc >> 24);
u32 r_syscall_base = (r_desc >> 24); u32 r_syscall_base = (r_desc >> 24);
if (syscall_base != r_syscall_base) { if (syscall_base != r_syscall_base) {
@ -306,32 +290,31 @@ Result NpdmUtils::ValidateCapabilityAgainstRestrictions(u32 *restrict_caps, size
break; break;
} }
/* Valid! */ /* Valid! */
rc = ResultSuccess; return ResultSuccess;
break;
} }
} }
break; return ResultLoaderInvalidCapabilitySyscallMask;
case 6: /* Map IO/Normal. */ { case 6: /* Map IO/Normal. */
rc = ResultLoaderInvalidCapabilityMapRange; {
if (caps_remaining == 0) { if (caps_remaining == 0) {
break; return ResultLoaderInvalidCapabilityMapRange;
} }
u32 next_cap = *cur_cap++; u32 next_cap = *cur_cap++;
caps_remaining--; caps_remaining--;
if ((next_cap & 0x7F) != 0x3F) { if ((next_cap & 0x7F) != 0x3F) {
break; return ResultLoaderInvalidCapabilityMapRange;
} }
u32 next_desc = next_cap >> 7; u32 next_desc = next_cap >> 7;
u32 base_addr = desc & 0xFFFFFF; u32 base_addr = desc & 0xFFFFFF;
u32 base_size = next_desc & 0xFFFFFF; u32 base_size = next_desc & 0xFFFFFF;
/* Size check the mapping. */ /* Size check the mapping. */
if (base_size >> 20) { if (base_size >> 20) {
break; return ResultLoaderInvalidCapabilityMapRange;
} }
u32 base_end = base_addr + base_size; u32 base_end = base_addr + base_size;
/* Validate it's possible to validate this mapping. */ /* Validate it's possible to validate this mapping. */
if (num_restrict_caps < 2) { if (num_restrict_caps < 2) {
break; return ResultLoaderInvalidCapabilityMapRange;
} }
for (size_t i = 0; i < num_restrict_caps - 1; i++) { for (size_t i = 0; i < num_restrict_caps - 1; i++) {
if ((restrict_caps[i] & 0x7F) == 0x3F) { if ((restrict_caps[i] & 0x7F) == 0x3F) {
@ -360,28 +343,24 @@ Result NpdmUtils::ValidateCapabilityAgainstRestrictions(u32 *restrict_caps, size
continue; continue;
} }
/* Valid! */ /* Valid! */
rc = ResultSuccess; return ResultSuccess;
break;
} }
} }
} }
break; return ResultLoaderInvalidCapabilityMapRange;
case 7: /* Map Normal Page. */ case 7: /* Map Normal Page. */
rc = ResultLoaderInvalidCapabilityMapPage;
for (size_t i = 0; i < num_restrict_caps; i++) { for (size_t i = 0; i < num_restrict_caps; i++) {
if ((restrict_caps[i] & 0xFF) == 0x7F) { if ((restrict_caps[i] & 0xFF) == 0x7F) {
r_desc = restrict_caps[i] >> 8; r_desc = restrict_caps[i] >> 8;
if (r_desc != desc) { if (r_desc != desc) {
continue; continue;
} }
/* Valid! */ /* Valid! */
rc = ResultSuccess; return ResultSuccess;
break;
} }
} }
break; return ResultLoaderInvalidCapabilityMapPage;
case 11: /* IRQ Pair. */ case 11: /* IRQ Pair. */
rc = ResultSuccess;
for (unsigned int irq_i = 0; irq_i < 2; irq_i++) { for (unsigned int irq_i = 0; irq_i < 2; irq_i++) {
u32 irq = desc & 0x3FF; u32 irq = desc & 0x3FF;
desc >>= 10; desc >>= 10;
@ -398,18 +377,16 @@ Result NpdmUtils::ValidateCapabilityAgainstRestrictions(u32 *restrict_caps, size
} }
} }
if (!found) { if (!found) {
rc = ResultLoaderInvalidCapabilityInterruptPair; return ResultLoaderInvalidCapabilityInterruptPair;
break;
} }
} }
} }
break; return ResultSuccess;
case 13: /* App Type. */ case 13: /* App Type. */
rc = ResultLoaderInvalidCapabilityApplicationType;
if (num_restrict_caps) { if (num_restrict_caps) {
for (size_t i = 0; i < num_restrict_caps; i++) { for (size_t i = 0; i < num_restrict_caps; i++) {
if ((restrict_caps[i] & 0x3FFF) == 0x1FFF) { if ((restrict_caps[i] & 0x3FFF) == 0x1FFF) {
r_desc = restrict_caps[i] >> 14; r_desc = restrict_caps[i] >> 14;
break; break;
} }
} }
@ -418,15 +395,14 @@ Result NpdmUtils::ValidateCapabilityAgainstRestrictions(u32 *restrict_caps, size
} }
if (desc == r_desc) { if (desc == r_desc) {
/* Valid! */ /* Valid! */
rc = ResultSuccess; return ResultSuccess;
} }
break; return ResultLoaderInvalidCapabilityApplicationType;
case 14: /* Kernel Release Version. */ case 14: /* Kernel Release Version. */
rc = ResultLoaderInvalidCapabilityKernelVersion;
if (num_restrict_caps) { if (num_restrict_caps) {
for (size_t i = 0; i < num_restrict_caps; i++) { for (size_t i = 0; i < num_restrict_caps; i++) {
if ((restrict_caps[i] & 0x7FFF) == 0x3FFF) { if ((restrict_caps[i] & 0x7FFF) == 0x3FFF) {
r_desc = restrict_caps[i] >> 15; r_desc = restrict_caps[i] >> 15;
break; break;
} }
} }
@ -435,31 +411,28 @@ Result NpdmUtils::ValidateCapabilityAgainstRestrictions(u32 *restrict_caps, size
} }
if (desc == r_desc) { if (desc == r_desc) {
/* Valid! */ /* Valid! */
rc = ResultSuccess; return ResultSuccess;
} }
break; return ResultLoaderInvalidCapabilityKernelVersion;
case 15: /* Handle Table Size. */ case 15: /* Handle Table Size. */
rc = ResultLoaderInvalidCapabilityHandleTable;
for (size_t i = 0; i < num_restrict_caps; i++) { for (size_t i = 0; i < num_restrict_caps; i++) {
if ((restrict_caps[i] & 0xFFFF) == 0x7FFF) { if ((restrict_caps[i] & 0xFFFF) == 0x7FFF) {
r_desc = restrict_caps[i] >> 16; r_desc = restrict_caps[i] >> 16;
desc &= 0x3FF; desc &= 0x3FF;
r_desc &= 0x3FF; r_desc &= 0x3FF;
if (desc > r_desc) { if (desc > r_desc) {
break; break;
} }
/* Valid! */ /* Valid! */
rc = ResultSuccess; return ResultSuccess;
break;
} }
} }
break; return ResultLoaderInvalidCapabilityHandleTable;
case 16: /* Debug Flags. */ case 16: /* Debug Flags. */
rc = ResultLoaderInvalidCapabilityDebugFlags;
if (num_restrict_caps) { if (num_restrict_caps) {
for (size_t i = 0; i < num_restrict_caps; i++) { for (size_t i = 0; i < num_restrict_caps; i++) {
if ((restrict_caps[i] & 0x1FFFF) == 0xFFFF) { if ((restrict_caps[i] & 0x1FFFF) == 0xFFFF) {
r_desc = restrict_caps[i] >> 17; r_desc = restrict_caps[i] >> 17;
break; break;
} }
} }
@ -468,33 +441,29 @@ Result NpdmUtils::ValidateCapabilityAgainstRestrictions(u32 *restrict_caps, size
} }
if ((desc & ~r_desc) == 0) { if ((desc & ~r_desc) == 0) {
/* Valid! */ /* Valid! */
rc = ResultSuccess; return ResultSuccess;
} }
break; return ResultLoaderInvalidCapabilityDebugFlags;
case 32: /* Empty Descriptor. */ case 32: /* Empty Descriptor. */
rc = ResultSuccess; return ResultSuccess;
break;
default: /* Unrecognized Descriptor. */ default: /* Unrecognized Descriptor. */
rc = ResultLoaderUnknownCapability; return ResultLoaderUnknownCapability;
break;
} }
return rc;
} }
Result NpdmUtils::ValidateCapabilities(u32 *acid_caps, size_t num_acid_caps, u32 *aci0_caps, size_t num_aci0_caps) { Result NpdmUtils::ValidateCapabilities(const u32 *acid_caps, size_t num_acid_caps, const u32 *aci0_caps, size_t num_aci0_caps) {
Result rc = ResultSuccess; const u32 *cur_cap = aci0_caps;
size_t remaining = num_aci0_caps; size_t remaining = num_aci0_caps;
u32 *cur_cap = aci0_caps;
while (remaining) { while (remaining) {
if (R_FAILED((rc = ValidateCapabilityAgainstRestrictions(acid_caps, num_acid_caps, cur_cap, remaining)))) { /* Validate, update capabilities. cur_cap and remaining passed by reference. */
break; R_TRY(ValidateCapabilityAgainstRestrictions(acid_caps, num_acid_caps, cur_cap, remaining));
}
} }
return rc; return ResultSuccess;
} }
u32 NpdmUtils::GetApplicationType(u32 *caps, size_t num_caps) { u32 NpdmUtils::GetApplicationType(const u32 *caps, size_t num_caps) {
u32 application_type = 0; u32 application_type = 0;
for (unsigned int i = 0; i < num_caps; i++) { for (unsigned int i = 0; i < num_caps; i++) {
if ((caps[i] & 0x3FFF) == 0x1FFF) { if ((caps[i] & 0x3FFF) == 0x1FFF) {
@ -514,7 +483,7 @@ u32 NpdmUtils::GetApplicationType(u32 *caps, size_t num_caps) {
} }
/* Like GetApplicationType, except this returns the raw kac descriptor value. */ /* Like GetApplicationType, except this returns the raw kac descriptor value. */
u32 NpdmUtils::GetApplicationTypeRaw(u32 *caps, size_t num_caps) { u32 NpdmUtils::GetApplicationTypeRaw(const u32 *caps, size_t num_caps) {
u32 application_type = 0; u32 application_type = 0;
for (unsigned int i = 0; i < num_caps; i++) { for (unsigned int i = 0; i < num_caps; i++) {
if ((caps[i] & 0x3FFF) == 0x1FFF) { if ((caps[i] & 0x3FFF) == 0x1FFF) {

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <switch.h> #include <switch.h>
#include <cstdio> #include <cstdio>
@ -25,7 +25,7 @@
#define MAGIC_ACI0 0x30494341 #define MAGIC_ACI0 0x30494341
#define MAGIC_ACID 0x44494341 #define MAGIC_ACID 0x44494341
class NpdmUtils { class NpdmUtils {
public: public:
struct NpdmHeader { struct NpdmHeader {
u32 magic; u32 magic;
@ -91,17 +91,17 @@ class NpdmUtils {
NpdmInfo info; NpdmInfo info;
u8 buffer[0x8000]; u8 buffer[0x8000];
}; };
static_assert(sizeof(NpdmHeader) == 0x80, "Incorrectly defined NpdmHeader!"); static_assert(sizeof(NpdmHeader) == 0x80, "Incorrectly defined NpdmHeader!");
static_assert(sizeof(NpdmAcid) == 0x240, "Incorrectly defined NpdmAcid!"); static_assert(sizeof(NpdmAcid) == 0x240, "Incorrectly defined NpdmAcid!");
static_assert(sizeof(NpdmAci0) == 0x40, "Incorrectly defined NpdmAci0!"); static_assert(sizeof(NpdmAci0) == 0x40, "Incorrectly defined NpdmAci0!");
static u32 GetApplicationType(u32 *caps, size_t num_caps); static u32 GetApplicationType(const u32 *caps, size_t num_caps);
static u32 GetApplicationTypeRaw(u32 *caps, size_t num_caps); static u32 GetApplicationTypeRaw(const u32 *caps, size_t num_caps);
static Result ValidateCapabilityAgainstRestrictions(u32 *restrict_caps, size_t num_restrict_caps, u32 *&cur_cap, size_t &caps_remaining); static Result ValidateCapabilityAgainstRestrictions(const u32 *restrict_caps, size_t num_restrict_caps, const 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 ValidateCapabilities(const u32 *acid_caps, size_t num_acid_caps, const u32 *aci0_caps, size_t num_aci0_caps);
static FILE *OpenNpdmFromECS(ContentManagement::ExternalContentSource *ecs); static FILE *OpenNpdmFromECS(ContentManagement::ExternalContentSource *ecs);
static FILE *OpenNpdmFromHBL(); static FILE *OpenNpdmFromHBL();
static FILE *OpenNpdmFromExeFS(); static FILE *OpenNpdmFromExeFS();

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <switch.h> #include <switch.h>
#include <algorithm> #include <algorithm>
#include <cstdio> #include <cstdio>
@ -47,7 +47,7 @@ FILE *NsoUtils::OpenNsoFromExeFS(unsigned int index) {
return fopen(g_nso_path, "rb"); return fopen(g_nso_path, "rb");
} }
FILE *NsoUtils::OpenNsoFromSdCard(unsigned int index, u64 title_id) { FILE *NsoUtils::OpenNsoFromSdCard(unsigned int index, u64 title_id) {
std::fill(g_nso_path, g_nso_path + FS_MAX_PATH, 0); std::fill(g_nso_path, g_nso_path + FS_MAX_PATH, 0);
snprintf(g_nso_path, FS_MAX_PATH, "sdmc:/atmosphere/titles/%016lx/exefs/%s", title_id, NsoUtils::GetNsoFileName(index)); snprintf(g_nso_path, FS_MAX_PATH, "sdmc:/atmosphere/titles/%016lx/exefs/%s", title_id, NsoUtils::GetNsoFileName(index));
return fopen(g_nso_path, "rb"); return fopen(g_nso_path, "rb");
@ -69,7 +69,7 @@ FILE *NsoUtils::OpenNso(unsigned int index, u64 title_id) {
if ((ecs = ContentManagement::GetExternalContentSource(title_id)) != nullptr) { if ((ecs = ContentManagement::GetExternalContentSource(title_id)) != nullptr) {
return OpenNsoFromECS(index, ecs); return OpenNsoFromECS(index, ecs);
} }
/* First, check HBL. */ /* First, check HBL. */
if (ContentManagement::ShouldOverrideContentsWithHBL(title_id)) { if (ContentManagement::ShouldOverrideContentsWithHBL(title_id)) {
return OpenNsoFromHBL(index); return OpenNsoFromHBL(index);
@ -84,7 +84,7 @@ FILE *NsoUtils::OpenNso(unsigned int index, u64 title_id) {
return NULL; return NULL;
} }
} }
/* Finally, default to exefs. */ /* Finally, default to exefs. */
return OpenNsoFromExeFS(index); return OpenNsoFromExeFS(index);
} }
@ -103,11 +103,11 @@ unsigned char *NsoUtils::GetNsoBuildId(unsigned int index) {
Result NsoUtils::LoadNsoHeaders(u64 title_id) { Result NsoUtils::LoadNsoHeaders(u64 title_id) {
FILE *f_nso; FILE *f_nso;
/* Zero out the cache. */ /* Zero out the cache. */
std::fill(g_nso_present, g_nso_present + NSO_NUM_MAX, false); std::fill(g_nso_present, g_nso_present + NSO_NUM_MAX, false);
std::fill(g_nso_headers, g_nso_headers + NSO_NUM_MAX, NsoUtils::NsoHeader{}); std::fill(g_nso_headers, g_nso_headers + NSO_NUM_MAX, NsoUtils::NsoHeader{});
for (unsigned int i = 0; i < NSO_NUM_MAX; i++) { for (unsigned int i = 0; i < NSO_NUM_MAX; i++) {
f_nso = OpenNso(i, title_id); f_nso = OpenNso(i, title_id);
if (f_nso != NULL) { if (f_nso != NULL) {
@ -124,7 +124,7 @@ Result NsoUtils::LoadNsoHeaders(u64 title_id) {
i = 11; i = 11;
} }
} }
return ResultSuccess; return ResultSuccess;
} }
@ -133,7 +133,7 @@ Result NsoUtils::ValidateNsoLoadSet() {
if (!g_nso_present[1]) { if (!g_nso_present[1]) {
return ResultLoaderInvalidNso; return ResultLoaderInvalidNso;
} }
/* Behavior switches depending on whether we have an rtld. */ /* Behavior switches depending on whether we have an rtld. */
if (g_nso_present[0]) { if (g_nso_present[0]) {
/* If we have an rtld, dst offset for .text must be 0 for all other NSOs. */ /* If we have an rtld, dst offset for .text must be 0 for all other NSOs. */
@ -154,7 +154,7 @@ Result NsoUtils::ValidateNsoLoadSet() {
return ResultLoaderInvalidNso; return ResultLoaderInvalidNso;
} }
} }
return ResultSuccess; return ResultSuccess;
} }
@ -188,7 +188,7 @@ Result NsoUtils::CalculateNsoLoadExtents(u32 addspace_type, u32 args_size, NsoLo
} }
} }
} }
/* Calculate ASLR extents for address space type. */ /* Calculate ASLR extents for address space type. */
u64 addspace_start, addspace_size; u64 addspace_start, addspace_size;
if ((GetRuntimeFirmwareVersion() >= FirmwareVersion_200)) { if ((GetRuntimeFirmwareVersion() >= FirmwareVersion_200)) {
@ -221,12 +221,12 @@ Result NsoUtils::CalculateNsoLoadExtents(u32 addspace_type, u32 args_size, NsoLo
if (extents->total_size > addspace_size) { if (extents->total_size > addspace_size) {
return ResultKernelOutOfMemory; return ResultKernelOutOfMemory;
} }
u64 aslr_slide = 0; u64 aslr_slide = 0;
if (addspace_type & 0x20) { if (addspace_type & 0x20) {
aslr_slide = StratosphereRandomUtils::GetRandomU64((addspace_size - extents->total_size) >> 21) << 21; aslr_slide = StratosphereRandomUtils::GetRandomU64((addspace_size - extents->total_size) >> 21) << 21;
} }
extents->base_address = addspace_start + aslr_slide; extents->base_address = addspace_start + aslr_slide;
for (unsigned int i = 0; i < NSO_NUM_MAX; i++) { for (unsigned int i = 0; i < NSO_NUM_MAX; i++) {
if (g_nso_present[i]) { if (g_nso_present[i]) {
@ -236,7 +236,7 @@ Result NsoUtils::CalculateNsoLoadExtents(u32 addspace_type, u32 args_size, NsoLo
if (extents->args_address) { if (extents->args_address) {
extents->args_address += extents->base_address; extents->args_address += extents->base_address;
} }
return ResultSuccess; return ResultSuccess;
} }
@ -253,24 +253,24 @@ Result NsoUtils::LoadNsoSegment(u64 title_id, unsigned int index, unsigned int s
if ((u32)(size | out_size) >> 31) { if ((u32)(size | out_size) >> 31) {
return ResultLoaderInvalidNso; return ResultLoaderInvalidNso;
} }
u8 *dst_addr = map_base + g_nso_headers[index].segments[segment].dst_offset; u8 *dst_addr = map_base + g_nso_headers[index].segments[segment].dst_offset;
u8 *load_addr = is_compressed ? map_end - size : dst_addr; u8 *load_addr = is_compressed ? map_end - size : dst_addr;
fseek(f_nso, g_nso_headers[index].segments[segment].file_offset, SEEK_SET); fseek(f_nso, g_nso_headers[index].segments[segment].file_offset, SEEK_SET);
if (fread(load_addr, 1, size, f_nso) != size) { if (fread(load_addr, 1, size, f_nso) != size) {
return ResultLoaderInvalidNso; return ResultLoaderInvalidNso;
} }
if (is_compressed) { if (is_compressed) {
if (LZ4_decompress_safe((char *)load_addr, (char *)dst_addr, size, out_size) != (int)out_size) { if (LZ4_decompress_safe((char *)load_addr, (char *)dst_addr, size, out_size) != (int)out_size) {
return ResultLoaderInvalidNso; return ResultLoaderInvalidNso;
} }
} }
if (check_hash) { if (check_hash) {
u8 hash[0x20] = {0}; u8 hash[0x20] = {0};
sha256CalculateHash(hash, dst_addr, out_size); sha256CalculateHash(hash, dst_addr, out_size);
@ -279,35 +279,32 @@ Result NsoUtils::LoadNsoSegment(u64 title_id, unsigned int index, unsigned int s
return ResultLoaderInvalidNso; return ResultLoaderInvalidNso;
} }
} }
return ResultSuccess; return ResultSuccess;
} }
Result NsoUtils::LoadNsosIntoProcessMemory(Handle process_h, u64 title_id, NsoLoadExtents *extents, u8 *args, u32 args_size) { Result NsoUtils::LoadNsosIntoProcessMemory(Handle process_h, u64 title_id, NsoLoadExtents *extents, const u8 *args, u32 args_size) {
Result rc = ResultLoaderInvalidNso;
for (unsigned int i = 0; i < NSO_NUM_MAX; i++) { for (unsigned int i = 0; i < NSO_NUM_MAX; i++) {
if (g_nso_present[i]) { if (g_nso_present[i]) {
AutoCloseMap nso_map; AutoCloseMap nso_map;
if (R_FAILED((rc = nso_map.Open(process_h, extents->nso_addresses[i], extents->nso_sizes[i])))) { R_TRY(nso_map.Open(process_h, extents->nso_addresses[i], extents->nso_sizes[i]));
return rc;
}
u8 *map_base = (u8 *)nso_map.GetMappedAddress(); u8 *map_base = (u8 *)nso_map.GetMappedAddress();
FILE *f_nso = OpenNso(i, title_id); /* Load NSO segments from file. */
if (f_nso == NULL) { {
/* TODO: Is there a better error to return here? */ FILE *f_nso = OpenNso(i, title_id);
return ResultLoaderInvalidNso; if (f_nso == NULL) {
} /* TODO: Is there a better error to return here? */
for (unsigned int seg = 0; seg < 3; seg++) { return ResultLoaderInvalidNso;
if (R_FAILED((rc = LoadNsoSegment(title_id, i, seg, f_nso, map_base, map_base + extents->nso_sizes[i])))) { }
fclose(f_nso); ON_SCOPE_EXIT { fclose(f_nso); };
return rc;
for (unsigned int seg = 0; seg < 3; seg++) {
R_TRY(LoadNsoSegment(title_id, i, seg, f_nso, map_base, map_base + extents->nso_sizes[i]));
} }
} }
fclose(f_nso);
f_nso = NULL;
/* Zero out memory before .text. */ /* Zero out memory before .text. */
u64 text_base = 0, text_start = g_nso_headers[i].segments[0].dst_offset; u64 text_base = 0, text_start = g_nso_headers[i].segments[0].dst_offset;
std::fill(map_base + text_base, map_base + text_start, 0); std::fill(map_base + text_base, map_base + text_start, 0);
@ -320,12 +317,12 @@ Result NsoUtils::LoadNsosIntoProcessMemory(Handle process_h, u64 title_id, NsoLo
/* Zero out .bss. */ /* Zero out .bss. */
u64 bss_base = rw_start + g_nso_headers[i].segments[2].decomp_size, bss_size = g_nso_headers[i].segments[2].align_or_total_size; u64 bss_base = rw_start + g_nso_headers[i].segments[2].decomp_size, bss_size = g_nso_headers[i].segments[2].align_or_total_size;
std::fill(map_base + bss_base, map_base + bss_base + bss_size, 0); std::fill(map_base + bss_base, map_base + bss_base + bss_size, 0);
/* Apply patches to loaded module. */ /* Apply patches to loaded module. */
PatchUtils::ApplyPatches(&g_nso_headers[i], map_base, bss_base); PatchUtils::ApplyPatches(&g_nso_headers[i], map_base, bss_base);
nso_map.Close(); nso_map.Close();
for (unsigned int seg = 0; seg < 3; seg++) { for (unsigned int seg = 0; seg < 3; seg++) {
u64 size = g_nso_headers[i].segments[seg].decomp_size; u64 size = g_nso_headers[i].segments[seg].decomp_size;
if (seg == 2) { if (seg == 2) {
@ -334,33 +331,27 @@ Result NsoUtils::LoadNsosIntoProcessMemory(Handle process_h, u64 title_id, NsoLo
size += 0xFFF; size += 0xFFF;
size &= ~0xFFFULL; size &= ~0xFFFULL;
const static unsigned int segment_perms[3] = {5, 1, 3}; const static unsigned int segment_perms[3] = {5, 1, 3};
if (R_FAILED((rc = svcSetProcessMemoryPermission(process_h, extents->nso_addresses[i] + g_nso_headers[i].segments[seg].dst_offset, size, segment_perms[seg])))) { R_TRY(svcSetProcessMemoryPermission(process_h, extents->nso_addresses[i] + g_nso_headers[i].segments[seg].dst_offset, size, segment_perms[seg]));
return rc;
}
} }
} }
} }
/* Map in arguments. */ /* Map in arguments. */
if (args != NULL && args_size) { if (args != nullptr && args_size) {
AutoCloseMap args_map; AutoCloseMap args_map;
if (R_FAILED((rc = args_map.Open(process_h, extents->args_address, extents->args_size)))) { R_TRY(args_map.Open(process_h, extents->args_address, extents->args_size));
return rc;
}
NsoArgument *arg_map_base = (NsoArgument *)args_map.GetMappedAddress(); NsoArgument *arg_map_base = (NsoArgument *)args_map.GetMappedAddress();
arg_map_base->allocated_space = extents->args_size; arg_map_base->allocated_space = extents->args_size;
arg_map_base->args_size = args_size; arg_map_base->args_size = args_size;
std::fill(arg_map_base->_0x8, arg_map_base->_0x8 + sizeof(arg_map_base->_0x8), 0); std::fill(arg_map_base->_0x8, arg_map_base->_0x8 + sizeof(arg_map_base->_0x8), 0);
std::copy(args, args + args_size, arg_map_base->arguments); std::copy(args, args + args_size, arg_map_base->arguments);
args_map.Close(); args_map.Close();
if (R_FAILED((rc = svcSetProcessMemoryPermission(process_h, extents->args_address, extents->args_size, 3)))) { R_TRY(svcSetProcessMemoryPermission(process_h, extents->args_address, extents->args_size, 3));
return rc;
}
} }
return rc; return ResultSuccess;
} }

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <switch.h> #include <switch.h>
#include <cstdio> #include <cstdio>
@ -31,7 +31,7 @@ class NsoUtils {
u32 decomp_size; u32 decomp_size;
u32 align_or_total_size; u32 align_or_total_size;
}; };
struct NsoHeader { struct NsoHeader {
u32 magic; u32 magic;
u32 _0x4; u32 _0x4;
@ -45,7 +45,7 @@ class NsoUtils {
u64 dynsym_extents; u64 dynsym_extents;
u8 section_hashes[3][0x20]; u8 section_hashes[3][0x20];
}; };
struct NsoLoadExtents { struct NsoLoadExtents {
u64 base_address; u64 base_address;
u64 total_size; u64 total_size;
@ -54,17 +54,17 @@ class NsoUtils {
u64 nso_addresses[NSO_NUM_MAX]; u64 nso_addresses[NSO_NUM_MAX];
u64 nso_sizes[NSO_NUM_MAX]; u64 nso_sizes[NSO_NUM_MAX];
}; };
struct NsoArgument { struct NsoArgument {
u32 allocated_space; u32 allocated_space;
u32 args_size; u32 args_size;
u8 _0x8[0x18]; u8 _0x8[0x18];
u8 arguments[]; u8 arguments[];
}; };
static_assert(sizeof(NsoHeader) == 0x100, "Incorrectly defined NsoHeader!"); static_assert(sizeof(NsoHeader) == 0x100, "Incorrectly defined NsoHeader!");
static const char *GetNsoFileName(unsigned int index) { static const char *GetNsoFileName(unsigned int index) {
switch (index) { switch (index) {
case 0: case 0:
@ -104,13 +104,13 @@ class NsoUtils {
static FILE *OpenNsoFromSdCard(unsigned int index, u64 title_id); static FILE *OpenNsoFromSdCard(unsigned int index, u64 title_id);
static bool CheckNsoStubbed(unsigned int index, u64 title_id); static bool CheckNsoStubbed(unsigned int index, u64 title_id);
static FILE *OpenNso(unsigned int index, u64 title_id); static FILE *OpenNso(unsigned int index, u64 title_id);
static bool IsNsoPresent(unsigned int index); static bool IsNsoPresent(unsigned int index);
static unsigned char *GetNsoBuildId(unsigned int index); static unsigned char *GetNsoBuildId(unsigned int index);
static Result LoadNsoHeaders(u64 title_id); static Result LoadNsoHeaders(u64 title_id);
static Result ValidateNsoLoadSet(); static Result ValidateNsoLoadSet();
static Result CalculateNsoLoadExtents(u32 addspace_type, u32 args_size, NsoLoadExtents *extents); static Result CalculateNsoLoadExtents(u32 addspace_type, u32 args_size, NsoLoadExtents *extents);
static Result LoadNsoSegment(u64 title_id, unsigned int index, unsigned int segment, FILE *f_nso, u8 *map_base, u8 *map_end); static Result LoadNsoSegment(u64 title_id, unsigned int index, unsigned int segment, FILE *f_nso, u8 *map_base, u8 *map_end);
static Result LoadNsosIntoProcessMemory(Handle process_h, u64 title_id, NsoLoadExtents *extents, u8 *args, u32 args_size); static Result LoadNsosIntoProcessMemory(Handle process_h, u64 title_id, NsoLoadExtents *extents, const u8 *args, u32 args_size);
}; };

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <cstdlib> #include <cstdlib>
#include <cstdint> #include <cstdint>
#include <cstdio> #include <cstdio>
@ -49,14 +49,14 @@ static bool MatchesBuildId(const char *name, size_t name_len, const u8 *build_id
return false; return false;
} }
} }
/* Read build id from name. */ /* Read build id from name. */
u8 build_id_from_name[0x20] = {0}; u8 build_id_from_name[0x20] = {0};
for (unsigned int name_ofs = 0, id_ofs = 0; name_ofs < name_len - 4; id_ofs++) { for (unsigned int name_ofs = 0, id_ofs = 0; name_ofs < name_len - 4; id_ofs++) {
build_id_from_name[id_ofs] |= HexNybbleToU8(name[name_ofs++]) << 4; build_id_from_name[id_ofs] |= HexNybbleToU8(name[name_ofs++]) << 4;
build_id_from_name[id_ofs] |= HexNybbleToU8(name[name_ofs++]); build_id_from_name[id_ofs] |= HexNybbleToU8(name[name_ofs++]);
} }
return memcmp(build_id, build_id_from_name, sizeof(build_id_from_name)) == 0; return memcmp(build_id, build_id_from_name, sizeof(build_id_from_name)) == 0;
} }
@ -68,7 +68,7 @@ static void ApplyIpsPatch(u8 *mapped_nso, size_t mapped_size, bool is_ips32, FIL
} else if (!is_ips32 && memcmp(buffer, IPS_TAIL, 3) == 0) { } else if (!is_ips32 && memcmp(buffer, IPS_TAIL, 3) == 0) {
break; break;
} }
/* Offset of patch. */ /* Offset of patch. */
u32 patch_offset; u32 patch_offset;
if (is_ips32) { if (is_ips32) {
@ -76,27 +76,27 @@ static void ApplyIpsPatch(u8 *mapped_nso, size_t mapped_size, bool is_ips32, FIL
} else { } else {
patch_offset = (buffer[0] << 16) | (buffer[1] << 8) | (buffer[2]); patch_offset = (buffer[0] << 16) | (buffer[1] << 8) | (buffer[2]);
} }
/* Size of patch. */ /* Size of patch. */
if (fread(buffer, 2, 1, f_ips) != 1) { if (fread(buffer, 2, 1, f_ips) != 1) {
break; break;
} }
u32 patch_size = (buffer[0] << 8) | (buffer[1]); u32 patch_size = (buffer[0] << 8) | (buffer[1]);
/* Check for RLE encoding. */ /* Check for RLE encoding. */
if (patch_size == 0) { if (patch_size == 0) {
/* Size of RLE. */ /* Size of RLE. */
if (fread(buffer, 2, 1, f_ips) != 1) { if (fread(buffer, 2, 1, f_ips) != 1) {
break; break;
} }
u32 rle_size = (buffer[0] << 8) | (buffer[1]); u32 rle_size = (buffer[0] << 8) | (buffer[1]);
/* Value for RLE. */ /* Value for RLE. */
if (fread(buffer, 1, 1, f_ips) != 1) { if (fread(buffer, 1, 1, f_ips) != 1) {
break; break;
} }
if (patch_offset < sizeof(NsoUtils::NsoHeader)) { if (patch_offset < sizeof(NsoUtils::NsoHeader)) {
if (patch_offset + rle_size > sizeof(NsoUtils::NsoHeader)) { if (patch_offset + rle_size > sizeof(NsoUtils::NsoHeader)) {
u32 diff = sizeof(NsoUtils::NsoHeader) - patch_offset; u32 diff = sizeof(NsoUtils::NsoHeader) - patch_offset;

View file

@ -13,14 +13,14 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <switch.h> #include <switch.h>
#include <cstdio> #include <cstdio>
#include "ldr_nso.hpp" #include "ldr_nso.hpp"
class PatchUtils { class PatchUtils {
public: public:
static void ApplyPatches(const NsoUtils::NsoHeader *header, u8 *mapped_nso, size_t size); static void ApplyPatches(const NsoUtils::NsoHeader *header, u8 *mapped_nso, size_t size);
}; };

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <switch.h> #include <switch.h>
#include <algorithm> #include <algorithm>
#include <stratosphere.hpp> #include <stratosphere.hpp>
@ -28,27 +28,27 @@
Result ProcessCreation::InitializeProcessInfo(NpdmUtils::NpdmInfo *npdm, Handle reslimit_h, u64 arg_flags, ProcessInfo *out_proc_info) { Result ProcessCreation::InitializeProcessInfo(NpdmUtils::NpdmInfo *npdm, Handle reslimit_h, u64 arg_flags, ProcessInfo *out_proc_info) {
/* Initialize a ProcessInfo using an npdm. */ /* Initialize a ProcessInfo using an npdm. */
*out_proc_info = {}; *out_proc_info = {};
/* Copy all but last char of name, insert NULL terminator. */ /* Copy all but last char of name, insert NULL terminator. */
std::copy(npdm->header->title_name, npdm->header->title_name + sizeof(out_proc_info->name) - 1, out_proc_info->name); std::copy(npdm->header->title_name, npdm->header->title_name + sizeof(out_proc_info->name) - 1, out_proc_info->name);
out_proc_info->name[sizeof(out_proc_info->name) - 1] = 0; out_proc_info->name[sizeof(out_proc_info->name) - 1] = 0;
/* Set title id. */ /* Set title id. */
out_proc_info->title_id = npdm->aci0->title_id; out_proc_info->title_id = npdm->aci0->title_id;
/* Set process category. */ /* Set process category. */
out_proc_info->process_category = npdm->header->process_category; out_proc_info->process_category = npdm->header->process_category;
/* Copy reslimit handle raw. */ /* Copy reslimit handle raw. */
out_proc_info->reslimit_h = reslimit_h; out_proc_info->reslimit_h = reslimit_h;
/* Set IsAddressSpace64Bit, AddressSpaceType. */ /* Set IsAddressSpace64Bit, AddressSpaceType. */
if (npdm->header->mmu_flags & 8) { if (npdm->header->mmu_flags & 8) {
/* Invalid Address Space Type. */ /* Invalid Address Space Type. */
return ResultLoaderInvalidMeta; return ResultLoaderInvalidMeta;
} }
out_proc_info->process_flags = (npdm->header->mmu_flags & 0xF); out_proc_info->process_flags = (npdm->header->mmu_flags & 0xF);
/* Set Bit 4 (?) and EnableAslr based on argument flags. */ /* Set Bit 4 (?) and EnableAslr based on argument flags. */
out_proc_info->process_flags |= ((arg_flags & 3) << 4) ^ 0x20; out_proc_info->process_flags |= ((arg_flags & 3) << 4) ^ 0x20;
/* Set UseSystemMemBlocks if application type is 1. */ /* Set UseSystemMemBlocks if application type is 1. */
@ -62,7 +62,7 @@ Result ProcessCreation::InitializeProcessInfo(NpdmUtils::NpdmInfo *npdm, Handle
} }
} }
} }
/* 3.0.0+ System Resource Size. */ /* 3.0.0+ System Resource Size. */
if ((GetRuntimeFirmwareVersion() >= FirmwareVersion_300)) { if ((GetRuntimeFirmwareVersion() >= FirmwareVersion_300)) {
if (npdm->header->system_resource_size & 0x1FFFFF) { if (npdm->header->system_resource_size & 0x1FFFFF) {
@ -83,7 +83,7 @@ Result ProcessCreation::InitializeProcessInfo(NpdmUtils::NpdmInfo *npdm, Handle
} else { } else {
out_proc_info->system_resource_num_pages = 0; out_proc_info->system_resource_num_pages = 0;
} }
/* 5.0.0+ Pool Partition. */ /* 5.0.0+ Pool Partition. */
if ((GetRuntimeFirmwareVersion() >= FirmwareVersion_500)) { if ((GetRuntimeFirmwareVersion() >= FirmwareVersion_500)) {
u32 pool_partition_id = (npdm->acid->flags >> 2) & 0xF; u32 pool_partition_id = (npdm->acid->flags >> 2) & 0xF;
@ -106,7 +106,7 @@ Result ProcessCreation::InitializeProcessInfo(NpdmUtils::NpdmInfo *npdm, Handle
return ResultLoaderInvalidMeta; return ResultLoaderInvalidMeta;
} }
} }
return ResultSuccess; return ResultSuccess;
} }
@ -117,92 +117,82 @@ Result ProcessCreation::CreateProcess(Handle *out_process_h, u64 index, char *nc
Registration::Process *target_process; Registration::Process *target_process;
Handle process_h = 0; Handle process_h = 0;
u64 process_id = 0; u64 process_id = 0;
bool mounted_code = false;
Result rc;
/* Get the process from the registration queue. */ /* Get the process from the registration queue. */
target_process = Registration::GetProcess(index); target_process = Registration::GetProcess(index);
if (target_process == NULL) { if (target_process == nullptr) {
return ResultLoaderProcessNotRegistered; return ResultLoaderProcessNotRegistered;
} }
/* Mount the title's exefs. */ /* Mount the title's exefs. */
bool mounted_code = false;
if (target_process->tid_sid.storage_id != FsStorageId_None) { if (target_process->tid_sid.storage_id != FsStorageId_None) {
rc = ContentManagement::MountCodeForTidSid(&target_process->tid_sid); R_TRY(ContentManagement::MountCodeForTidSid(&target_process->tid_sid));
if (R_FAILED(rc)) {
return rc;
}
mounted_code = true; mounted_code = true;
} else { } else {
if (R_SUCCEEDED(ContentManagement::MountCodeNspOnSd(target_process->tid_sid.title_id))) { if (R_SUCCEEDED(ContentManagement::MountCodeNspOnSd(target_process->tid_sid.title_id))) {
mounted_code = true; mounted_code = true;
} }
} }
ON_SCOPE_EXIT {
if (mounted_code) {
if (R_FAILED(ContentManagement::UnmountCode()) && target_process->tid_sid.storage_id != FsStorageId_None) {
std::abort();
}
}
};
/* Load the process's NPDM. */ /* Load the process's NPDM. */
rc = NpdmUtils::LoadNpdmFromCache(target_process->tid_sid.title_id, &npdm_info); R_TRY(NpdmUtils::LoadNpdmFromCache(target_process->tid_sid.title_id, &npdm_info));
if (R_FAILED(rc)) {
goto CREATE_PROCESS_END;
}
/* Validate the title we're loading is what we expect. */ /* Validate the title we're loading is what we expect. */
if (npdm_info.aci0->title_id < npdm_info.acid->title_id_range_min || npdm_info.aci0->title_id > npdm_info.acid->title_id_range_max) { if (npdm_info.aci0->title_id < npdm_info.acid->title_id_range_min || npdm_info.aci0->title_id > npdm_info.acid->title_id_range_max) {
rc = ResultLoaderInvalidProgramId; return ResultLoaderInvalidProgramId;
goto CREATE_PROCESS_END;
} }
/* Validate that the ACI0 Kernel Capabilities are valid and restricted by the ACID Kernel Capabilities. */ /* Validate that the ACI0 Kernel Capabilities are valid and restricted by the ACID Kernel Capabilities. */
rc = NpdmUtils::ValidateCapabilities((u32 *)npdm_info.acid_kac, npdm_info.acid->kac_size/sizeof(u32), (u32 *)npdm_info.aci0_kac, npdm_info.aci0->kac_size/sizeof(u32)); const u32 *acid_caps = reinterpret_cast<u32 *>(npdm_info.acid_kac);
if (R_FAILED(rc)) { const u32 *aci0_caps = reinterpret_cast<u32 *>(npdm_info.aci0_kac);
goto CREATE_PROCESS_END; const size_t num_acid_caps = npdm_info.acid->kac_size / sizeof(*acid_caps);
} const size_t num_aci0_caps = npdm_info.aci0->kac_size / sizeof(*aci0_caps);
R_TRY(NpdmUtils::ValidateCapabilities(acid_caps, num_acid_caps, aci0_caps, num_aci0_caps));
/* Read in all NSO headers, see what NSOs are present. */ /* Read in all NSO headers, see what NSOs are present. */
rc = NsoUtils::LoadNsoHeaders(npdm_info.aci0->title_id); R_TRY(NsoUtils::LoadNsoHeaders(npdm_info.aci0->title_id));
if (R_FAILED(rc)) {
goto CREATE_PROCESS_END;
}
/* Validate that the set of NSOs to be loaded is correct. */ /* Validate that the set of NSOs to be loaded is correct. */
rc = NsoUtils::ValidateNsoLoadSet(); R_TRY(NsoUtils::ValidateNsoLoadSet());
if (R_FAILED(rc)) {
goto CREATE_PROCESS_END;
}
/* Initialize the ProcessInfo. */ /* Initialize the ProcessInfo. */
rc = ProcessCreation::InitializeProcessInfo(&npdm_info, reslimit_h, arg_flags, &process_info); R_TRY(ProcessCreation::InitializeProcessInfo(&npdm_info, reslimit_h, arg_flags, &process_info));
if (R_FAILED(rc)) {
goto CREATE_PROCESS_END;
}
/* 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(process_info.process_flags, launch_item != NULL ? launch_item->arg_size : 0, &nso_extents); R_TRY(NsoUtils::CalculateNsoLoadExtents(process_info.process_flags, launch_item != nullptr ? launch_item->arg_size : 0, &nso_extents));
if (R_FAILED(rc)) {
goto CREATE_PROCESS_END;
}
/* Set Address Space information in ProcessInfo. */ /* Set Address Space information in ProcessInfo. */
process_info.code_addr = nso_extents.base_address; process_info.code_addr = nso_extents.base_address;
process_info.code_num_pages = nso_extents.total_size + 0xFFF; process_info.code_num_pages = nso_extents.total_size + 0xFFF;
process_info.code_num_pages >>= 12; process_info.code_num_pages >>= 12;
/* Call svcCreateProcess(). */ /* Call svcCreateProcess(). */
rc = svcCreateProcess(&process_h, &process_info, (u32 *)npdm_info.aci0_kac, npdm_info.aci0->kac_size/sizeof(u32)); R_TRY(svcCreateProcess(&process_h, &process_info, (u32 *)npdm_info.aci0_kac, npdm_info.aci0->kac_size/sizeof(u32)));
if (R_FAILED(rc)) { auto proc_handle_guard = SCOPE_GUARD {
goto CREATE_PROCESS_END; svcCloseHandle(process_h);
} };
/* Load all NSOs into Process memory, and set permissions accordingly. */ /* Load all NSOs into Process memory, and set permissions accordingly. */
if (launch_item != NULL) { {
rc = NsoUtils::LoadNsosIntoProcessMemory(process_h, npdm_info.aci0->title_id, &nso_extents, (u8 *)launch_item->args, launch_item->arg_size); const u8 *launch_args = nullptr;
} else { size_t launch_args_size = 0;
rc = NsoUtils::LoadNsosIntoProcessMemory(process_h, npdm_info.aci0->title_id, &nso_extents, NULL, 0); if (launch_item != nullptr) {
launch_args = reinterpret_cast<const u8 *>(launch_item->args);
launch_args_size = launch_item->arg_size;
}
R_TRY(NsoUtils::LoadNsosIntoProcessMemory(process_h, npdm_info.aci0->title_id, &nso_extents, launch_args, launch_args_size));
} }
if (R_FAILED(rc)) {
goto CREATE_PROCESS_END;
}
/* Update the list of registered processes with the new process. */ /* Update the list of registered processes with the new process. */
svcGetProcessId(&process_id, process_h); svcGetProcessId(&process_id, process_h);
bool is_64_bit_addspace; bool is_64_bit_addspace;
@ -213,15 +203,13 @@ Result ProcessCreation::CreateProcess(Handle *out_process_h, u64 index, char *nc
} }
Registration::SetProcessIdTidAndIs64BitAddressSpace(index, process_id, npdm_info.aci0->title_id, is_64_bit_addspace); Registration::SetProcessIdTidAndIs64BitAddressSpace(index, process_id, npdm_info.aci0->title_id, is_64_bit_addspace);
for (unsigned int i = 0; i < NSO_NUM_MAX; i++) { for (unsigned int i = 0; i < NSO_NUM_MAX; i++) {
if (NsoUtils::IsNsoPresent(i)) { if (NsoUtils::IsNsoPresent(i)) {
Registration::AddModuleInfo(index, nso_extents.nso_addresses[i], nso_extents.nso_sizes[i], NsoUtils::GetNsoBuildId(i)); Registration::AddModuleInfo(index, nso_extents.nso_addresses[i], nso_extents.nso_sizes[i], NsoUtils::GetNsoBuildId(i));
} }
} }
/* Send the pid/tid pair to anyone interested in man-in-the-middle-attacking it. */ /* Send the pid/tid pair to anyone interested in man-in-the-middle-attacking it. */
Registration::AssociatePidTidForMitM(index); Registration::AssociatePidTidForMitM(index);
rc = ResultSuccess;
/* If HBL, override HTML document path. */ /* If HBL, override HTML document path. */
if (ContentManagement::ShouldOverrideContentsWithHBL(target_process->tid_sid.title_id)) { if (ContentManagement::ShouldOverrideContentsWithHBL(target_process->tid_sid.title_id)) {
@ -231,20 +219,10 @@ Result ProcessCreation::CreateProcess(Handle *out_process_h, u64 index, char *nc
/* ECS is a one-shot operation, but we don't clear on failure. */ /* ECS is a one-shot operation, but we don't clear on failure. */
ContentManagement::ClearExternalContentSource(target_process->tid_sid.title_id); ContentManagement::ClearExternalContentSource(target_process->tid_sid.title_id);
/* Cancel the process handle guard. */
proc_handle_guard.Cancel();
CREATE_PROCESS_END: /* Write process handle to output. */
if (mounted_code) { *out_process_h = process_h;
if (R_SUCCEEDED(rc) && target_process->tid_sid.storage_id != FsStorageId_None) { return ResultSuccess;
rc = ContentManagement::UnmountCode();
} else {
ContentManagement::UnmountCode();
}
}
if (R_SUCCEEDED(rc)) {
*out_process_h = process_h;
} else {
svcCloseHandle(process_h);
}
return rc;
} }

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <switch.h> #include <switch.h>

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "ldr_process_manager.hpp" #include "ldr_process_manager.hpp"
@ -23,7 +23,6 @@
#include "ldr_npdm.hpp" #include "ldr_npdm.hpp"
Result ProcessManagerService::CreateProcess(Out<MovedHandle> proc_h, u64 index, u32 flags, CopiedHandle reslimit_h) { Result ProcessManagerService::CreateProcess(Out<MovedHandle> proc_h, u64 index, u32 flags, CopiedHandle reslimit_h) {
Result rc;
Registration::TidSid tid_sid; Registration::TidSid tid_sid;
LaunchQueue::LaunchItem *launch_item; LaunchQueue::LaunchItem *launch_item;
char nca_path[FS_MAX_PATH] = {0}; char nca_path[FS_MAX_PATH] = {0};
@ -32,58 +31,35 @@ Result ProcessManagerService::CreateProcess(Out<MovedHandle> proc_h, u64 index,
/* Loader doesn't persist the copied resource limit handle. */ /* Loader doesn't persist the copied resource limit handle. */
svcCloseHandle(reslimit_h.handle); svcCloseHandle(reslimit_h.handle);
}; };
rc = Registration::GetRegisteredTidSid(index, &tid_sid); R_TRY(Registration::GetRegisteredTidSid(index, &tid_sid));
if (R_FAILED(rc)) {
return rc;
}
if (tid_sid.storage_id != FsStorageId_None) { if (tid_sid.storage_id != FsStorageId_None) {
rc = ContentManagement::ResolveContentPathForTidSid(nca_path, &tid_sid); R_TRY(ContentManagement::ResolveContentPathForTidSid(nca_path, &tid_sid));
if (R_FAILED(rc)) {
return rc;
}
} }
launch_item = LaunchQueue::GetItem(tid_sid.title_id); launch_item = LaunchQueue::GetItem(tid_sid.title_id);
R_TRY(ProcessCreation::CreateProcess(proc_h.GetHandlePointer(), index, nca_path, launch_item, flags, reslimit_h.handle));
rc = ProcessCreation::CreateProcess(proc_h.GetHandlePointer(), index, nca_path, launch_item, flags, reslimit_h.handle);
ContentManagement::SetCreatedTitle(tid_sid.title_id);
if (R_SUCCEEDED(rc)) { return ResultSuccess;
ContentManagement::SetCreatedTitle(tid_sid.title_id);
}
return rc;
} }
Result ProcessManagerService::GetProgramInfo(OutPointerWithServerSize<ProcessManagerService::ProgramInfo, 0x1> out_program_info, Registration::TidSid tid_sid) { Result ProcessManagerService::GetProgramInfo(OutPointerWithServerSize<ProcessManagerService::ProgramInfo, 0x1> out_program_info, Registration::TidSid tid_sid) {
Result rc;
char nca_path[FS_MAX_PATH] = {0}; char nca_path[FS_MAX_PATH] = {0};
/* Zero output. */ /* Zero output. */
std::fill(out_program_info.pointer, out_program_info.pointer + out_program_info.num_elements, ProcessManagerService::ProgramInfo{}); std::fill(out_program_info.pointer, out_program_info.pointer + out_program_info.num_elements, ProcessManagerService::ProgramInfo{});
rc = PopulateProgramInfoBuffer(out_program_info.pointer, &tid_sid); R_TRY(PopulateProgramInfoBuffer(out_program_info.pointer, &tid_sid));
if (R_FAILED(rc)) {
return {rc};
}
if (tid_sid.storage_id != FsStorageId_None && tid_sid.title_id != out_program_info.pointer->title_id) { if (tid_sid.storage_id != FsStorageId_None && tid_sid.title_id != out_program_info.pointer->title_id) {
rc = ContentManagement::ResolveContentPathForTidSid(nca_path, &tid_sid); R_TRY(ContentManagement::ResolveContentPathForTidSid(nca_path, &tid_sid));
if (R_FAILED(rc)) { R_TRY(ContentManagement::RedirectContentPath(nca_path, out_program_info.pointer->title_id, tid_sid.storage_id));
return {rc}; R_TRY(LaunchQueue::AddCopy(tid_sid.title_id, out_program_info.pointer->title_id));
}
rc = ContentManagement::RedirectContentPath(nca_path, out_program_info.pointer->title_id, tid_sid.storage_id);
if (R_FAILED(rc)) {
return {rc};
}
rc = LaunchQueue::AddCopy(tid_sid.title_id, out_program_info.pointer->title_id);
} }
return {rc}; return ResultSuccess;
} }
Result ProcessManagerService::RegisterTitle(Out<u64> index, Registration::TidSid tid_sid) { Result ProcessManagerService::RegisterTitle(Out<u64> index, Registration::TidSid tid_sid) {
@ -97,68 +73,70 @@ Result ProcessManagerService::UnregisterTitle(u64 index) {
Result ProcessManagerService::PopulateProgramInfoBuffer(ProcessManagerService::ProgramInfo *out, Registration::TidSid *tid_sid) { Result ProcessManagerService::PopulateProgramInfoBuffer(ProcessManagerService::ProgramInfo *out, Registration::TidSid *tid_sid) {
NpdmUtils::NpdmInfo info; NpdmUtils::NpdmInfo info;
Result rc;
bool mounted_code = false; /* Mount code, load NPDM. */
{
if (tid_sid->storage_id != FsStorageId_None) { bool mounted_code = false;
rc = ContentManagement::MountCodeForTidSid(tid_sid); if (tid_sid->storage_id != FsStorageId_None) {
if (R_FAILED(rc)) { R_TRY(ContentManagement::MountCodeForTidSid(tid_sid));
return rc; mounted_code = true;
} else if (R_SUCCEEDED(ContentManagement::MountCodeNspOnSd(tid_sid->title_id))) {
mounted_code = true;
} }
mounted_code = true; ON_SCOPE_EXIT {
} else if (R_SUCCEEDED(ContentManagement::MountCodeNspOnSd(tid_sid->title_id))) { if (mounted_code) {
mounted_code = true; ContentManagement::UnmountCode();
} }
};
rc = NpdmUtils::LoadNpdm(tid_sid->title_id, &info);
R_TRY(NpdmUtils::LoadNpdm(tid_sid->title_id, &info));
if (mounted_code) {
ContentManagement::UnmountCode();
}
if (R_FAILED(rc)) {
return rc;
} }
out->main_thread_priority = info.header->main_thread_prio; out->main_thread_priority = info.header->main_thread_prio;
out->default_cpu_id = info.header->default_cpuid; out->default_cpu_id = info.header->default_cpuid;
out->main_thread_stack_size = info.header->main_stack_size; out->main_thread_stack_size = info.header->main_stack_size;
out->title_id = info.aci0->title_id; out->title_id = info.aci0->title_id;
out->acid_fac_size = info.acid->fac_size; out->acid_fac_size = info.acid->fac_size;
out->aci0_sac_size = info.aci0->sac_size; out->aci0_sac_size = info.aci0->sac_size;
out->aci0_fah_size = info.aci0->fah_size; out->aci0_fah_size = info.aci0->fah_size;
size_t offset = 0; size_t offset = 0;
rc = ResultLoaderInternalError;
if (offset + info.acid->sac_size < sizeof(out->ac_buffer)) { /* Copy ACID Service Access Control. */
out->acid_sac_size = info.acid->sac_size; if (offset + info.acid->sac_size >= sizeof(out->ac_buffer)) {
std::memcpy(out->ac_buffer + offset, info.acid_sac, out->acid_sac_size); return ResultLoaderInternalError;
offset += out->acid_sac_size;
if (offset + info.aci0->sac_size < sizeof(out->ac_buffer)) {
out->aci0_sac_size = info.aci0->sac_size;
std::memcpy(out->ac_buffer + offset, info.aci0_sac, out->aci0_sac_size);
offset += out->aci0_sac_size;
if (offset + info.acid->fac_size < sizeof(out->ac_buffer)) {
out->acid_fac_size = info.acid->fac_size;
std::memcpy(out->ac_buffer + offset, info.acid_fac, out->acid_fac_size);
offset += out->acid_fac_size;
if (offset + info.aci0->fah_size < sizeof(out->ac_buffer)) {
out->aci0_fah_size = info.aci0->fah_size;
std::memcpy(out->ac_buffer + offset, info.aci0_fah, out->aci0_fah_size);
offset += out->aci0_fah_size;
rc = ResultSuccess;
}
}
}
} }
out->acid_sac_size = info.acid->sac_size;
std::memcpy(out->ac_buffer + offset, info.acid_sac, out->acid_sac_size);
offset += out->acid_sac_size;
/* Copy ACI0 Service Access Control. */
if (offset + info.aci0->sac_size >= sizeof(out->ac_buffer)) {
return ResultLoaderInternalError;
}
out->aci0_sac_size = info.aci0->sac_size;
std::memcpy(out->ac_buffer + offset, info.aci0_sac, out->aci0_sac_size);
offset += out->aci0_sac_size;
/* Copy ACID Filesystem Access Control. */
if (offset + info.acid->fac_size >= sizeof(out->ac_buffer)) {
return ResultLoaderInternalError;
}
out->acid_fac_size = info.acid->fac_size;
std::memcpy(out->ac_buffer + offset, info.acid_fac, out->acid_fac_size);
offset += out->acid_fac_size;
/* Copy ACI0 Filesystem Access Header. */
if (offset + info.aci0->fah_size >= sizeof(out->ac_buffer)) {
return ResultLoaderInternalError;
}
out->aci0_fah_size = info.aci0->fah_size;
std::memcpy(out->ac_buffer + offset, info.aci0_fah, out->aci0_fah_size);
offset += out->aci0_fah_size;
/* Parse application type. */ /* Parse application type. */
if (R_SUCCEEDED(rc)) { out->application_type = NpdmUtils::GetApplicationType(reinterpret_cast<const u32 *>(info.acid_kac), info.acid->kac_size / sizeof(u32));
out->application_type = NpdmUtils::GetApplicationType((u32 *)info.acid_kac, info.acid->kac_size / sizeof(u32));
} return ResultSuccess;
return rc;
} }

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp> #include <stratosphere.hpp>
@ -41,15 +41,15 @@ class ProcessManagerService final : public IServiceObject {
u32 aci0_fah_size; u32 aci0_fah_size;
u8 ac_buffer[0x3E0]; u8 ac_buffer[0x3E0];
}; };
static_assert(sizeof(ProcessManagerService::ProgramInfo) == 0x400, "Incorrect ProgramInfo definition."); static_assert(sizeof(ProcessManagerService::ProgramInfo) == 0x400, "Incorrect ProgramInfo definition.");
private: private:
/* Actual commands. */ /* Actual commands. */
Result CreateProcess(Out<MovedHandle> proc_h, u64 index, u32 flags, CopiedHandle reslimit_h); Result CreateProcess(Out<MovedHandle> proc_h, u64 index, u32 flags, CopiedHandle reslimit_h);
Result GetProgramInfo(OutPointerWithServerSize<ProcessManagerService::ProgramInfo, 0x1> out_program_info, Registration::TidSid tid_sid); Result GetProgramInfo(OutPointerWithServerSize<ProcessManagerService::ProgramInfo, 0x1> out_program_info, Registration::TidSid tid_sid);
Result RegisterTitle(Out<u64> index, Registration::TidSid tid_sid); Result RegisterTitle(Out<u64> index, Registration::TidSid tid_sid);
Result UnregisterTitle(u64 index); Result UnregisterTitle(u64 index);
/* Utilities */ /* Utilities */
Result PopulateProgramInfoBuffer(ProcessManagerService::ProgramInfo *out, Registration::TidSid *tid_sid); Result PopulateProgramInfoBuffer(ProcessManagerService::ProgramInfo *out, Registration::TidSid *tid_sid);
public: public:

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <switch.h> #include <switch.h>
#include <algorithm> #include <algorithm>
#include <cstdio> #include <cstdio>
@ -50,12 +50,12 @@ Registration::Process *Registration::GetProcessByProcessId(u64 pid) {
return NULL; return NULL;
} }
bool Registration::RegisterTidSid(const TidSid *tid_sid, u64 *out_index) { bool Registration::RegisterTidSid(const TidSid *tid_sid, u64 *out_index) {
Registration::Process *free_process = GetFreeProcess(); Registration::Process *free_process = GetFreeProcess();
if (free_process == NULL) { if (free_process == NULL) {
return false; return false;
} }
/* Reset the process. */ /* Reset the process. */
*free_process = {}; *free_process = {};
free_process->tid_sid = *tid_sid; free_process->tid_sid = *tid_sid;
@ -70,7 +70,7 @@ bool Registration::UnregisterIndex(u64 index) {
if (target_process == NULL) { if (target_process == NULL) {
return false; return false;
} }
/* Reset the process. */ /* Reset the process. */
*target_process = {}; *target_process = {};
return true; return true;
@ -82,9 +82,9 @@ Result Registration::GetRegisteredTidSid(u64 index, Registration::TidSid *out) {
if (target_process == NULL) { if (target_process == NULL) {
return ResultLoaderProcessNotRegistered; return ResultLoaderProcessNotRegistered;
} }
*out = target_process->tid_sid; *out = target_process->tid_sid;
return ResultSuccess; return ResultSuccess;
} }
@ -93,7 +93,7 @@ void Registration::SetProcessIdTidAndIs64BitAddressSpace(u64 index, u64 process_
if (target_process == NULL) { if (target_process == NULL) {
return; return;
} }
target_process->process_id = process_id; target_process->process_id = process_id;
target_process->title_id = tid; target_process->title_id = tid;
target_process->is_64_bit_addspace = is_64_bit_addspace; target_process->is_64_bit_addspace = is_64_bit_addspace;
@ -120,13 +120,13 @@ Result Registration::GetProcessModuleInfo(LoaderModuleInfo *out, u32 max_out, u6
return ResultLoaderProcessNotRegistered; return ResultLoaderProcessNotRegistered;
} }
u32 cur = 0; u32 cur = 0;
for (unsigned int i = 0; i < Registration::MaxModuleInfos && cur < max_out; i++) { for (unsigned int i = 0; i < Registration::MaxModuleInfos && cur < max_out; i++) {
if (target_process->module_infos[i].in_use) { if (target_process->module_infos[i].in_use) {
out[cur++] = target_process->module_infos[i].info; out[cur++] = target_process->module_infos[i].info;
} }
} }
*num_written = cur; *num_written = cur;
return ResultSuccess; return ResultSuccess;
@ -137,7 +137,7 @@ void Registration::AssociatePidTidForMitM(u64 index) {
if (target_process == NULL) { if (target_process == NULL) {
return; return;
} }
Handle sm_hnd; Handle sm_hnd;
Result rc = svcConnectToNamedPort(&sm_hnd, "sm:"); Result rc = svcConnectToNamedPort(&sm_hnd, "sm:");
if (R_SUCCEEDED(rc)) { if (R_SUCCEEDED(rc)) {
@ -182,12 +182,12 @@ void Registration::AssociatePidTidForMitM(u64 index) {
u64 process_id; u64 process_id;
u64 title_id; u64 title_id;
} *raw = (decltype(raw))ipcPrepareHeader(&c, sizeof(*raw)); } *raw = (decltype(raw))ipcPrepareHeader(&c, sizeof(*raw));
raw->magic = SFCI_MAGIC; raw->magic = SFCI_MAGIC;
raw->cmd_id = 65002; raw->cmd_id = 65002;
raw->process_id = target_process->process_id; raw->process_id = target_process->process_id;
raw->title_id = target_process->tid_sid.title_id; raw->title_id = target_process->tid_sid.title_id;
ipcDispatch(sm_hnd); ipcDispatch(sm_hnd);
} }
svcCloseHandle(sm_hnd); svcCloseHandle(sm_hnd);

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <switch.h> #include <switch.h>
#include <array> #include <array>
@ -34,7 +34,7 @@ class Registration {
u64 title_id; u64 title_id;
FsStorageId storage_id; FsStorageId storage_id;
}; };
struct Process { struct Process {
bool in_use; bool in_use;
bool is_64_bit_addspace; bool is_64_bit_addspace;
@ -44,12 +44,12 @@ class Registration {
Registration::TidSid tid_sid; Registration::TidSid tid_sid;
std::array<Registration::ModuleInfoHolder, MaxModuleInfos> module_infos; std::array<Registration::ModuleInfoHolder, MaxModuleInfos> module_infos;
}; };
struct List { struct List {
std::array<Registration::Process, MaxProcesses> processes; std::array<Registration::Process, MaxProcesses> processes;
u64 num_processes; u64 num_processes;
}; };
static Registration::Process *GetFreeProcess(); static Registration::Process *GetFreeProcess();
static Registration::Process *GetProcess(u64 index); static Registration::Process *GetProcess(u64 index);
static Registration::Process *GetProcessByProcessId(u64 pid); static Registration::Process *GetProcessByProcessId(u64 pid);
@ -59,7 +59,7 @@ class Registration {
static void SetProcessIdTidAndIs64BitAddressSpace(u64 index, u64 process_id, u64 tid, bool is_64_bit_addspace); static void SetProcessIdTidAndIs64BitAddressSpace(u64 index, u64 process_id, u64 tid, bool is_64_bit_addspace);
static void AddModuleInfo(u64 index, u64 base_address, u64 size, const unsigned char *build_id); static void AddModuleInfo(u64 index, u64 base_address, u64 size, const unsigned char *build_id);
static Result GetProcessModuleInfo(LoaderModuleInfo *out, u32 max_out, u64 process_id, u32 *num_written); static Result GetProcessModuleInfo(LoaderModuleInfo *out, u32 max_out, u64 process_id, u32 *num_written);
/* Atmosphere MitM Extension. */ /* Atmosphere MitM Extension. */
static void AssociatePidTidForMitM(u64 index); static void AssociatePidTidForMitM(u64 index);
}; };

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "ldr_shell.hpp" #include "ldr_shell.hpp"
@ -34,10 +34,7 @@ Result ShellService::SetExternalContentSource(Out<MovedHandle> out, u64 tid) {
Handle server_h; Handle server_h;
Handle client_h; Handle client_h;
Result rc; R_TRY(svcCreateSession(&server_h, &client_h, 0, 0));
if (R_FAILED(rc = svcCreateSession(&server_h, &client_h, 0, 0))) {
return rc;
}
Service service; Service service;
serviceCreate(&service, client_h); serviceCreate(&service, client_h);

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <switch.h> #include <switch.h>
#include <stratosphere.hpp> #include <stratosphere.hpp>
@ -31,7 +31,7 @@ class ShellService final : public IServiceObject {
/* Actual commands. */ /* Actual commands. */
Result AddTitleToLaunchQueue(u64 tid, InPointer<char> args, u32 args_size); Result AddTitleToLaunchQueue(u64 tid, InPointer<char> args, u32 args_size);
void ClearLaunchQueue(); void ClearLaunchQueue();
/* Atmosphere commands. */ /* Atmosphere commands. */
Result SetExternalContentSource(Out<MovedHandle> out, u64 tid); Result SetExternalContentSource(Out<MovedHandle> out, u64 tid);
void ClearExternalContentSource(u64 tid); void ClearExternalContentSource(u64 tid);