Skip to content

Commit

Permalink
Stratosphere: Fix FS permissions for <4.0.0 KIPs
Browse files Browse the repository at this point in the history
  • Loading branch information
SciresM committed Oct 17, 2018
1 parent 781f259 commit 5dc31f0
Show file tree
Hide file tree
Showing 10 changed files with 183 additions and 15 deletions.
46 changes: 36 additions & 10 deletions stratosphere/pm/source/pm_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "pm_process_track.hpp"
#include "pm_registration.hpp"
#include "pm_debug_monitor.hpp"
#include "smm_ams.h"

extern "C" {
extern u32 __start__;
Expand Down Expand Up @@ -56,6 +57,20 @@ void __libnx_initheap(void) {
fake_heap_end = (char*)addr + size;
}

void RegisterPrivilegedProcessesWithFs() {
/* Ensures that all privileged processes are registered with full FS permissions. */
constexpr u64 PRIVILEGED_PROCESS_MIN = 0;
constexpr u64 PRIVILEGED_PROCESS_MAX = 0x4F;

const u32 PRIVILEGED_FAH[0x1C/sizeof(u32)] = {0x00000001, 0x00000000, 0x80000000, 0x0000001C, 0x00000000, 0x0000001C, 0x00000000};
const u32 PRIVILEGED_FAC[0x2C/sizeof(u32)] = {0x00000001, 0x00000000, 0x80000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF};

for (u64 pid = PRIVILEGED_PROCESS_MIN; pid <= PRIVILEGED_PROCESS_MAX; pid++) {
fsprUnregisterProgram(pid);
fsprRegisterProgram(pid, pid, FsStorageId_NandSystem, PRIVILEGED_FAH, sizeof(PRIVILEGED_FAH), PRIVILEGED_FAC, sizeof(PRIVILEGED_FAC));
}
}

void __appInit(void) {
Result rc;

Expand All @@ -64,27 +79,33 @@ void __appInit(void) {
fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_SM));
}

rc = fsInitialize();
if (R_FAILED(rc)) {
fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_FS));
}

rc = lrInitialize();
rc = fsprInitialize();
if (R_FAILED(rc)) {
fatalSimple(0xCAFE << 4 | 1);
}

rc = fsprInitialize();
if (R_FAILED(rc)) {
/* This works around a bug with process permissions on < 4.0.0. */
RegisterPrivilegedProcessesWithFs();

rc = smManagerAmsInitialize();
if (R_SUCCEEDED(rc)) {
smManagerAmsEndInitialDefers();
smManagerAmsExit();
} else {
fatalSimple(0xCAFE << 4 | 2);
}

rc = ldrPmInitialize();
rc = smManagerInitialize();
if (R_FAILED(rc)) {
fatalSimple(0xCAFE << 4 | 3);
}

rc = lrInitialize();
if (R_FAILED(rc)) {
fatalSimple(0xCAFE << 4 | 4);
}

rc = smManagerInitialize();
rc = ldrPmInitialize();
if (R_FAILED(rc)) {
fatalSimple(0xCAFE << 4 | 5);
}
Expand All @@ -94,6 +115,11 @@ void __appInit(void) {
fatalSimple(0xCAFE << 4 | 6);
}

rc = fsInitialize();
if (R_FAILED(rc)) {
fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_FS));
}

CheckAtmosphereVersion();
}

Expand Down
3 changes: 2 additions & 1 deletion stratosphere/pm/source/pm_resource_limits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@ void ResourceLimitUtils::InitializeLimits() {
/* Atmosphere: Allocate extra memory (24 MiB) to SYSTEM away from Applet. */
for (unsigned int i = 0; i < 6; i++) {
g_memory_resource_limits[i][0] += ATMOSPHERE_EXTRA_SYSTEM_MEMORY_FOR_SYSMODULES;
g_memory_resource_limits[i][2] -= ATMOSPHERE_EXTRA_SYSTEM_MEMORY_FOR_SYSMODULES;
//g_memory_resource_limits[i][2] -= ATMOSPHERE_EXTRA_SYSTEM_MEMORY_FOR_SYSMODULES;
g_memory_resource_limits[i][1] -= ATMOSPHERE_EXTRA_SYSTEM_MEMORY_FOR_SYSMODULES;
}

/* Set resource limits. */
Expand Down
69 changes: 69 additions & 0 deletions stratosphere/pm/source/smm_ams.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2018 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <switch.h>
#include <switch/arm/atomics.h>
#include "smm_ams.h"

static Service g_smManagerAmsSrv;
static u64 g_smManagerAmsRefcnt;

Result smManagerAmsInitialize(void) {
atomicIncrement64(&g_smManagerAmsRefcnt);

if (serviceIsActive(&g_smManagerAmsSrv))
return 0;

return smGetService(&g_smManagerAmsSrv, "sm:m");
}

void smManagerAmsExit(void) {
if (atomicDecrement64(&g_smManagerAmsRefcnt) == 0)
serviceClose(&g_smManagerAmsSrv);
}

Result smManagerAmsEndInitialDefers(void) {
IpcCommand c;
ipcInitialize(&c);

struct {
u64 magic;
u64 cmd_id;
} *raw;

raw = serviceIpcPrepareHeader(&g_smManagerAmsSrv, &c, sizeof(*raw));
raw->magic = SFCI_MAGIC;
raw->cmd_id = 65000;


Result rc = serviceIpcDispatch(&g_smManagerAmsSrv);

if (R_SUCCEEDED(rc)) {
IpcParsedCommand r;
struct {
u64 magic;
u64 result;
} *resp;

serviceIpcParse(&g_smManagerAmsSrv, &r, sizeof(*resp));
resp = r.Raw;

rc = resp->result;
}

return rc;

}
21 changes: 21 additions & 0 deletions stratosphere/pm/source/smm_ams.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* @file smm_ams.h
* @brief Service manager (sm:m) IPC wrapper for Atmosphere extensions.
* @author SciresM
* @copyright libnx Authors
*/
#pragma once
#include <switch.h>

#ifdef __cplusplus
extern "C" {
#endif

Result smManagerAmsInitialize(void);
void smManagerAmsExit(void);

Result smManagerAmsEndInitialDefers(void);

#ifdef __cplusplus
}
#endif
2 changes: 1 addition & 1 deletion stratosphere/sm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE
CFLAGS := -g -Wall -O2 -ffunction-sections \
$(ARCH) $(DEFINES)

CFLAGS += $(INCLUDE) -D__SWITCH__ -DSM_ENABLE_SMHAX -DSM_ENABLE_MITM -DSM_MINIMUM_SESSION_LIMIT=8
CFLAGS += $(INCLUDE) -D__SWITCH__ -DSM_ENABLE_SMHAX -DSM_ENABLE_MITM -DSM_ENABLE_INIT_DEFERS -DSM_MINIMUM_SESSION_LIMIT=8

CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17

Expand Down
9 changes: 9 additions & 0 deletions stratosphere/sm/source/sm_manager_service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ Result ManagerService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_
case Manager_Cmd_UnregisterProcess:
rc = WrapIpcCommandImpl<&ManagerService::unregister_process>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
case Manager_Cmd_AtmosphereEndInitDefers:
rc = WrapIpcCommandImpl<&ManagerService::end_init_defers>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
default:
break;
}
Expand All @@ -47,3 +50,9 @@ std::tuple<Result> ManagerService::register_process(u64 pid, InBuffer<u8> acid_s
std::tuple<Result> ManagerService::unregister_process(u64 pid) {
return {Registration::UnregisterProcess(pid)};
}

std::tuple<Result> ManagerService::end_init_defers() {
Registration::EndInitDefers();
return {0};
}

6 changes: 5 additions & 1 deletion stratosphere/sm/source/sm_manager_service.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@

enum ManagerServiceCmd {
Manager_Cmd_RegisterProcess = 0,
Manager_Cmd_UnregisterProcess = 1
Manager_Cmd_UnregisterProcess = 1,


Manager_Cmd_AtmosphereEndInitDefers = 65000,
};

class ManagerService final : public IServiceObject {
Expand All @@ -36,4 +39,5 @@ class ManagerService final : public IServiceObject {
/* Actual commands. */
std::tuple<Result> register_process(u64 pid, InBuffer<u8> acid_sac, InBuffer<u8> aci0_sac);
std::tuple<Result> unregister_process(u64 pid);
std::tuple<Result> end_init_defers();
};
37 changes: 36 additions & 1 deletion stratosphere/sm/source/sm_registration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ static std::array<Registration::Service, REGISTRATION_LIST_MAX_SERVICE> g_servic
static u64 g_initial_process_id_low = 0;
static u64 g_initial_process_id_high = 0;
static bool g_determined_initial_process_ids = false;
static bool g_end_init_defers = false;

u64 GetServiceNameLength(u64 service) {
u64 service_name_len = 0;
Expand All @@ -36,6 +37,38 @@ u64 GetServiceNameLength(u64 service) {
return service_name_len;
}

/* Atmosphere extension utilities. */
void Registration::EndInitDefers() {
g_end_init_defers = true;
}

constexpr u64 EncodeNameConstant(const char *name) {
u64 service = 0;
for (unsigned int i = 0; i < sizeof(service); i++) {
if (name[i] == '\x00') {
break;
}
service |= ((u64)name[i]) << (8 * i);
}
return service;
}

bool Registration::ShouldInitDefer(u64 service) {
/* Only enable if compile-time generated. */
#ifndef SM_ENABLE_INIT_DEFERS
return false;
#endif

if (g_end_init_defers) {
return false;
}

/* This is a mechanism by which certain services will always be deferred until sm:m receives a special command. */
/* This can be extended with more services as needed at a later date. */
constexpr u64 FSP_SRV = EncodeNameConstant("fsp-srv");
return service == FSP_SRV;
}

/* Utilities. */
Registration::Process *Registration::GetProcessForPid(u64 pid) {
auto process_it = std::find_if(g_process_list.begin(), g_process_list.end(), member_equals_fn(&Process::pid, pid));
Expand Down Expand Up @@ -188,11 +221,13 @@ bool Registration::HasService(u64 service) {

Result Registration::GetServiceHandle(u64 pid, u64 service, Handle *out) {
Registration::Service *target_service = GetService(service);
if (target_service == NULL) {
if (target_service == NULL || ShouldInitDefer(service)) {
/* Note: This defers the result until later. */
return RESULT_DEFER_SESSION;
}

/* */

*out = 0;
Result rc;
if (target_service->mitm_pid == 0 || target_service->mitm_pid == pid) {
Expand Down
3 changes: 3 additions & 0 deletions stratosphere/sm/source/sm_registration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ class Registration {
};

/* Utilities. */
static void EndInitDefers();
static bool ShouldInitDefer(u64 service);

static Registration::Process *GetProcessForPid(u64 pid);
static Registration::Process *GetFreeProcess();
static Registration::Service *GetService(u64 service);
Expand Down
2 changes: 1 addition & 1 deletion stratosphere/sm/source/sm_user_service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Result UserService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id,

Result UserService::handle_deferred() {
/* If we're deferred, GetService failed. */
return WrapDeferredIpcCommandImpl<&UserService::deferred_get_service>(this, this->deferred_service);;
return WrapDeferredIpcCommandImpl<&UserService::deferred_get_service>(this, this->deferred_service);
}


Expand Down

0 comments on commit 5dc31f0

Please sign in to comment.